温州15000 做网站的工作,更多标签的下载方法,南平建设企业网站,关晓彤经纪公司要想学习AES#xff0c;首先要清楚三个基本的概念#xff1a;密钥、填充、模式。 1、密钥 密钥是AES算法实现加密和解密的根本。对称加密算法之所以对称#xff0c;是因为这类算法对明文的加密和解密需要使用同一个密钥。 AES支持三种长度的密钥#xff1a; 128位#xff… 要想学习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相似区别是PKCS5Padding的blocksize为8字节而PKCS7Padding的blocksize可以为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模式简介 2、CBC模式简介 下图中IV一般为16字节全0数据块长度为16字节的整数倍则在此数据块后附加一个8字节长的数据块 附加的数据块为16进制的“80 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00” cbc本质上和ecb差别不大唯一区别是将前一次加密结果与要加密的内容异或。因此cbc的并行性较差因为每次都要等待前一次的结果而ecb则不用速度较快。其主要区别仍然看文章开头原理图看参考链接。 3.2、AES算法ECB模式 生成加密/解密的Key int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);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密钥encAES_ENCRYPT 代表加密 AES_DECRYPT代表解密 3.3、AES算法CBC模式 生成加密/解密的Key int AES_set_encrypt_key(const unsigned char *userKey, const int bits, AES_KEY *key);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对数据进行加解密 void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, 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函数的底层实现代码 ... //处理16字节倍数的数据while (len 16) { for (n 0; n 16; n)out[n] in[n] ^ iv[n];(*block) (out, out, key); //调用AES_encrypt处理数据iv out;len - 16; in 16;out 16;} //当数据小于16字节的时候进入下面的循环while (len) { for (n 0; n 16 n len; n)out[n] in[n] ^ iv[n]; for (; n 16; n)out[n] iv[n]; //使用ivec补齐不足16字节的部分(*block) (out, out, key); //调用AES_encrypt处理数据iv out; if (len 16)break;len - 16; in 16;out 16;} ECB与CBC都是封装下面的加密解密函数实现的。 使用AES加密/解密 void AES_encrypt(const unsigned char *in, unsigned char *out, const AES_KEY *key);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 #ifndef HEADER_AES_H# define HEADER_AES_H # include openssl/opensslconf.h # ifdef OPENSSL_NO_AES# error AES is disabled.# endif # include stddef.h # define AES_ENCRYPT 1# define AES_DECRYPT 0 /* * Because array size cant be a const in C, the following two are macros. * Both sizes are in bytes. */# define AES_MAXNR 14# define AES_BLOCK_SIZE 16 #ifdef __cplusplusextern C {#endif /* This should be a hidden type, but EVP requires that the size be known */struct aes_key_st {# ifdef AES_LONGunsigned long rd_key[4 * (AES_MAXNR 1)];# elseunsigned int rd_key[4 * (AES_MAXNR 1)];# endifint rounds;};typedef struct aes_key_st AES_KEY; const char *AES_options(void); int AES_set_encrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key);int AES_set_decrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key); int private_AES_set_encrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key);int private_AES_set_decrypt_key(const unsigned char *userKey, const int bits,AES_KEY *key); void AES_encrypt(const unsigned char *in, unsigned char *out,const AES_KEY *key);void AES_decrypt(const unsigned char *in, unsigned char *out,const AES_KEY *key); void AES_ecb_encrypt(const unsigned char *in, unsigned char *out,const AES_KEY *key, const int enc);void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char *ivec, const int enc);void AES_cfb128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char *ivec, int *num, const int enc);void AES_cfb1_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char *ivec, int *num, const int enc);void AES_cfb8_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char *ivec, int *num, const int enc);void AES_ofb128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char *ivec, int *num);void AES_ctr128_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char ivec[AES_BLOCK_SIZE],unsigned char ecount_buf[AES_BLOCK_SIZE],unsigned int *num);/* NB: the IV is _two_ blocks long */void AES_ige_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,unsigned char *ivec, const int enc);/* NB: the IV is _four_ blocks long */void AES_bi_ige_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key,const AES_KEY *key2, const unsigned char *ivec,const int enc); int AES_wrap_key(AES_KEY *key, const unsigned char *iv,unsigned char *out,const unsigned char *in, unsigned int inlen);int AES_unwrap_key(AES_KEY *key, const unsigned char *iv,unsigned char *out,const unsigned char *in, unsigned int inlen); #ifdef __cplusplus}#endif #endif /* !HEADER_AES_H */ 5.1、CBC模式的实战代码 头文件AES_CBC256.h #ifndef _AES_CBC256_H_#include stdio.h#include stdlib.h#include string.h#include openssl/aes.h#include stddef.h #define _AES_CBC256_H_#define USER_KEY_LENGTH 32#define IVEC_LENGTH 16#define AES_BLOCK_SIZE 16#define BITS_LENGTH (USER_KEY_LENGTH * 8)class AES_CBC256 { public:AES_CBC256();virtual ~AES_CBC256(); // CBC Mode Encryptbool AES_CBC256_Encrypt(const unsigned char *in, unsigned char *out, size_t length); // CBC Mode Decryptbool AES_CBC256_Decrypt(const unsigned char *in, unsigned char *out, size_t length); unsigned char m_userKey [USER_KEY_LENGTH];unsigned char m_ivec [IVEC_LENGTH]; // Default value is all 0 of 16 };#endif // _AES_CBC256_H_ 源文件AES_CBC256.cpp #ifndef _AES_CBC256_H_# include AES_CBC256.h#endif AES_CBC256::AES_CBC256() {memcpy(m_userKey, XZJE151628AED2A6ABF7158809CF4F3C2B7E151628AED2A6ABF7158809CF4FTP, USER_KEY_LENGTH);memcpy(m_ivec, XZJ2030405060708090A0B0C0D0E0FTP, IVEC_LENGTH); // Vector initialization }AES_CBC256::~AES_CBC256() { } bool AES_CBC256::AES_CBC256_Encrypt(const unsigned char *in, unsigned char *out, size_t length) { if (0 ! (length % AES_BLOCK_SIZE)) {printf(%s\n, the length is not multiple of AES_BLOCK_SIZE(16bytes)); return false;}unsigned char ivec [IVEC_LENGTH];memcpy(ivec, m_ivec, IVEC_LENGTH);AES_KEY key; // get the key with userkey if (AES_set_encrypt_key(m_userKey, BITS_LENGTH, key) 0) {printf(%s\n, get the key error); return false;} else {printf(%s\n, get the key successful);} AES_cbc_encrypt(in, out, length, key, ivec, AES_ENCRYPT); return true;} bool AES_CBC256::AES_CBC256_Decrypt(const unsigned char *in, unsigned char *out, size_t length) { if (0 ! (length % AES_BLOCK_SIZE)) {printf(%s\n, the length is not multiple of AES_BLOCK_SIZE(16bytes)); return false;}unsigned char ivec [IVEC_LENGTH];memcpy(ivec, m_ivec, IVEC_LENGTH);AES_KEY key; // get the key with userkey if (AES_set_decrypt_key(m_userKey, BITS_LENGTH, key) 0) {printf(%s\n, get the key error); return false;} else {printf(%s\n, get the key successful);} AES_cbc_encrypt(in, out, length, key, ivec, AES_DECRYPT); return true;} 入口测试文件AES_main.cpp #ifndef _AES_CBC256_H_# include AES_CBC256.h#endif#define NAME_SIZE 34 struct persion{int age;unsigned char name [NAME_SIZE];}; int main(int argc, char const *argv[]){AES_CBC256 m_pcAES_CBC256;persion m_persion {28,xzj8023tp}; size_t length 0; if (0 (sizeof(persion) % AES_BLOCK_SIZE)) { length sizeof(persion);} else { length sizeof(persion) (AES_BLOCK_SIZE - sizeof(persion) % AES_BLOCK_SIZE);}unsigned char *encrypt_in_data new unsigned char[sizeof(persion)];unsigned char *encrypt_out_data new unsigned char[length];memcpy(encrypt_in_data, m_persion, sizeof(persion)); // encryptbool encrypt_ret m_pcAES_CBC256.AES_CBC256_Encrypt(encrypt_in_data, encrypt_out_data, length); if (false encrypt_ret) {printf(encrypt error!\n);} else {printf(encrypt successful!\n);} //decryptunsigned char *decrypt_out_data new unsigned char[length];bool decrypt_ret m_pcAES_CBC256.AES_CBC256_Decrypt(encrypt_out_data, decrypt_out_data, length); if (false decrypt_ret) {printf(decrypt error!\n);} else {printf(decrypt successful!\n);persion showData;memcpy(showData, decrypt_out_data, sizeof(persion));printf(my name is [%s] and I am [%d] years old\n, showData.name, showData.age);} return 0;} 当出现下面错误的时候 xzjxzj-virtual-machine:~/Code/CCode/AES$ g AES_main.cpp AES_CBC256.cpp -o main.run/tmp/ccsNmQln.o在函数‘AES_CBC256::AES_CBC256_Encrypt(unsigned char const*, unsigned char*, unsigned long)’中AES_CBC256.cpp:(.text0x131)对‘AES_set_encrypt_key’未定义的引用AES_CBC256.cpp:(.text0x184)对‘AES_cbc_encrypt’未定义的引用/tmp/ccsNmQln.o在函数‘AES_CBC256::AES_CBC256_Decrypt(unsigned char const*, unsigned char*, unsigned long)’中AES_CBC256.cpp:(.text0x235)对‘AES_set_decrypt_key’未定义的引用AES_CBC256.cpp:(.text0x288)对‘AES_cbc_encrypt’未定义的引用collect2: 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: 没有那个文件或目录 xzjxzj-virtual-machine:~/Code/CCode/AES$ g AES_main.cpp AES_CBC256.cpp -o main.runIn file included from AES_main.cpp:2:0:AES_CBC256.h:5:25: fatal error: openssl/aes.h: 没有那个文件或目录#include openssl/aes.h^compilation terminated.In file included from AES_CBC256.cpp:2:0:AES_CBC256.h:5:25: fatal error: openssl/aes.h: 没有那个文件或目录#include openssl/aes.h^compilation terminated. 解决办法 sudo apt-get install opensslsudo apt-get install libssl-dev 最后执行结果 5.2、ECB模式的实战代码 头文件AES_ECB256.h #ifndef _AES_ECB256_H_#include stdio.h#include stdlib.h#include string.h#include openssl/aes.h#include stddef.h #define _AES_ECB256_H_#define USER_KEY_LENGTH 32#define AES_BLOCK_SIZE 16#define BITS_LENGTH (USER_KEY_LENGTH * 8)class AES_ECB256 { public: AES_ECB256(); virtual ~AES_ECB256(); // CBC Mode Encrypt bool AES_ECB256_Encrypt(const unsigned char *in, unsigned char *out); // CBC Mode Decrypt bool AES_ECB256_Decrypt(const unsigned char *in, unsigned char *out); unsigned char m_userKey [USER_KEY_LENGTH]; };#endif // _AES_ECB256_H_ 源文件AES_ECB256.cpp #ifndef _AES_ECB256_H_# include AES_ECB256.h#endif AES_ECB256::AES_ECB256() {memcpy(m_userKey, XZJE151628AED2A6ABF7158809CF4F3C2B7E151628AED2A6ABF7158809CF4FTP, USER_KEY_LENGTH); }AES_ECB256::~AES_ECB256() { } bool AES_ECB256::AES_ECB256_Encrypt(const unsigned char *in, unsigned char *out) { AES_KEY key; // get the key with userkey if (AES_set_encrypt_key(m_userKey, BITS_LENGTH, key) 0) {printf(%s\n, get the key error); return false;} else {printf(%s\n, get the key successful);} AES_ecb_encrypt(in, out, key, AES_ENCRYPT); return true;} bool AES_ECB256::AES_ECB256_Decrypt(const unsigned char *in, unsigned char *out) { AES_KEY key; // get the key with userkey if (AES_set_decrypt_key(m_userKey, BITS_LENGTH, key) 0) {printf(%s\n, get the key error); return false;} else {printf(%s\n, get the key successful);} AES_ecb_encrypt(in, out, key, AES_DECRYPT); return true;} 入口测试文件ECB_main.cpp #ifndef _AES_ECB256_H_# include AES_ECB256.h#endif#define NAME_SIZE 34 struct persion{ int age; unsigned char name [NAME_SIZE];}; int main(int argc, char const *argv[]){AES_ECB256 m_pcAES_ECB256;persion m_persion {28,xzj8023tp}; unsigned char *encrypt_in_data new unsigned char[sizeof(persion)]; unsigned char *encrypt_out_data new unsigned char[sizeof(persion)]; memcpy(encrypt_in_data, m_persion, sizeof(persion)); // encrypt bool encrypt_ret m_pcAES_ECB256.AES_ECB256_Encrypt(encrypt_in_data, encrypt_out_data); if (false encrypt_ret) { printf(encrypt error!\n);} else { printf(encrypt successful!\n);} //decrypt unsigned char *decrypt_out_data new unsigned char[sizeof(persion)]; bool decrypt_ret m_pcAES_ECB256.AES_ECB256_Decrypt(encrypt_out_data, decrypt_out_data); if (false decrypt_ret) { printf(decrypt error!\n);} else { printf(decrypt successful!\n);persion showData; memcpy(showData, decrypt_out_data, sizeof(persion)); printf(my name is [%s] and I am [%d] years old\n, showData.name, showData.age);} return 0;} 最后执行结果 xzjxzj-virtual-machine:~/Code/CCode/AES/AES_ECB$ g AES_ECB256.cpp ECB_main.cpp -o main_run -lssl -lcryptoxzjxzj-virtual-machine:~/Code/CCode/AES/AES_ECB$ lsAES_ECB256.cpp AES_ECB256.h ECB_main.cpp main_runxzjxzj-virtual-machine:~/Code/CCode/AES/AES_ECB$ ./main_run get the key successfulencrypt successful!get the key successfuldecrypt successful!my name is [xzj8023tp] and I am [28] years oldxzjxzj-virtual-machine:~/Code/CCode/AES/AES_ECB$