AES加解密模式

要想学习AES,首先要清楚三个基本的概念:密钥、填充、模式。

1、密钥

密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。

AES支持三种长度的密钥: 128位,192位,256位

平时大家所说的AES128AES192AES256,实际上就是指AES算法对不同长度密钥的使用。

三种密钥的区别:

从安全性来看,AES256安全性最高。从性能看,AES128性能最高。本质原因是它们的加密处理轮数不同。

2、填充

要想了解填充的概念,我们先要了解AES的分组加密特性。
什么是分组加密?

AES算法在对明文加密的时候,并不是把整个明文一股脑的加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit

这些明文块经过AES加密器复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密的结果。

但这里涉及到一个问题,假如一段明文长度是196bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding) 。

几种典型的填充方式:

NoPadding: 不做任何填充,但是要求明文必须是16字节的整数倍。
PKCS5Padding(默认): 如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6 }
ISO10126Padding:如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
PKCS7Padding原理与PKCS5Padding相似,区别是PKCS5Paddingblocksize为8字节,而PKCS7Paddingblocksize可以为1到255字节

需要注意的是,如果在AES加密的时候使用了某一种填充方式,解密的时候也必须采用同样的填充方式。

3、模式

AES的工作模式,体现在把明文块加密成密文块的处理过程中。AES加密算法提供了五种不同的工作模式:CBC,ECB,CTR,CFB,OFB
模式之间的主题思想是近似的,在处理细节上有一些差别

AES加密算法 - 加密模式

ECB模式
  优点:
  1.简单;
  2.有利于并行计算;
  3.误差不会被传送;
  缺点:
  1.不能隐藏明文的模式;
  2.可能对明文进行主动攻击;
CBC模式:
  优点:
  1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
  缺点:
  1.不利于并行计算;
  2.误差传递;
  3.需要初始化向量IV
CFB模式:
  优点:
  1.隐藏了明文模式;
  2.分组密码转化为流模式;
  3.可以及时加密传送小于分组的数据;
  缺点:
  1.不利于并行计算;
  2.误差传送:一个明文单元损坏影响多个单元;
  3.唯一的IV;
ofb模式:
  优点:
  1.隐藏了明文模式;
  2.分组密码转化为流模式;
  3.可以及时加密传送小于分组的数据;
  缺点:
  1.不利于并行计算;
  2.对明文的主动攻击是可能的;
  3.误差传送:一个明文单元损坏影响多个单元;

上面四个不同模式原理图链接:分组对称加密模式:ECB/CBC/CFB/OFB缺CTR - Ady Lee - 博客园

3.1、ECB模式简介

img

2)、CBC模式简介

下图中,IV一般为16字节全0,数据块长度为16字节的整数倍,则在此数据块后附加一个8字节长的数据块,

附加的数据块为:16进制的“80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00”

img

cbc本质上和ecb差别不大,唯一区别是将前一次加密结果,与要加密的内容异或。因此,cbc的并行性较差,因为每次都要等待前一次的结果,而ecb则不用,速度较快。其主要区别仍然看文章开头,原理图看参考链接。

3.2、AES算法ECB模式

生成加密/解密的Key

   
   
   
    
     
  1. int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
  2. int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);

参数说明:

参数名称 描述
userKey 用户指定的密码。注意:只能是16、24、32字节。如果密码字符串长度不够,可以在字符串末尾追加一些特定的字符,或者重复密码字符串,直到满足最少的长度
bits 密码位数。即userKey的长度 * 8,只能是128、192、256位。
key 向外输出参数。

如果函数调用成功,返回0,否则是负数。

使用函数AES_ecb_encrypt对数据进行加解密

函数原型:

void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc);

   
   
   
    
     

函数说明:

AES加密/解密单个数据块(16个字节),ECB模式

参数说明:

参数名称 描述
in 需要加密/解密的数据
out 计算后输出的数据
key 密钥
enc AES_ENCRYPT 代表加密, AES_DECRYPT代表解密

3.3、AES算法CBC模式

生成加密/解密的Key

   
   
   
    
     
  1. int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
  2. int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);

参数说明:

参数名称 描述
userKey 用户指定的密码。注意:只能是16、24、32字节。如果密码字符串长度不够,可以在字符串末尾追加一些特定的字符,或者重复密码字符串,直到满足最少的长度
bits 密码位数。即userKey的长度 * 8,只能是128、192、256位。
key 向外输出参数。

如果函数调用成功,返回0,否则是负数。

使用AES_cbc_encrypt对数据进行加解密

   
   
   
    
     
  1. void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
  2. size_t length, const AES_KEY *key,
  3. unsigned char *ivec, const int enc);

函数说明:

AES加密/解密单个数据块(16个字节),CBC模式

参数说明:

参数名称 描述
in 输入数据。长度任意。
out 输出数据。能够容纳下输入数据,且长度必须是16字节的倍数。
length 输出数据的实际长度。
key 使用AES_set_encrypt/decrypt_key生成的Key。
ivec 可读写的一块内存。长度必须是16字节。
enc 是否是加密操作。AES_ENCRYPT表示加密,AES_DECRYPT表示解密。

​ 这个函数比AES_encrypt多了一个ivec参数,ivec的内容可以任意指定,但是加密和解密操作必须使用同样的数据。在AES_cbc_encrypt底层,实际上是每16个字节做一次处理,先和ivec做异或运算,然后调用AES_encrypt函数进行加密。
AES_cbc_encrypt在加密的过程中会修改ivec的内容,因此ivec参数不能是一个常量,而且不能在传递给加密函数后再立马传递给解密函数,必须重新赋值之后再传递给解密函数。

关于输出数据的长度
输出数据缓冲区的长度必须是16字节的倍数,加密完成后,比输入长度多出来的输出数据是不可以丢弃的。因此,存档的时候,需要记录原始数据的长度

关于输入数据的长度不必是16字节的倍数(做个备忘):
下面是AES_cbc_encrypt函数的底层实现代码


   
   
   
    
     
  1. ...
  2. / /处理 16字节倍数的数据
  3. while (len >= 16) {
  4. for (n = 0; n < 16; + +n)
  5. out[n] = in[n] ^ iv[n];
  6. ( * block) (out, out, key); / /调用AES_encrypt处理数据
  7. iv = out;
  8. len - = 16;
  9. in + = 16;
  10. out + = 16;
  11. }
  12. / /当数据小于 16字节的时候,进入下面的循环
  13. while (len) {
  14. for (n = 0; n < 16 & & n < len; + +n)
  15. out[n] = in[n] ^ iv[n];
  16. for (; n < 16; + +n)
  17. out[n] = iv[n]; / /使用ivec补齐不足 16字节的部分
  18. ( * block) (out, out, key); / /调用AES_encrypt处理数据
  19. iv = out;
  20. if (len <= 16)
  21. break;
  22. len - = 16;
  23. in + = 16;
  24. out + = 16;
  25. }

