您的位置:首页 > 其它

使用 libTomCrypt 实现 AES、HMAC、HKDF 运算

2017-12-07 18:37 246 查看

使用 libTomCrypt 实现 AES、HMAC、HKDF 运算

Qidi 2017.11.06 (Markdown & Haroopad)

[b]1、libTomCrypt 简介[/b]

  libTomCrypt 是一个使用 C 语言编写的开源加解密算法库,使用 WTF 协议进行授权,支持 AES、HMAC、HKDF、RSA、PRNG、BASE64 等常用加解密算法。

[b]2、基础文件[/b]

  我们在使用 libTomCrypt 时会发现,调用某一类算法时总是要依赖几个特定头文件和源文件。我称这些头文件/源文件为该类算法的基础文件。

  对于 AES 算法来说,这些基础文件是:

tomcrypt.h    tomcrypt_argchk.h    tomcrypt_cipher.h
aes.c    aes_tab.c    compare_testvector.c
crypt_argchk.c    crypt_cipher_descriptor.c    crypt_cipher_is_valid.c
crypt_find_cipher.c    crypt_register_cipher.c    crypt_unregister_cipher.c
zeromem.c


  对于 HMAC 和 HKDF 算法来说,这些基础文件是:

tomcrypt.h    tomcrypt_argchk.h    tomcrypt_cipher.h
aes.c    aes_tab.c    compare_testvector.c
crypt_argchk.c    crypt_hash_descriptor.c   crypt_hash_is_valid.c
crypt_find_hash.c    crypt_register_hash.c    crypt_unregister_hash.c
zeromem.c


[b]3、AES 算法调用流程[/b]

  使用 AES 算法时一般可以分为以下几个步骤:

注册算法描述符:

register_cipher(&aes_desc);


获取算法描述符:

idx = find_cipher("aes");


初始化算法结构体:

XXX_start(idx, IV,
key, key_len,
num_rounds,
symmetric_XXX *XXX);


加密:

XXX_encrypt(*plain_text, *crypted_text,
len, symmetric_XXX *XXX);


解密:

XXX_decrypt(*crypted_text, *plain_text,
len, symmetric_XXX *XXX);


结束运算:

XXX_done(symmetric_XXX *XXX);


释放资源:

zeromem(key, sizeof(key));
zeromem(XXX, sizeof(XXX));


[b]3.1、实现 AES-128-ECB 加解密[/b]

  要实现
aes-128-ecb
加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个
ecb
相关的源文件,如下:

ecb_decrypt.c    ecb_done.c
ecb_encrypt.c    ecb_start.c


  工程中截取的代码片段如下:

    ...
symmetric_ECB ecb;
unsigned char key[MAXBLOCKSIZE] = "1234567890abcdef" \
"1234567890abcdef" \
"1234567890abcdef" \
"1234567890abcdef" \
"1234567890abcdef" \
"1234567890abcdef" \
"1234567890abcdef" \
"1234567890abcde";
unsigned char pt[4096] = "Keep it simple and stupid."; // plain text for encrypting, place your own content here
unsigned char ct[4096];
if (register_cipher(&aes_desc) < 0) {
ALOGE("register_cipher() failed!\n");
goto exit1;
}
intidx = find_cipher("aes");
if (idx == -1) {
ALOGE("find_cipher() failed!\n");
goto exit1;
}
if (CRYPT_OK != ecb_start(idx, key, cipher_descriptor[idx].min_key_length, 0, &ecb)) {
ALOGE("ecb_start() failed!\n");
goto exit1;
}
if (CRYPT_OK != ecb_encrypt(pt, ct, sizeof(pt), &ecb)) {
ALOGE("ecb_encrypt() failed!\n");
goto exit1;
}
#if SHOW_DECRYPT
if (CRYPT_OK != ecb_decrypt(ct, at, sizeof(at), &ecb)) {
LOG("ecb_decrypt() failed!\n");
goto exit1;
}
#endif
if (CRYPT_OK != ecb_done(&ecb)) {
LOG("ecb_done() failed!\n");
goto exit1;
}
...
exit1:
...


