对称加密
使用相同密钥进行加密明文和解密密文的算法,有AES、DES、3DES,这些算法单次只能处理一个固定长度的数据。比如AES算法单次只能处理128bit数据,所以需要分组密码模式和填充方式处理
分组密码模式
-
ECB(Electronic Codebook)电子密码本模式
将明文进行分组加密,加密结果为密文分组,一个明文分组对应一个密文分组
-
CBC(cipher block chaining)密码分组链接模式
每一组明文在加密前都与前面的密文分组进行异或操作,由于第一个明文分组前面没有密文分组所以需要准备一个与密文分组长度相同的比特序列来代替密文分组,这个比特序列被称作初始化向量IV。
-
CTR计数器模式
CTR模式使用与明文长度相同的计数值参与运算,通过加密计数值来产生密钥流,然后让密钥流与明文进行异或操作来加密明文。加入最后一个明文长度不是分组长度整数被,则对密钥流截取明文长度后异或加密,所以这种方式不需要对明文分组进行填充。(ECB、CBC需要填充)
PKCS7填充方案
ECB、CBC模式中需要进行填充,常用的是PKCS7填充方案,以AES-CBC为例,分组长度16字节,若明文28字节,则需要在明文末尾填充4字节的04,若待明文明文长度是16字节,则需要额外填充16字节的16,解密后取最后一个明文字节的值,比如是x,则要去掉尾部x字节后才是真正明文消息。
AES-128-CBC/CTR的例子
下面是AES-128-CBC/CTR的例子,注意CBC和ECB解密成明文后都需要删除填充而CTR不需要,注意下面几个宏要打开
MBEDTLS_AES_C 开启AES算法
MBEDTLS_CIPHER_MODE_CBC 开启CBC模式
MBEDTLS_CIPHER_MODE_CTR 开启CTR模式
MBEDTLS_AES_ROM_TABLES 使用预定义S盒,节省部分ram
MBEDTLS_CIPHER_C 开启cipher接口
MBEDTLS_CIPHER_MODE_WITH_PADDING 开启填充
MBEDTLS_CIPHER_MODE_PADDING_PKCS7 开启PKCS7填充方案
#include <string.h>
#include <stdio.h>
#include <stdint.h>
#include "mbedtls/cipher.h"
#include "mbedtls/platform.h"
/*
# padding with pkcs7 AES_128_CBC Encrypt
ptx = "CBC has been the most commonly used mode of operation."
key = 06a9214036b8a15b512e03d534120006
iv = 3dafba429d9eb430b422da802c9fac41
*/
char *ptx = "CBC has been the most commonly used mode of operation.";
uint8_t key[16] =
{
0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06
};
uint8_t iv[16] =
{
0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41
};
static void dump_buf(char *info, uint8_t *buf, uint32_t len)
{
mbedtls_printf("%s", info);
for (int i = 0; i < len; i++) {
mbedtls_printf("%s%02X%s", i % 16 == 0 ? "\n\t":" ",
buf[i], i == len - 1 ? "\n":"");
}
mbedtls_printf("\n");
}
int my_aes_init(int type,mbedtls_cipher_context_t *ctx,const unsigned char *key,
int key_bitlen, const mbedtls_operation_t operation,const unsigned char *iv, size_t iv_len)
{
const mbedtls_cipher_info_t *info;
mbedtls_cipher_init(ctx);
info = mbedtls_cipher_info_from_type(type);
mbedtls_cipher_setup(ctx, info);
mbedtls_printf("\n cipher info setup, name: %s, block size: %d\n",
mbedtls_cipher_get_name(ctx),
mbedtls_cipher_get_block_size(ctx));
mbedtls_cipher_setkey(ctx, key, key_bitlen, operation);
mbedtls_cipher_set_iv(ctx, iv, iv_len);
return 0;
}
int my_aes_update(mbedtls_cipher_context_t *ctx, const unsigned char *input,
size_t ilen, unsigned char *output, size_t *olen )
{
return mbedtls_cipher_update(ctx, input,ilen, output,olen);
}
int my_aes_finish(mbedtls_cipher_context_t *ctx,unsigned char *output, size_t *olen )
{
return mbedtls_cipher_finish(ctx,output,olen);
}
void my_aes_deinit(mbedtls_cipher_context_t *ctx)
{
mbedtls_cipher_free(ctx);
}
int main(void)
{
size_t len;
int olen = 0;
uint8_t buf[256];
//MBEDTLS_CIPHER_AES_128_CBC enc
mbedtls_cipher_context_t aes_cbc_128_ctx;
my_aes_init(MBEDTLS_CIPHER_AES_128_CBC,&aes_cbc_128_ctx,key,sizeof(key)*8,MBEDTLS_ENCRYPT,iv,sizeof(iv));
olen = 0;
memset(buf,0,sizeof(buf));
my_aes_update(&aes_cbc_128_ctx,ptx,strlen(ptx),buf,&len);
olen += len;
my_aes_update(&aes_cbc_128_ctx,ptx,strlen(ptx),buf+olen,&len);
olen += len;
my_aes_finish(&aes_cbc_128_ctx,buf+olen,&len);
olen += len;
my_aes_deinit(&aes_cbc_128_ctx);
dump_buf("\n cbc cipher aes encrypt:", buf, olen);
printf("%d\n",olen);
int text_olen = 0;len = 0;
uint8_t text_buf[256];
//MBEDTLS_CIPHER_AES_128_CBC dec
my_aes_init(MBEDTLS_CIPHER_AES_128_CBC,&aes_cbc_128_ctx,key,sizeof(key)*8,MBEDTLS_DECRYPT,iv,sizeof(iv));
memset(text_buf,0,sizeof(text_buf));
my_aes_update(&aes_cbc_128_ctx,buf,olen,text_buf,&len);
text_olen +=len;
my_aes_finish(&aes_cbc_128_ctx,text_buf+text_olen,&len);
text_olen += len;
my_aes_deinit(&aes_cbc_128_ctx);
printf("text_olen :%d strlen(text_buf): %ld\n",text_olen,strlen(text_buf));
dump_buf("\n cbc text aes decrypt:", text_buf, text_olen);
dump_buf("\n cbc text aes decrypt:", text_buf, strlen(text_buf));
//del padding
int del_cnt = text_buf[strlen(text_buf)-1];
while(del_cnt)
{
text_buf[text_olen+del_cnt-1] = 0;
del_cnt--;
}
printf("cbc decrypt: %s\n",text_buf);
//===========================================================
//MBEDTLS_CIPHER_AES_128_CTR enc
mbedtls_cipher_context_t aes_ctr_128_ctr;
my_aes_init(MBEDTLS_CIPHER_AES_128_CTR,&aes_ctr_128_ctr,key,sizeof(key)*8,MBEDTLS_ENCRYPT,iv,sizeof(iv));
olen = 0;
memset(buf,0,sizeof(buf));
my_aes_update(&aes_ctr_128_ctr,ptx,strlen(ptx),buf,&len);
olen += len;
my_aes_update(&aes_ctr_128_ctr,ptx,strlen(ptx),buf+olen,&len);
olen += len;
my_aes_finish(&aes_ctr_128_ctr,buf+olen,&len);
olen += len;
my_aes_deinit(&aes_ctr_128_ctr);
dump_buf("\n ctr cipher aes encrypt:", buf, olen);
printf("%d\n",olen);
text_olen = 0;len = 0;
//MBEDTLS_CIPHER_AES_128_CTR dec
my_aes_init(MBEDTLS_CIPHER_AES_128_CTR,&aes_ctr_128_ctr,key,sizeof(key)*8,MBEDTLS_DECRYPT,iv,sizeof(iv));
memset(text_buf,0,sizeof(text_buf));
my_aes_update(&aes_ctr_128_ctr,buf,olen,text_buf,&len);
text_olen +=len;
my_aes_finish(&aes_ctr_128_ctr,text_buf+text_olen,&len);
text_olen += len;
my_aes_deinit(&aes_ctr_128_ctr);
printf("text_olen :%d strlen(text_buf) :%ld\n",text_olen,strlen(text_buf));
dump_buf("\n cbc text aes decrypt:", text_buf, text_olen);
dump_buf("\n cbc text aes decrypt:", text_buf, strlen(text_buf));
printf("ctr decrypt: %s\n",text_buf);
return 0;
}
运行log
cipher info setup, name: AES-128-CBC, block size: 16
cbc cipher aes encrypt:
4D DF 90 12 D7 B3 89 87 45 A1 ED 98 60 EB 0F A2
FD 2B BD 80 D2 71 90 D7 2A 2F 24 0C 8F 37 2A 27
63 74 62 96 DD C2 BF CE 7C 25 2B 6C D7 DD 4B A8
AE 07 D9 7E 87 94 36 FC 86 35 FA 0F 80 F8 B2 35
35 37 44 27 9B BE 90 D1 2F C9 E4 4C 15 41 0C AD
94 A3 45 46 4B CF DA 22 E0 DF E4 9F F5 5C 6D E3
1F 8D B7 3B 21 63 48 12 4E 6F 86 3A 18 CA C1 60
112
cipher info setup, name: AES-128-CBC, block size: 16
text_olen 108 strlen(text_buf) 112
cbc text aes decrypt:
43 42 43 20 68 61 73 20 62 65 65 6E 20 74 68 65
20 6D 6F 73 74 20 63 6F 6D 6D 6F 6E 6C 79 20 75
73 65 64 20 6D 6F 64 65 20 6F 66 20 6F 70 65 72
61 74 69 6F 6E 2E 43 42 43 20 68 61 73 20 62 65
65 6E 20 74 68 65 20 6D 6F 73 74 20 63 6F 6D 6D
6F 6E 6C 79 20 75 73 65 64 20 6D 6F 64 65 20 6F
66 20 6F 70 65 72 61 74 69 6F 6E 2E
cbc text aes decrypt:
43 42 43 20 68 61 73 20 62 65 65 6E 20 74 68 65
20 6D 6F 73 74 20 63 6F 6D 6D 6F 6E 6C 79 20 75
73 65 64 20 6D 6F 64 65 20 6F 66 20 6F 70 65 72
61 74 69 6F 6E 2E 43 42 43 20 68 61 73 20 62 65
65 6E 20 74 68 65 20 6D 6F 73 74 20 63 6F 6D 6D
6F 6E 6C 79 20 75 73 65 64 20 6D 6F 64 65 20 6F
66 20 6F 70 65 72 61 74 69 6F 6E 2E 04 04 04 04
cbc decrypt: CBC has been the most commonly used mode of operation.CBC has been the most commonly used mode of operation.
cipher info setup, name: AES-128-CTR, block size: 16
ctr cipher aes encrypt:
C4 1A 1D B1 56 C0 9B 59 E8 25 D9 5B 72 FD 97 BE
F7 06 BA C1 B8 4F F5 4E 72 88 2D 17 0B DB 53 0A
9B 0A FD 86 41 65 73 06 6B C1 F0 52 18 FC 1D 57
9D F4 81 F7 08 CB CD FD 27 4F AA 86 FC C2 FF 86
0A 70 5E 83 BA 3B 4F 1C 7E EE CE 8D 22 34 71 E3
AA A9 B5 DC 92 D8 C8 B5 CA B0 9F CE A1 A1 E9 C9
6B C5 A8 07 0B 96 38 BE 35 C2 4E FB
108
cipher info setup, name: AES-128-CTR, block size: 16
text_olen 108 strlen(text_buf) 108
cbc text aes decrypt:
43 42 43 20 68 61 73 20 62 65 65 6E 20 74 68 65
20 6D 6F 73 74 20 63 6F 6D 6D 6F 6E 6C 79 20 75
73 65 64 20 6D 6F 64 65 20 6F 66 20 6F 70 65 72
61 74 69 6F 6E 2E 43 42 43 20 68 61 73 20 62 65
65 6E 20 74 68 65 20 6D 6F 73 74 20 63 6F 6D 6D
6F 6E 6C 79 20 75 73 65 64 20 6D 6F 64 65 20 6F
66 20 6F 70 65 72 61 74 69 6F 6E 2E
cbc text aes decrypt:
43 42 43 20 68 61 73 20 62 65 65 6E 20 74 68 65
20 6D 6F 73 74 20 63 6F 6D 6D 6F 6E 6C 79 20 75
73 65 64 20 6D 6F 64 65 20 6F 66 20 6F 70 65 72
61 74 69 6F 6E 2E 43 42 43 20 68 61 73 20 62 65
65 6E 20 74 68 65 20 6D 6F 73 74 20 63 6F 6D 6D
6F 6E 6C 79 20 75 73 65 64 20 6D 6F 64 65 20 6F
66 20 6F 70 65 72 61 74 69 6F 6E 2E
ctr decrypt: CBC has been the most commonly used mode of operation.CBC has been the most commonly used mode of operation.
注意上面cbc解密出来的末尾填充是要去掉的。
用openssl验证
echo -n CBC has been the most commonly used mode of operation.CBC has been the most commonly used mode of operation. >text
openssl enc -aes-128-cbc -e -in text -out text.enc -K 06a9214036b8a15b512e03d534120006 -iv 3dafba429d9eb430b422da802c9fac41
hexdump -C text.enc
openssl enc -aes-128-cbc -d -in text.enc -out text.d -K 06a9214036b8a15b512e03d534120006 -iv 3dafba429d9eb430b422da802c9fac41
cat text.d
hexdump -C text.d
ctr的命令是
openssl enc -aes-128-ctr -e -in text -out ctr_text.enc -K 06a9214036b8a15b512e03d534120006 -iv 3dafba429d9eb430b422da802c9fac41
openssl enc -aes-128-ctr -d -in ctr_text.enc -out ctr_text.d -K 06a9214036b8a15b512e03d534120006 -iv 3dafba429d9eb430b422da802c9fac41