ECBCBC都是封装下面的加密解密函数实现的。

使用AES加密/解密

   
   
   
    
     
  1. void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
  2. void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);

参数说明:

参数名称 描述
in 输入数据。必须是16字节
out 输出数据。必须是16字节
key 使用AES_set_encrypt/decrypt_key生成的Key。

AES_encrypt/AES_decrypt一次只处理16个字节。如果输入数据较长,你需要使用循环语句,每16个字节处理一次,直到所有数据处理完毕。如果数据不足16字节,可以用0填充至16字节。

4、加密解密后的长度

AES有几种扩展算法,其中ecb和cbc需要填充,即加密后长度可能会不一样,cfb和ofb不需要填充,密文长度和明文长度一样

5、实战代码

/usr/include/openssl/aes.h


   
   
   
    
     
  1. #ifndef HEADER_AES_H
  2. # define HEADER_AES_H
  3. # include <openssl /opensslconf.h >
  4. # ifdef OPENSSL_ NO_AES
  5. # error AES is disabled.
  6. # endif
  7. # include <stddef.h >
  8. # define AES_ENCRYPT 1
  9. # define AES_DECRYPT 0
  10. / *
  11. * Because array size can't be a const in C, the following two are macros.
  12. * Both sizes are in bytes.
  13. */
  14. # define AES_MAXNR 14
  15. # define AES_ BLOCK_ SIZE 16
  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif
  19. / * This should be a hidden type, but EVP requires that the size be known * /
  20. struct aes_ key_st {
  21. # ifdef AES_LONG
  22. unsigned long rd_ key[ 4 * (AES_MAXNR + 1)];
  23. # else
  24. unsigned int rd_ key[ 4 * (AES_MAXNR + 1)];
  25. # endif
  26. int rounds;
  27. };
  28. typedef struct aes_ key_st AES_ KEY;
  29. const char *AES_ options(void);
  30. int AES_ set_encrypt_ key(const unsigned char *userKey, const int bits,
  31. AES_ KEY * key);
  32. int AES_ set_decrypt_ key(const unsigned char *userKey, const int bits,
  33. AES_ KEY * key);
  34. int private_AES_ set_encrypt_ key(const unsigned char *userKey, const int bits,
  35. AES_ KEY * key);
  36. int private_AES_ set_decrypt_ key(const unsigned char *userKey, const int bits,
  37. AES_ KEY * key);
  38. void AES_encrypt(const unsigned char * in, unsigned char *out,
  39. const AES_ KEY * key);
  40. void AES_decrypt(const unsigned char * in, unsigned char *out,
  41. const AES_ KEY * key);
  42. void AES_ecb_encrypt(const unsigned char * in, unsigned char *out,
  43. const AES_ KEY * key, const int enc);
  44. void AES_cbc_encrypt(const unsigned char * in, unsigned char *out,
  45. size_t length, const AES_ KEY * key,
  46. unsigned char *ivec, const int enc);
  47. void AES_cfb 128_encrypt(const unsigned char * in, unsigned char *out,
  48. size_t length, const AES_ KEY * key,
  49. unsigned char *ivec, int *num, const int enc);
  50. void AES_cfb 1_encrypt(const unsigned char * in, unsigned char *out,
  51. size_t length, const AES_ KEY * key,
  52. unsigned char *ivec, int *num, const int enc);
  53. void AES_cfb 8_encrypt(const unsigned char * in, unsigned char *out,
  54. size_t length, const AES_ KEY * key,
  55. unsigned char *ivec, int *num, const int enc);
  56. void AES_ofb 128_encrypt(const unsigned char * in, unsigned char *out,
  57. size_t length, const AES_ KEY * key,
  58. unsigned char *ivec, int *num);
  59. void AES_ctr 128_encrypt(const unsigned char * in, unsigned char *out,
  60. size_t length, const AES_ KEY * key,
  61. unsigned char ivec[AES_ BLOCK_ SIZE],
  62. unsigned char ecount_buf[AES_ BLOCK_ SIZE],
  63. unsigned int *num);
  64. / * NB: the IV is _two_ blocks long * /
  65. void AES_ige_encrypt(const unsigned char * in, unsigned char *out,
  66. size_t length, const AES_ KEY * key,
  67. unsigned char *ivec, const int enc);
  68. / * NB: the IV is _four_ blocks long * /
  69. void AES_bi_ige_encrypt(const unsigned char * in, unsigned char *out,
  70. size_t length, const AES_ KEY * key,
  71. const AES_ KEY * key 2, const unsigned char *ivec,
  72. const int enc);
  73. int AES_wrap_ key(AES_ KEY * key, const unsigned char *iv,
  74. unsigned char *out,
  75. const unsigned char * in, unsigned int inlen);
  76. int AES_unwrap_ key(AES_ KEY * key, const unsigned char *iv,
  77. unsigned char *out,
  78. const unsigned char * in, unsigned int inlen);
  79. #ifdef __cplusplus
  80. }
  81. #endif
  82. #endif / * !HEADER_AES_H * /

5.1、CBC模式的实战代码

头文件:AES_CBC256.h

   
   
   
    
     
  1. #ifndef _AES_CBC 256_H_
  2. #include <stdio.h >
  3. #include <stdlib.h >
  4. #include < string.h >
  5. #include <openssl /aes.h >
  6. #include <stddef.h >
  7. #define _AES_CBC 256_H_
  8. #define USER_ KEY_ LENGTH 32
  9. #define IVEC_ LENGTH 16
  10. #define AES_ BLOCK_ SIZE 16
  11. #define BITS_ LENGTH (USER_ KEY_ LENGTH * 8)
  12. class AES_CBC 256 {
  13. public:
  14. AES_CBC 256();
  15. virtual ~AES_CBC 256();
  16. / / CBC Mode Encrypt
  17. bool AES_CBC 256_Encrypt(const unsigned char * in, unsigned char *out, size_t length);
  18. / / CBC Mode Decrypt
  19. bool AES_CBC 256_Decrypt(const unsigned char * in, unsigned char *out, size_t length);
  20. unsigned char m_userKey [USER_ KEY_ LENGTH];
  21. unsigned char m_ivec [IVEC_ LENGTH]; / / Default value is all 0 of 16
  22. };
  23. #endif / / _AES_CBC 256_H_