[b]3.2、实现 AES-128-CTR 加解密[/b]

  要实现
aes-128-ctr
加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个
ctr
相关的源文件,如下:

ctr_decrypt.c    ctr_done.c
ctr_encrypt.c    ctr_start.c


  工程中截取的代码片段如下:

...
if (register_cipher(&aes_desc) < 0) {
ALOGE("Qidi - aes-128-ctr register_cipher() failed!\n");
goto error;
}
idx = find_cipher("aes");
if (idx == -1) {
ALOGE("Qidi - aes-128-ctr find_cipher() failed!\n");
goto error;
}
err = ctr_start(idx, session_iv, session_key, 16, 0, CTR_COUNTER_BIG_ENDIAN, &ctr);
if (err != CRYPT_OK) {
ALOGE("Qidi - ctr_start() failed!\n");
goto error;
}
err = ctr_encrypt((unsigned char*)input_raw, buf, 16, &ctr);
if (err != CRYPT_OK) {
ALOGE("Qidi - ctr_encrypt() failed!\n");
goto error;
}
// ctr 解密前需要再 start 初始化一次
err = ctr_start(idx, session_iv, session_key, 16, 0, CTR_COUNTER_BIG_ENDIAN, &ctr);
if (err != CRYPT_OK) {
ALOGE("Qidi - ctr_start() failed!\n");
goto error;
}
memset(input_raw, 0, 16);
err = ctr_decrypt((unsigned char *)output_raw, (unsigned char *)input_raw, 16, &ctr);
if (err != CRYPT_OK) {
ALOGE("Qidi - ERROR: ctr_decrypt() failed!\n");
goto error;
}
ctr_done(&ctr);
...
error:
...


[b]4、HASH 算法一般调用流程[/b]

  使用 HASH 算法时,一般可以分为以下几个步骤:

注册算法描述符:

register_hash(&aes_desc);


获取算法描述符:

idx = find_hash("aes");


初始化算法结构体:

XXX_start(idx, IV,
key, key_len,
num_rounds,
symmetric_XXX *XXX);


加密:

XXX_encrypt(*plain_text, *crypted_text,
len, symmetric_XXX *XXX);


解密:

XXX_decrypt(*crypted_text, *plain_text,
len, symmetric_XXX *XXX);


结束运算:

XXX_done(symmetric_XXX *XXX);


释放资源:

zeromem(key, sizeof(key));
zeromem(XXX, sizeof(XXX));


[b]4.1、实现 HMAC 运算[/b]

  要实现
hmac
加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个
hmac
相关的源文件,如下:

hmac_init.c    hmac_process.c
hmac_memory.c  hash_memory.c
hmac_done.c    sha256.c


  工程中截取的代码片段如下:

...
if (register_hash(&sha256_desc) < 0) {
ALOGE("Qidi - ERROR: verify fw_resp register_hash(&sha256_desc) failed!\n");
goto error;
}
int idx = find_hash("sha256");
if (idx < 0) {
ALOGE("Qidi - ERROR: verify fw_resp find_hash(sha256) failed!\n");
goto error;
}

if (CRYPT_OK != hmac_memory(idx, (unsigned char*)pre_key, 32,
(unsigned char*)in_data, 36,
(unsigned char*)fw_resp, &fw_resp_len)) {
ALOGE("ERROR: verify fw_resp hmac_memory() failed!\n");
goto error;
}
...
error:
...


  其中
hmac_memory()
函数实际上是对
hmac_init()
hmac_process
hmac_done()
的封装。

[b]4.2、实现 HKDF 运算[/b]

  要实现
hkdf
加解密,除了要包含(#include)和引用(Makefile 中添加)第 2 节中提到的文件外,还要引用几个
hkdf
相关的源文件,如下:

hkdf.c    sha256.c


  工程中截取的代码片段如下:

...
register_hash(&sha256_desc);
int idx = find_hash("sha256");
ret = hkdf(idx, (unsigned char*)salt, 20,
(unsigned char*)info, 20, (unsigned char*)in_data, 18, session_key_iv, 32);
...


  其中
hkdf()
函数实际上是对
hkdf_extract()
hkdf_expand()
的封装。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: