当前位置:网站首页>Libtomcrypt AES 加密及解密
Libtomcrypt AES 加密及解密
2022-08-04 09:17:00 【Rose Island】
主控芯片: MM32F2377
开发环境: IAR 7.80.4
libtomcrypt: v1.18.2
AES 简介
加密算法主要分成三种:
- 对称加密: AES / DES / 3DES(加密和解密的秘钥相同)
- 非对称加密:RSA / DSA(加密和解密的秘钥不同,公钥 +私钥)
- 散列算法:SHA-1 / MD5(不需要秘钥)
AES (Advanced Encyption Standard) 为对称加密算法,即加密和解密使用的是相同的密钥。
AES 加密原理
明文 P
未经加密的原始数据
密钥 K
在对称加密中,加密和解密的密钥是相同的。由加密方和解密方确定,或者由加密方通过非对称加密算法对密钥进行加密,再发送给解密方。
密文 C
经过加密后的数据
加密函数: C = E ( K , P ) C = E(K,P) C=E(K,P)
解密函数: P = D ( K , C ) P = D(K,C) P=D(K,C)

AES Modes
AES 有 5 种加密模式:
ECB (Electronic Codebook)
ECB 为最简单的加密模式,根据加密块大小分成若干块,然后使用相同的密钥对每一块单独加密
C i = E k ( P i ) C_i = E_k(P_i) Ci=Ek(Pi)CBC (Cipher Block Chaining)
CBC 先将明文切分成若干小段,然后每一小段与初始块或者上一段的密文段进行异或运算后,再与密钥进行加密
C i = E k ( P i ⊕ C i − 1 ) C_i = E_k(P_i \oplus C_{i-1}) Ci=Ek(Pi⊕Ci−1)CTR (Counter)
CTR 有一个自增的算子,这个算子用密钥加密之后的输出和明文异或的结果得到密文
C − 1 = C − 1 + 1 ( m o d 2 W ) C i = P i ⊕ E k ( C − 1 ) C_{-1} = C_{-1} + 1(mod 2^W) \\ C_i = P_i \oplus E_k(C_{-1}) C−1=C−1+1(mod2W)Ci=Pi⊕Ek(C−1)CFB (Ciphertext Feedback)
CFB 对加密得到的密文再次加密,再将这个加密得到的数据与当前的明文异或
C i = P i ⊕ C 1 C − 1 = E k ( C i ) C_i = P_i \oplus C_1 \\ C_{-1} = E_k(C_i) Ci=Pi⊕C1C−1=Ek(Ci)OFB (Output Feedback)
与 CFB 不同的是,OFB 先对之前的加密结果进行加密,然后再与当前的明文进行异或
C − 1 = E k ( C − 1 ) C i = P i ⊕ C − 1 C_{-1} = E_k(C_{-1}) \\ C_i = P_i \oplus C_{-1} C−1=Ek(C−1)Ci=Pi⊕C−1
AES Padding
当 AES 明文 P 的数据长度不是 16 的倍数时,需要在后面补齐,补齐的方法有多种。
Zero Padding
全部补 0
| AA AA AA AA AA AA AA AA | AA AA AA 00 00 00 00 00|
PKCS7 Padding
差几个字节就补几
| AA AA AA AA AA AA AA AA | AA AA AA 05 05 05 05 05|
ANSI X.923
最后一个字节补缺少的字节个数,前面的都补 0
| AA AA AA AA AA AA AA AA | AA AA AA 00 00 00 00 05|
ISO 10126
最后一个字节补缺少的字节个数,前面的随机补充
| AA AA AA AA AA AA AA AA | AA AA AA 89 12 A3 68 05|
Libtomcrypt 简介
Libtom 是一个开源的、可移植的密码库,分为 Libtomcrypt / Libtommath / Tomsfastmath / Libtompoly / Libtomfloat,其中用的比较多的是 Libtomcrypt 和 Libtommath。
Libtomcrypt 支持多种加密算法,包括 AES,MD5,RSA,HMAC,HKDF 等等。具体的可查看 Libtom 官网。也可查看 [Libtomcrypt 文档][lib_doc]。
使用 AES 算法
Libtomcrypt AES 移植
首先从 Libtomcrypt Github 克隆项目,AES 加密不需要用到 Libtommath 库,如果是 RSA 加密,还需要克隆 Libtommath。
这里选择的是 v1.18.2 Release 版本。
需要调用的文件主要是在 ./libtomcrypt/src 中,根据不同的算法类型进行了分组。

项目使用的 IDE 为 IAR,首先在项目中新建一个分组,为 libtomcrypt,在该组下根据 ./libtomcrypt/src 中的文件新建分组。

AES 需要使用的文件包括以下:
- cipher
- aes.c
- aes_tab.c
- misc
- 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
- modes
- ecb_decrypt.c
- ecb_done.c
- ecb_encrypt.c
- ecb_start.c
将这些文件依次添加进项目分组中。

还需要在 Options -> C/C++ Compiler -> Preprocessor -> Defined symbols 中添加一些宏定义:
LTC_NO_MODES
LTC_NO_MACS
LTC_NO_PRNGS
LTC_NO_CIPHERS
LTC_NO_HASHES
LTC_NO_PK
LTC_NO_PKCS
LTC_NO_MISC
LTC_NO_FILE
LTC_ECB_MODE
LTC_RIJNDAEL
_CRT_SECURE_NO_WARNINGS
这样就完成移植啦
AES 加密 + 解密
这里选择 AES-128-ECB 方式。
首先新建一个 .c 和 一个 .h 文件,在 .h 文件中定义一个 symmetric_ECB 结构体变量名为 ecb。其中包括了算法类型、块长度以及密钥。
/** A block cipher ECB structure */
typedef struct {
/** The index of the cipher chosen */
int cipher,
/** The block size of the given cipher */
blocklen;
/** The scheduled key */
symmetric_key key;
} symmetric_ECB;
之后定义密钥值以及引用 aes_desc 描述符,描述符里描述了密码算法需要的变量以及函数操作。
.h 里面主要是这三句话:
symmetric_ECB ecb;
unsigned char key[MAXBLOCKSIZE] = "0123456789abcdef";
extern const struct ltc_cipher_descriptor aes_desc;
接下来是 .c 文件。
根据官方文档 Symmetric Block Ciphers 可以知道 Libtomcrypt 对称加密算法调用的一个大致流程:
- 注册算法描述符:
register_cipher() - 获取算法描述符:
find_cipher() - 初始化算法结构体:
ecb_start() - 加密或解密:
ecb_encrypt()/ecb_decrypt() - 结束运算:
ecb_done() - 释放资源:
zeromem(key, sizeof(key))+zeromem(&ecb, sizeof(ecb))
更详细的可参考文档3.4.8 Examples。
接下来就模仿这个例子写 aes_ecb_128 的加密和解密函数:
- aes_ecb_128 加密
int mm32_aes_ecb_encrypt(const unsigned char pt[], unsigned char ct[], unsigned long ptLen)
{
int idx = 0;
int err = 0;
// register aes
if(register_cipher(&aes_desc) != CRYPT_OK){
printf("register_cipher failed! \n");
return CRYPT_INVALID_CIPHER;
}
// find aes
if((idx == find_cipher("aes")) == -1){
printf("find_cipher failed! \n");
return CRYPT_NOP;
}
// aes init
if((err = ecb_start(idx, key, cipher_descriptor[idx].min_key_length, 0, &ecb)) != CRYPT_OK){
// printf("ecb_start failed! \nError type is %d. \n", err);
return err;
}
// aes encrypt
if((err = ecb_encrypt(pt, ct, ptLen, &ecb)) != CRYPT_OK){
printf("ecb_encrypt failed! \nError type is %d. \n", err);
return err;
}
printf("********************************************\n");
printf("Encrypt result is %s \n", ct);
printf("********************************************\n");
// aes end
if((err = ecb_done(&ecb)) != CRYPT_OK){
printf("ecb_done failed! \nError type is %d. \n", err);
return err;
}
// unregister aes
if(unregister_cipher(&aes_desc) != CRYPT_OK){
printf("unregister_cipher failed! \n");
return CRYPT_INVALID_CIPHER;
}
// clear up
zeromem(key, sizeof(key));
zeromem(&ecb, sizeof(ecb));
return CRYPT_OK;
}
- aes_ecb_128 解密
int mm32_aes_ecb_decrypt(const unsigned char ct[], unsigned char pt[], unsigned long ptLen)
{
int idx = 0;
int err = 0;
// register aes
if(register_cipher(&aes_desc) != CRYPT_OK){
printf("register_cipher failed! \n");
return CRYPT_INVALID_CIPHER;
}
// find aes
if((idx == find_cipher("aes")) == -1){
printf("find_cipher failed! \n");
return CRYPT_NOP;
}
// aes init
if((err = ecb_start(idx, key, cipher_descriptor[idx].min_key_length, 0, &ecb)) != CRYPT_OK){
printf("ecb_start failed! \nError type is %d. \n", err);
return err;
}
// aes decrypt
if((err = ecb_decrypt(ct, pt, ptLen, &ecb)) != CRYPT_OK){
printf("ecb_decrypt failed! \nError type is %d. \n", err);
return err;
}
printf("********************************************\n");
printf("Decrypt result is %s \n", pt);
printf("********************************************\n");
// aes end
if((err = ecb_done(&ecb)) != CRYPT_OK){
printf("ecb_done failed! \nError type is %d. \n", err);
return err;
}
// unregister aes
if(unregister_cipher(&aes_desc) != CRYPT_OK){
printf("unregister_cipher failed! \n");
return CRYPT_INVALID_CIPHER;
}
// clear up
zeromem(key, sizeof(key));
zeromem(&ecb, sizeof(ecb));
return CRYPT_OK;
}
AES 在线加密 + 解密
推荐一个 AES 在线加密解密网站,支持 5 种加密模式和 5 种 padding 模式,同时也支持多种结果显示模式。