源文件:AES_CBC256.cpp

   
   
   
    
     
  1. #ifndef _AES_CBC 256_H_
  2. # include "AES_CBC256.h"
  3. #endif
  4. AES_CBC 256 ::AES_CBC 256() {
  5. memcpy(m_userKey, "XZJE151628AED2A6ABF7158809CF4F3C2B7E151628AED2A6ABF7158809CF4FTP", USER_ KEY_ LENGTH);
  6. memcpy(m_ivec, "XZJ2030405060708090A0B0C0D0E0FTP", IVEC_ LENGTH); / / Vector initialization
  7. }
  8. AES_CBC 256 ::~AES_CBC 256() {
  9. }
  10. bool AES_CBC 256 ::AES_CBC 256_Encrypt(const unsigned char * in, unsigned char *out, size_t length) {
  11. if ( 0 ! = ( length % AES_ BLOCK_ SIZE)) {
  12. printf( "%s\n", "the length is not multiple of AES_BLOCK_SIZE(16bytes)");
  13. return false;
  14. }
  15. unsigned char ivec [IVEC_ LENGTH];
  16. memcpy(ivec, m_ivec, IVEC_ LENGTH);
  17. AES_ KEY key;
  18. / / get the key with userkey
  19. if (AES_ set_encrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  20. printf( "%s\n", "get the key error");
  21. return false;
  22. } else {
  23. printf( "%s\n", "get the key successful");
  24. }
  25. AES_cbc_encrypt( in, out, length, & key, ivec, AES_ENCRYPT);
  26. return true;
  27. }
  28. bool AES_CBC 256 ::AES_CBC 256_Decrypt(const unsigned char * in, unsigned char *out, size_t length) {
  29. if ( 0 ! = ( length % AES_ BLOCK_ SIZE)) {
  30. printf( "%s\n", "the length is not multiple of AES_BLOCK_SIZE(16bytes)");
  31. return false;
  32. }
  33. unsigned char ivec [IVEC_ LENGTH];
  34. memcpy(ivec, m_ivec, IVEC_ LENGTH);
  35. AES_ KEY key;
  36. / / get the key with userkey
  37. if (AES_ set_decrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  38. printf( "%s\n", "get the key error");
  39. return false;
  40. } else {
  41. printf( "%s\n", "get the key successful");
  42. }
  43. AES_cbc_encrypt( in, out, length, & key, ivec, AES_DECRYPT);
  44. return true;
  45. }
入口测试文件:AES_main.cpp

   
   
   
    
     
  1. #ifndef _AES_CBC 256_H_
  2. # include "AES_CBC256.h"
  3. #endif
  4. #define NAME_ SIZE 34
  5. struct persion
  6. {
  7. int age;
  8. unsigned char name [NAME_ SIZE];
  9. };
  10. int main(int argc, char const *argv[])
  11. {
  12. AES_CBC 256 m_pcAES_CBC 256;
  13. persion m_persion = { 28, "xzj8023tp"};
  14. size_t length = 0;
  15. if ( 0 = = (sizeof(persion) % AES_ BLOCK_ SIZE)) {
  16. length = sizeof(persion);
  17. } else {
  18. length = sizeof(persion) + (AES_ BLOCK_ SIZE - sizeof(persion) % AES_ BLOCK_ SIZE);
  19. }
  20. unsigned char *encrypt_ in_ data = new unsigned char[sizeof(persion)];
  21. unsigned char *encrypt_out_ data = new unsigned char[ length];
  22. memcpy(encrypt_ in_ data, &m_persion, sizeof(persion));
  23. / / encrypt
  24. bool encrypt_ret = m_pcAES_CBC 256.AES_CBC 256_Encrypt(encrypt_ in_ data, encrypt_out_ data, length);
  25. if ( false = = encrypt_ret) {
  26. printf( "encrypt error!\n");
  27. } else {
  28. printf( "encrypt successful!\n");
  29. }
  30. / /decrypt
  31. unsigned char *decrypt_out_ data = new unsigned char[ length];
  32. bool decrypt_ret = m_pcAES_CBC 256.AES_CBC 256_Decrypt(encrypt_out_ data, decrypt_out_ data, length);
  33. if ( false = = decrypt_ret) {
  34. printf( "decrypt error!\n");
  35. } else {
  36. printf( "decrypt successful!\n");
  37. persion showData;
  38. memcpy( &showData, decrypt_out_ data, sizeof(persion));
  39. printf( "my name is [%s] and I am [%d] years old\n", showData.name, showData.age);
  40. }
  41. return 0;
  42. }

当出现下面错误的时候


   
   
   
    
     
  1. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES$ g + + AES_main.cpp AES_CBC 256.cpp -o main. run
  2. /tmp /ccsNmQln.o:在函数‘AES_CBC 256 ::AES_CBC 256_Encrypt(unsigned char const *, unsigned char *, unsigned long)’中:
  3. AES_CBC 256.cpp:(.text + 0x 131):对‘AES_ set_encrypt_ key’未定义的引用
  4. AES_CBC 256.cpp:(.text + 0x 184):对‘AES_cbc_encrypt’未定义的引用
  5. /tmp /ccsNmQln.o:在函数‘AES_CBC 256 ::AES_CBC 256_Decrypt(unsigned char const *, unsigned char *, unsigned long)’中:
  6. AES_CBC 256.cpp:(.text + 0x 235):对‘AES_ set_decrypt_ key’未定义的引用
  7. AES_CBC 256.cpp:(.text + 0x 288):对‘AES_cbc_encrypt’未定义的引用
  8. collect 2: error: ld returned 1 exit status

链接到openssl库 – 将其添加到您的命令行:-lssl -lcrypto

在Linux里的编译命令:

g++ AES_main.cpp  AES_CBC256.cpp  -o main.run -lssl -lcrypto

   
   
   
    
     

当出现下面错误openssl/aes.h: 没有那个文件或目录


   
   
   
    
     
  1. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES$ g + + AES_main.cpp AES_CBC 256.cpp -o main. run
  2. In file included from AES_main.cpp: 2: 0:
  3. AES_CBC 256.h: 5: 25: fatal error: openssl /aes.h: 没有那个文件或目录
  4. #include <openssl /aes.h >
  5. ^
  6. compilation terminated.
  7. In file included from AES_CBC 256.cpp: 2: 0:
  8. AES_CBC 256.h: 5: 25: fatal error: openssl /aes.h: 没有那个文件或目录
  9. #include <openssl /aes.h >
  10. ^
  11. compilation terminated.

