Libtomcrypt AES 加密及解密

主控芯片: 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

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(PiCi1)

  • 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}) C1=C1+1(mod2W)Ci=PiEk(C1)

  • 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=PiC1C1=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} C1=Ek(C1)Ci=PiC1

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 中,根据不同的算法类型进行了分组。

libtomcrypt_src

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

libtomcrypt_group

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

将这些文件依次添加进项目分组中。

libtomcrypt_group_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 模式,同时也支持多种结果显示模式。

aes_web

Conclusion

4 个月过去了,项目总算交掉了🐢,CSDN 也是 3 个多月没更新了,想总结一些东西留个纪念吧。

搬完家也一个多月了,慢慢地把家布置成自己想要的样子。感觉加班的日子过的浑浑噩噩的,生活和工作快失去了平衡,所以这个星期想要躺平。休息完后,重新出发吧🚀

明天是七夕,祝七夕快乐噢💝

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值