Conclusion
4 个月过去了,项目总算交掉了,CSDN 也是 3 个多月没更新了,想总结一些东西留个纪念吧。
搬完家也一个多月了,慢慢地把家布置成自己想要的样子。感觉加班的日子过的浑浑噩噩的,生活和工作快失去了平衡,所以这个星期想要躺平。休息完后,重新出发吧
明天是七夕,祝七夕快乐噢
边栏推荐
- 云函数实现网站自动化签到配置详解【Web函数/Nodejs/cookie】
- 我和 TiDB 的故事 | 缘份在,那就终是能相遇的
- 关于DSP驱动外挂flash
- sync-diff-inspector 使用实践
- How to import data from PG to kingbaseES
- B站回应HR称“核心用户都是Loser”、求职者是“白嫖党”:已被劝退
- ISO14443A读卡流程(作为示例参考)
- Ansible deployment scripts - pro available without pit
- layout manager
- ps如何换背景颜色,自学ps软件photoshop2022,3种不同的方式笔记记录
猜你喜欢

MindSpore:【mindinsight】【Profiler】用execution_time推导出来的训练耗时远小于真实的耗时

Grafana9.0发布,Prometheus和Loki查询生成器、全新导航、热图面板等新功能!

OAK-FFC-4P全网首次测试

有了这篇 Kubernetes 的介绍,它的原理秒懂!

After four years of outsourcing, the autumn recruits finally landed

cannot import name ‘import_string‘ from ‘werkzeug‘【bug解决】

Producer and Consumer Problems in Concurrent Programming

交换机链路聚合详解【华为eNSP】

IDEA 自动导入的配置(Auto import)

MySQL binlog都有哪些模式?
随机推荐
leetcode二叉树系列(二叉搜索树篇)
How Oracle for current library or certain library data on the same server number?
leetcode单调栈经典例题——最大矩形
低代码应用开发的五大好处
LVGL's multi-language conversion tool -- a good assistant for font settings
今年37了,被大厂抢着要...
SQL后计算的利器
学会 Arthas,让你 3 年经验掌握 5 年功力
交换机链路聚合详解【华为eNSP】
v-model原理,在“radio”、“checkbox”、“select”、修饰符
思想茶叶蛋 (Jul 31,2022)| 元宇宙(Metaverse)下了一枚什么样的蛋
MindSpore:Ascend运行出现问题
Producer and Consumer Problems in Concurrent Programming
It is found that several WRH tables are locked, what should I do?
华为od项目
蜜芽CEO刘楠:垂直电商黄金时代已落幕 坚定转型品牌之路
MindSpore:图算融合报错
VRRP+MSTP配置详解【华为eNSP实验】
DNS 查询原理详解—— 阮一峰的网络日志
浅聊偏函数