解决办法:


   
   
   
    
     
  1. sudo apt- get install openssl
  2. sudo apt- get install libssl-dev
最后执行结果:

5.2、ECB模式的实战代码

头文件:AES_ECB256.h

   
   
   
    
     
  1. #ifndef _AES_ECB256_H_
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <openssl/aes.h>
  6. #include <stddef.h>
  7. #define _AES_ECB256_H_
  8. #define USER_KEY_LENGTH 32
  9. #define AES_BLOCK_SIZE 16
  10. #define BITS_LENGTH (USER_KEY_LENGTH * 8)
  11. class AES_ECB256 {
  12. public:
  13. AES_ECB256();
  14. virtual ~ AES_ECB256();
  15. // CBC Mode Encrypt
  16. bool AES_ECB256_Encrypt(const unsigned char *in, unsigned char *out);
  17. // CBC Mode Decrypt
  18. bool AES_ECB256_Decrypt(const unsigned char *in, unsigned char *out);
  19. unsigned char m_userKey [USER_KEY_LENGTH];
  20. };
  21. #endif // _AES_ECB256_H_
源文件:AES_ECB256.cpp

   
   
   
    
     
  1. #ifndef _AES_ECB 256_H_
  2. # include "AES_ECB256.h"
  3. #endif
  4. AES_ECB 256 ::AES_ECB 256() {
  5. memcpy(m_userKey, "XZJE151628AED2A6ABF7158809CF4F3C2B7E151628AED2A6ABF7158809CF4FTP", USER_ KEY_ LENGTH);
  6. }
  7. AES_ECB 256 ::~AES_ECB 256() {
  8. }
  9. bool AES_ECB 256 ::AES_ECB 256_Encrypt(const unsigned char * in, unsigned char *out) {
  10. AES_ KEY key;
  11. / / get the key with userkey
  12. if (AES_ set_encrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  13. printf( "%s\n", "get the key error");
  14. return false;
  15. } else {
  16. printf( "%s\n", "get the key successful");
  17. }
  18. AES_ecb_encrypt( in, out, & key, AES_ENCRYPT);
  19. return true;
  20. }
  21. bool AES_ECB 256 ::AES_ECB 256_Decrypt(const unsigned char * in, unsigned char *out) {
  22. AES_ KEY key;
  23. / / get the key with userkey
  24. if (AES_ set_decrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  25. printf( "%s\n", "get the key error");
  26. return false;
  27. } else {
  28. printf( "%s\n", "get the key successful");
  29. }
  30. AES_ecb_encrypt( in, out, & key, AES_DECRYPT);
  31. return true;
  32. }
入口测试文件:ECB_main.cpp

   
   
   
    
     
  1. #ifndef _AES_ECB256_H_
  2. # include "AES_ECB256.h"
  3. #endif
  4. #define NAME_SIZE 34
  5. struct persion
  6. {
  7. int age;
  8. unsigned char name [NAME_SIZE];
  9. };
  10. int main(int argc, char const *argv[])
  11. {
  12. AES_ECB256 m_pcAES_ECB256;
  13. persion m_persion = { 28, "xzj8023tp"};
  14. unsigned char *encrypt_in_data = new unsigned char[ sizeof(persion)];
  15. unsigned char *encrypt_out_data = new unsigned char[ sizeof(persion)];
  16. memcpy(encrypt_in_data, &m_persion, sizeof(persion));
  17. // encrypt
  18. bool encrypt_ret = m_pcAES_ECB256. AES_ECB256_Encrypt(encrypt_in_data, encrypt_out_data);
  19. if ( false == encrypt_ret) {
  20. printf( "encrypt error!\n");
  21. } else {
  22. printf( "encrypt successful!\n");
  23. }
  24. //decrypt
  25. unsigned char *decrypt_out_data = new unsigned char[ sizeof(persion)];
  26. bool decrypt_ret = m_pcAES_ECB256. AES_ECB256_Decrypt(encrypt_out_data, decrypt_out_data);
  27. if ( false == decrypt_ret) {
  28. printf( "decrypt error!\n");
  29. } else {
  30. printf( "decrypt successful!\n");
  31. persion showData;
  32. memcpy(&showData, decrypt_out_data, sizeof(persion));
  33. printf( "my name is [%s] and I am [%d] years old\n", showData.name, showData.age);
  34. }
  35. return 0;
  36. }
最后执行结果:

   
   
   
    
     
  1. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$ g + + AES_ECB 256.cpp ECB_main.cpp -o main_ run -lssl -lcrypto
  2. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$ ls
  3. AES_ECB 256.cpp AES_ECB 256.h ECB_main.cpp main_ run
  4. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$ . /main_ run
  5. get the key successful
  6. encrypt successful!
  7. get the key successful
  8. decrypt successful!
  9. my name is [xzj 8023tp] and I am [ 28] years old
  10. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$

要想学习AES,首先要清楚三个基本的概念:密钥、填充、模式。

1、密钥

密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称,是因为这类算法对明文的加密和解密需要使用同一个密钥。

AES支持三种长度的密钥: 128位,192位,256位

平时大家所说的AES128AES192AES256,实际上就是指AES算法对不同长度密钥的使用。

三种密钥的区别:

从安全性来看,AES256安全性最高。从性能看,AES128性能最高。本质原因是它们的加密处理轮数不同。

2、填充

要想了解填充的概念,我们先要了解AES的分组加密特性。
什么是分组加密?

AES算法在对明文加密的时候,并不是把整个明文一股脑的加密成一整段密文,而是把明文拆分成一个个独立的明文块,每一个明文块长度128bit

这些明文块经过AES加密器复杂处理,生成一个个独立的密文块,这些密文块拼接在一起,就是最终的AES加密的结果。

但这里涉及到一个问题,假如一段明文长度是196bit,如果按每128bit一个明文块来拆分的话,第二个明文块只有64bit,不足128bit。这时候怎么办呢?就需要对明文块进行填充(Padding) 。

几种典型的填充方式:

NoPadding: 不做任何填充,但是要求明文必须是16字节的整数倍。
PKCS5Padding(默认): 如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字符,且每个字节的值等于缺少的字符数。 比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则补全为{1,2,3,4,5,a,b,c,d,e,6,6,6,6,6,6 }
ISO10126Padding:如果明文块少于16个字节(128bit),在明文块末尾补足相应数量的字节,最后一个字符值等于缺少的字符数,其他字符填充随机数。比如明文:{1,2,3,4,5,a,b,c,d,e},缺少6个字节,则可能补全为{1,2,3,4,5,a,b,c,d,e,5,c,3,G,$,6}
PKCS7Padding原理与PKCS5Padding相似,区别是PKCS5Paddingblocksize为8字节,而PKCS7Paddingblocksize可以为1到255字节

需要注意的是,如果在AES加密的时候使用了某一种填充方式,解密的时候也必须采用同样的填充方式。

3、模式

AES的工作模式,体现在把明文块加密成密文块的处理过程中。AES加密算法提供了五种不同的工作模式:CBC,ECB,CTR,CFB,OFB
模式之间的主题思想是近似的,在处理细节上有一些差别

AES加密算法 - 加密模式

ECB模式
  优点:
  1.简单;
  2.有利于并行计算;
  3.误差不会被传送;
  缺点:
  1.不能隐藏明文的模式;
  2.可能对明文进行主动攻击;
CBC模式:
  优点:
  1.不容易主动攻击,安全性好于ECB,适合传输长度长的报文,是SSL、IPSec的标准。
  缺点:
  1.不利于并行计算;
  2.误差传递;
  3.需要初始化向量IV
CFB模式:
  优点:
  1.隐藏了明文模式;
  2.分组密码转化为流模式;
  3.可以及时加密传送小于分组的数据;
  缺点:
  1.不利于并行计算;
  2.误差传送:一个明文单元损坏影响多个单元;
  3.唯一的IV;
ofb模式:
  优点:
  1.隐藏了明文模式;
  2.分组密码转化为流模式;
  3.可以及时加密传送小于分组的数据;
  缺点:
  1.不利于并行计算;
  2.对明文的主动攻击是可能的;
  3.误差传送:一个明文单元损坏影响多个单元;

上面四个不同模式原理图链接:分组对称加密模式:ECB/CBC/CFB/OFB缺CTR - Ady Lee - 博客园

3.1、ECB模式简介

img

2)、CBC模式简介

下图中,IV一般为16字节全0,数据块长度为16字节的整数倍,则在此数据块后附加一个8字节长的数据块,

附加的数据块为:16进制的“80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00”

img

cbc本质上和ecb差别不大,唯一区别是将前一次加密结果,与要加密的内容异或。因此,cbc的并行性较差,因为每次都要等待前一次的结果,而ecb则不用,速度较快。其主要区别仍然看文章开头,原理图看参考链接。

3.2、AES算法ECB模式

生成加密/解密的Key

   
   
 
  
   
  1. int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
  2. int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);

参数说明:

参数名称 描述
userKey 用户指定的密码。注意:只能是16、24、32字节。如果密码字符串长度不够,可以在字符串末尾追加一些特定的字符,或者重复密码字符串,直到满足最少的长度
bits 密码位数。即userKey的长度 * 8,只能是128、192、256位。
key 向外输出参数。

如果函数调用成功,返回0,否则是负数。

使用函数AES_ecb_encrypt对数据进行加解密

函数原型:

void AES_ecb_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key, const int enc);

   
   
 
  
   

函数说明:

AES加密/解密单个数据块(16个字节),ECB模式

参数说明:

参数名称 描述
in 需要加密/解密的数据
out 计算后输出的数据
key 密钥
enc AES_ENCRYPT 代表加密, AES_DECRYPT代表解密

3.3、AES算法CBC模式

生成加密/解密的Key

   
   
 
  
   
  1. int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);
  2. int AES_set_decrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);

参数说明:

参数名称 描述
userKey 用户指定的密码。注意:只能是16、24、32字节。如果密码字符串长度不够,可以在字符串末尾追加一些特定的字符,或者重复密码字符串,直到满足最少的长度
bits 密码位数。即userKey的长度 * 8,只能是128、192、256位。
key 向外输出参数。

如果函数调用成功,返回0,否则是负数。

使用AES_cbc_encrypt对数据进行加解密

   
   
 
  
   
  1. void AES_cbc_encrypt(const unsigned char *in, unsigned char *out,
  2. size_t length, const AES_KEY *key,
  3. unsigned char *ivec, const int enc);

函数说明:

AES加密/解密单个数据块(16个字节),CBC模式

参数说明:

参数名称 描述
in 输入数据。长度任意。
out 输出数据。能够容纳下输入数据,且长度必须是16字节的倍数。
length 输出数据的实际长度。
key 使用AES_set_encrypt/decrypt_key生成的Key。
ivec 可读写的一块内存。长度必须是16字节。
enc 是否是加密操作。AES_ENCRYPT表示加密,AES_DECRYPT表示解密。

​ 这个函数比AES_encrypt多了一个ivec参数,ivec的内容可以任意指定,但是加密和解密操作必须使用同样的数据。在AES_cbc_encrypt底层,实际上是每16个字节做一次处理,先和ivec做异或运算,然后调用AES_encrypt函数进行加密。
AES_cbc_encrypt在加密的过程中会修改ivec的内容,因此ivec参数不能是一个常量,而且不能在传递给加密函数后再立马传递给解密函数,必须重新赋值之后再传递给解密函数。

关于输出数据的长度
输出数据缓冲区的长度必须是16字节的倍数,加密完成后,比输入长度多出来的输出数据是不可以丢弃的。因此,存档的时候,需要记录原始数据的长度

关于输入数据的长度不必是16字节的倍数(做个备忘):
下面是AES_cbc_encrypt函数的底层实现代码


   
   
 
  
   
  1. ...
  2. / /处理 16字节倍数的数据
  3. while (len >= 16) {
  4. for (n = 0; n < 16; + +n)
  5. out[n] = in[n] ^ iv[n];
  6. ( * block) (out, out, key); / /调用AES_encrypt处理数据
  7. iv = out;
  8. len - = 16;
  9. in + = 16;
  10. out + = 16;
  11. }
  12. / /当数据小于 16字节的时候,进入下面的循环
  13. while (len) {
  14. for (n = 0; n < 16 & & n < len; + +n)
  15. out[n] = in[n] ^ iv[n];
  16. for (; n < 16; + +n)
  17. out[n] = iv[n]; / /使用ivec补齐不足 16字节的部分
  18. ( * block) (out, out, key); / /调用AES_encrypt处理数据
  19. iv = out;
  20. if (len <= 16)
  21. break;
  22. len - = 16;
  23. in + = 16;
  24. out + = 16;
  25. }

