對稱加密
使用相同密鑰進行加密明文和解密密文的算法,有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