ECBCBC都是封装下面的加密解密函数实现的。

使用AES加密/解密

   
   
 
  
   
  1. void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);
  2. void AES_decrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);

参数说明:

参数名称 描述
in 输入数据。必须是16字节
out 输出数据。必须是16字节
key 使用AES_set_encrypt/decrypt_key生成的Key。

AES_encrypt/AES_decrypt一次只处理16个字节。如果输入数据较长,你需要使用循环语句,每16个字节处理一次,直到所有数据处理完毕。如果数据不足16字节,可以用0填充至16字节。

4、加密解密后的长度

AES有几种扩展算法,其中ecb和cbc需要填充,即加密后长度可能会不一样,cfb和ofb不需要填充,密文长度和明文长度一样

5、实战代码

/usr/include/openssl/aes.h


   
   
 
  
   
  1. #ifndef HEADER_AES_H
  2. # define HEADER_AES_H
  3. # include <openssl /opensslconf.h >
  4. # ifdef OPENSSL_ NO_AES
  5. # error AES is disabled.
  6. # endif
  7. # include <stddef.h >
  8. # define AES_ENCRYPT 1
  9. # define AES_DECRYPT 0
  10. / *
  11. * Because array size can't be a const in C, the following two are macros.
  12. * Both sizes are in bytes.
  13. */
  14. # define AES_MAXNR 14
  15. # define AES_ BLOCK_ SIZE 16
  16. #ifdef __cplusplus
  17. extern "C" {
  18. #endif
  19. / * This should be a hidden type, but EVP requires that the size be known * /
  20. struct aes_ key_st {
  21. # ifdef AES_LONG
  22. unsigned long rd_ key[ 4 * (AES_MAXNR + 1)];
  23. # else
  24. unsigned int rd_ key[ 4 * (AES_MAXNR + 1)];
  25. # endif
  26. int rounds;
  27. };
  28. typedef struct aes_ key_st AES_ KEY;
  29. const char *AES_ options(void);
  30. int AES_ set_encrypt_ key(const unsigned char *userKey, const int bits,
  31. AES_ KEY * key);
  32. int AES_ set_decrypt_ key(const unsigned char *userKey, const int bits,
  33. AES_ KEY * key);
  34. int private_AES_ set_encrypt_ key(const unsigned char *userKey, const int bits,
  35. AES_ KEY * key);
  36. int private_AES_ set_decrypt_ key(const unsigned char *userKey, const int bits,
  37. AES_ KEY * key);
  38. void AES_encrypt(const unsigned char * in, unsigned char *out,
  39. const AES_ KEY * key);
  40. void AES_decrypt(const unsigned char * in, unsigned char *out,
  41. const AES_ KEY * key);
  42. void AES_ecb_encrypt(const unsigned char * in, unsigned char *out,
  43. const AES_ KEY * key, const int enc);
  44. void AES_cbc_encrypt(const unsigned char * in, unsigned char *out,
  45. size_t length, const AES_ KEY * key,
  46. unsigned char *ivec, const int enc);
  47. void AES_cfb 128_encrypt(const unsigned char * in, unsigned char *out,
  48. size_t length, const AES_ KEY * key,
  49. unsigned char *ivec, int *num, const int enc);
  50. void AES_cfb 1_encrypt(const unsigned char * in, unsigned char *out,
  51. size_t length, const AES_ KEY * key,
  52. unsigned char *ivec, int *num, const int enc);
  53. void AES_cfb 8_encrypt(const unsigned char * in, unsigned char *out,
  54. size_t length, const AES_ KEY * key,
  55. unsigned char *ivec, int *num, const int enc);
  56. void AES_ofb 128_encrypt(const unsigned char * in, unsigned char *out,
  57. size_t length, const AES_ KEY * key,
  58. unsigned char *ivec, int *num);
  59. void AES_ctr 128_encrypt(const unsigned char * in, unsigned char *out,
  60. size_t length, const AES_ KEY * key,
  61. unsigned char ivec[AES_ BLOCK_ SIZE],
  62. unsigned char ecount_buf[AES_ BLOCK_ SIZE],
  63. unsigned int *num);
  64. / * NB: the IV is _two_ blocks long * /
  65. void AES_ige_encrypt(const unsigned char * in, unsigned char *out,
  66. size_t length, const AES_ KEY * key,
  67. unsigned char *ivec, const int enc);
  68. / * NB: the IV is _four_ blocks long * /
  69. void AES_bi_ige_encrypt(const unsigned char * in, unsigned char *out,
  70. size_t length, const AES_ KEY * key,
  71. const AES_ KEY * key 2, const unsigned char *ivec,
  72. const int enc);
  73. int AES_wrap_ key(AES_ KEY * key, const unsigned char *iv,
  74. unsigned char *out,
  75. const unsigned char * in, unsigned int inlen);
  76. int AES_unwrap_ key(AES_ KEY * key, const unsigned char *iv,
  77. unsigned char *out,
  78. const unsigned char * in, unsigned int inlen);
  79. #ifdef __cplusplus
  80. }
  81. #endif
  82. #endif / * !HEADER_AES_H * /

5.1、CBC模式的实战代码

头文件:AES_CBC256.h

   
   
 
  
   
  1. #ifndef _AES_CBC 256_H_
  2. #include <stdio.h >
  3. #include <stdlib.h >
  4. #include < string.h >
  5. #include <openssl /aes.h >
  6. #include <stddef.h >
  7. #define _AES_CBC 256_H_
  8. #define USER_ KEY_ LENGTH 32
  9. #define IVEC_ LENGTH 16
  10. #define AES_ BLOCK_ SIZE 16
  11. #define BITS_ LENGTH (USER_ KEY_ LENGTH * 8)
  12. class AES_CBC 256 {
  13. public:
  14. AES_CBC 256();
  15. virtual ~AES_CBC 256();
  16. / / CBC Mode Encrypt
  17. bool AES_CBC 256_Encrypt(const unsigned char * in, unsigned char *out, size_t length);
  18. / / CBC Mode Decrypt
  19. bool AES_CBC 256_Decrypt(const unsigned char * in, unsigned char *out, size_t length);
  20. unsigned char m_userKey [USER_ KEY_ LENGTH];
  21. unsigned char m_ivec [IVEC_ LENGTH]; / / Default value is all 0 of 16
  22. };
  23. #endif / / _AES_CBC 256_H_
源文件:AES_CBC256.cpp

   
   
 
  
   
  1. #ifndef _AES_CBC 256_H_
  2. # include "AES_CBC256.h"
  3. #endif
  4. AES_CBC 256 ::AES_CBC 256() {
  5. memcpy(m_userKey, "XZJE151628AED2A6ABF7158809CF4F3C2B7E151628AED2A6ABF7158809CF4FTP", USER_ KEY_ LENGTH);
  6. memcpy(m_ivec, "XZJ2030405060708090A0B0C0D0E0FTP", IVEC_ LENGTH); / / Vector initialization
  7. }
  8. AES_CBC 256 ::~AES_CBC 256() {
  9. }
  10. bool AES_CBC 256 ::AES_CBC 256_Encrypt(const unsigned char * in, unsigned char *out, size_t length) {
  11. if ( 0 ! = ( length % AES_ BLOCK_ SIZE)) {
  12. printf( "%s\n", "the length is not multiple of AES_BLOCK_SIZE(16bytes)");
  13. return false;
  14. }
  15. unsigned char ivec [IVEC_ LENGTH];
  16. memcpy(ivec, m_ivec, IVEC_ LENGTH);
  17. AES_ KEY key;
  18. / / get the key with userkey
  19. if (AES_ set_encrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  20. printf( "%s\n", "get the key error");
  21. return false;
  22. } else {
  23. printf( "%s\n", "get the key successful");
  24. }
  25. AES_cbc_encrypt( in, out, length, & key, ivec, AES_ENCRYPT);
  26. return true;
  27. }
  28. bool AES_CBC 256 ::AES_CBC 256_Decrypt(const unsigned char * in, unsigned char *out, size_t length) {
  29. if ( 0 ! = ( length % AES_ BLOCK_ SIZE)) {
  30. printf( "%s\n", "the length is not multiple of AES_BLOCK_SIZE(16bytes)");
  31. return false;
  32. }
  33. unsigned char ivec [IVEC_ LENGTH];
  34. memcpy(ivec, m_ivec, IVEC_ LENGTH);
  35. AES_ KEY key;
  36. / / get the key with userkey
  37. if (AES_ set_decrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  38. printf( "%s\n", "get the key error");
  39. return false;
  40. } else {
  41. printf( "%s\n", "get the key successful");
  42. }
  43. AES_cbc_encrypt( in, out, length, & key, ivec, AES_DECRYPT);
  44. return true;
  45. }
入口测试文件:AES_main.cpp

   
   
 
  
   
  1. #ifndef _AES_CBC 256_H_
  2. # include "AES_CBC256.h"
  3. #endif
  4. #define NAME_ SIZE 34
  5. struct persion
  6. {
  7. int age;
  8. unsigned char name [NAME_ SIZE];
  9. };
  10. int main(int argc, char const *argv[])
  11. {
  12. AES_CBC 256 m_pcAES_CBC 256;
  13. persion m_persion = { 28, "xzj8023tp"};
  14. size_t length = 0;
  15. if ( 0 = = (sizeof(persion) % AES_ BLOCK_ SIZE)) {
  16. length = sizeof(persion);
  17. } else {
  18. length = sizeof(persion) + (AES_ BLOCK_ SIZE - sizeof(persion) % AES_ BLOCK_ SIZE);
  19. }
  20. unsigned char *encrypt_ in_ data = new unsigned char[sizeof(persion)];
  21. unsigned char *encrypt_out_ data = new unsigned char[ length];
  22. memcpy(encrypt_ in_ data, &m_persion, sizeof(persion));
  23. / / encrypt
  24. bool encrypt_ret = m_pcAES_CBC 256.AES_CBC 256_Encrypt(encrypt_ in_ data, encrypt_out_ data, length);
  25. if ( false = = encrypt_ret) {
  26. printf( "encrypt error!\n");
  27. } else {
  28. printf( "encrypt successful!\n");
  29. }
  30. / /decrypt
  31. unsigned char *decrypt_out_ data = new unsigned char[ length];
  32. bool decrypt_ret = m_pcAES_CBC 256.AES_CBC 256_Decrypt(encrypt_out_ data, decrypt_out_ data, length);
  33. if ( false = = decrypt_ret) {
  34. printf( "decrypt error!\n");
  35. } else {
  36. printf( "decrypt successful!\n");
  37. persion showData;
  38. memcpy( &showData, decrypt_out_ data, sizeof(persion));
  39. printf( "my name is [%s] and I am [%d] years old\n", showData.name, showData.age);
  40. }
  41. return 0;
  42. }

当出现下面错误的时候


   
   
 
  
   
  1. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES$ g + + AES_main.cpp AES_CBC 256.cpp -o main. run
  2. /tmp /ccsNmQln.o:在函数‘AES_CBC 256 ::AES_CBC 256_Encrypt(unsigned char const *, unsigned char *, unsigned long)’中:
  3. AES_CBC 256.cpp:(.text + 0x 131):对‘AES_ set_encrypt_ key’未定义的引用
  4. AES_CBC 256.cpp:(.text + 0x 184):对‘AES_cbc_encrypt’未定义的引用
  5. /tmp /ccsNmQln.o:在函数‘AES_CBC 256 ::AES_CBC 256_Decrypt(unsigned char const *, unsigned char *, unsigned long)’中:
  6. AES_CBC 256.cpp:(.text + 0x 235):对‘AES_ set_decrypt_ key’未定义的引用
  7. AES_CBC 256.cpp:(.text + 0x 288):对‘AES_cbc_encrypt’未定义的引用
  8. collect 2: error: ld returned 1 exit status

链接到openssl库 – 将其添加到您的命令行:-lssl -lcrypto

在Linux里的编译命令:

g++ AES_main.cpp  AES_CBC256.cpp  -o main.run -lssl -lcrypto

   
   
 
  
   

当出现下面错误openssl/aes.h: 没有那个文件或目录


   
   
 
  
   
  1. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES$ g + + AES_main.cpp AES_CBC 256.cpp -o main. run
  2. In file included from AES_main.cpp: 2: 0:
  3. AES_CBC 256.h: 5: 25: fatal error: openssl /aes.h: 没有那个文件或目录
  4. #include <openssl /aes.h >
  5. ^
  6. compilation terminated.
  7. In file included from AES_CBC 256.cpp: 2: 0:
  8. AES_CBC 256.h: 5: 25: fatal error: openssl /aes.h: 没有那个文件或目录
  9. #include <openssl /aes.h >
  10. ^
  11. compilation terminated.

解决办法:


   
   
 
  
   
  1. sudo apt- get install openssl
  2. sudo apt- get install libssl-dev
最后执行结果:

5.2、ECB模式的实战代码

头文件:AES_ECB256.h

   
   
 
  
   
  1. #ifndef _AES_ECB256_H_
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5. #include <openssl/aes.h>
  6. #include <stddef.h>
  7. #define _AES_ECB256_H_
  8. #define USER_KEY_LENGTH 32
  9. #define AES_BLOCK_SIZE 16
  10. #define BITS_LENGTH (USER_KEY_LENGTH * 8)
  11. class AES_ECB256 {
  12. public:
  13. AES_ECB256();
  14. virtual ~ AES_ECB256();
  15. // CBC Mode Encrypt
  16. bool AES_ECB256_Encrypt(const unsigned char *in, unsigned char *out);
  17. // CBC Mode Decrypt
  18. bool AES_ECB256_Decrypt(const unsigned char *in, unsigned char *out);
  19. unsigned char m_userKey [USER_KEY_LENGTH];
  20. };
  21. #endif // _AES_ECB256_H_
源文件:AES_ECB256.cpp

   
   
 
  
   
  1. #ifndef _AES_ECB 256_H_
  2. # include "AES_ECB256.h"
  3. #endif
  4. AES_ECB 256 ::AES_ECB 256() {
  5. memcpy(m_userKey, "XZJE151628AED2A6ABF7158809CF4F3C2B7E151628AED2A6ABF7158809CF4FTP", USER_ KEY_ LENGTH);
  6. }
  7. AES_ECB 256 ::~AES_ECB 256() {
  8. }
  9. bool AES_ECB 256 ::AES_ECB 256_Encrypt(const unsigned char * in, unsigned char *out) {
  10. AES_ KEY key;
  11. / / get the key with userkey
  12. if (AES_ set_encrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  13. printf( "%s\n", "get the key error");
  14. return false;
  15. } else {
  16. printf( "%s\n", "get the key successful");
  17. }
  18. AES_ecb_encrypt( in, out, & key, AES_ENCRYPT);
  19. return true;
  20. }
  21. bool AES_ECB 256 ::AES_ECB 256_Decrypt(const unsigned char * in, unsigned char *out) {
  22. AES_ KEY key;
  23. / / get the key with userkey
  24. if (AES_ set_decrypt_ key(m_userKey, BITS_ LENGTH, & key) < 0) {
  25. printf( "%s\n", "get the key error");
  26. return false;
  27. } else {
  28. printf( "%s\n", "get the key successful");
  29. }
  30. AES_ecb_encrypt( in, out, & key, AES_DECRYPT);
  31. return true;
  32. }
入口测试文件:ECB_main.cpp

   
   
 
  
   
  1. #ifndef _AES_ECB256_H_
  2. # include "AES_ECB256.h"
  3. #endif
  4. #define NAME_SIZE 34
  5. struct persion
  6. {
  7. int age;
  8. unsigned char name [NAME_SIZE];
  9. };
  10. int main(int argc, char const *argv[])
  11. {
  12. AES_ECB256 m_pcAES_ECB256;
  13. persion m_persion = { 28, "xzj8023tp"};
  14. unsigned char *encrypt_in_data = new unsigned char[ sizeof(persion)];
  15. unsigned char *encrypt_out_data = new unsigned char[ sizeof(persion)];
  16. memcpy(encrypt_in_data, &m_persion, sizeof(persion));
  17. // encrypt
  18. bool encrypt_ret = m_pcAES_ECB256. AES_ECB256_Encrypt(encrypt_in_data, encrypt_out_data);
  19. if ( false == encrypt_ret) {
  20. printf( "encrypt error!\n");
  21. } else {
  22. printf( "encrypt successful!\n");
  23. }
  24. //decrypt
  25. unsigned char *decrypt_out_data = new unsigned char[ sizeof(persion)];
  26. bool decrypt_ret = m_pcAES_ECB256. AES_ECB256_Decrypt(encrypt_out_data, decrypt_out_data);
  27. if ( false == decrypt_ret) {
  28. printf( "decrypt error!\n");
  29. } else {
  30. printf( "decrypt successful!\n");
  31. persion showData;
  32. memcpy(&showData, decrypt_out_data, sizeof(persion));
  33. printf( "my name is [%s] and I am [%d] years old\n", showData.name, showData.age);
  34. }
  35. return 0;
  36. }
最后执行结果:

   
   
 
  
   
  1. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$ g + + AES_ECB 256.cpp ECB_main.cpp -o main_ run -lssl -lcrypto
  2. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$ ls
  3. AES_ECB 256.cpp AES_ECB 256.h ECB_main.cpp main_ run
  4. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$ . /main_ run
  5. get the key successful
  6. encrypt successful!
  7. get the key successful
  8. decrypt successful!
  9. my name is [xzj 8023tp] and I am [ 28] years old
  10. xzj@xzj-virtual-machine:~ / Code /C + + Code /AES /AES_ECB$

相关推荐

  1. PHP AES 解密示例

    2024-01-12 16:10:04       31 阅读
  2. PHP AES解密示例

    2024-01-12 16:10:04       34 阅读
  3. PHP AES解密系列

    2024-01-12 16:10:04       37 阅读
  4. PHP AES解密示例

    2024-01-12 16:10:04       33 阅读
  5. PHP使用AES进行解密

    2024-01-12 16:10:04       18 阅读
  6. 鸿蒙开发之AES解密

    2024-01-12 16:10:04       19 阅读
  7. 基于openssl实现AES ECB解密

    2024-01-12 16:10:04       8 阅读
  8. 基于AES图像解密算法的MATLAB仿真

    2024-01-12 16:10:04       30 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-01-12 16:10:04       16 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-01-12 16:10:04       16 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-01-12 16:10:04       15 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-01-12 16:10:04       18 阅读

热门阅读

  1. python第三节:Str字符串类型(4)

    2024-01-12 16:10:04       36 阅读
  2. 「BUG」启动jar配置文件里的参数无法替换。

    2024-01-12 16:10:04       42 阅读
  3. 如何识别bootstrap版本?

    2024-01-12 16:10:04       32 阅读
  4. Golang 单元测试

    2024-01-12 16:10:04       35 阅读
  5. go语言的http post推送

    2024-01-12 16:10:04       34 阅读
  6. LNMP平台对接redis服务

    2024-01-12 16:10:04       25 阅读