使用Openssl的AES加密算法
原文链接: http://blog.csdn.net/yasi_xi/article/details/13997337
Openssl是很常见的C接口的库,个人觉得易用。以下是AES加密的使用备忘。如果你有一定的密码学基础,那么就很好理解。代码是从网上弄下来的(原始地址已经忘记了),然后在尝试的过程中改了一点东西。其它的cbc、cfb、ecb加密方式的用法都是类似的,只是函数名有点区别,就不一一列举了。
【yasi】IV: Initialization Vector,即初始化向量
一、接口简介
- //设置加密密钥,使用字符缓冲区
- 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);
- //加解密的接口,通过最后的enc来区分是加密还是解密操作
- //每次执行AES_cbc_encrypt后,iv(向量)会被更新,
- //所以需要自己保存它。
- void AES_cbc_encrypt(
- const unsigned char *in,
- unsigned char *out,
- const unsigned long length,
- const AES_KEY *key,
- unsigned char *ivec,
- const int enc);
二、一个简单的Makefile
【yasi】针对CentOS环境,做了修改
- LNK_OPT = -g -L/usr/lib64/ -lssl
- all:
- rm -f codec
- g++ -g aes_codec.cpp -o codec $(LNK_OPT)
- clean:
- rm -f codec
三、示例代码
- #include <stdio.h>
- #include <string.h>
- #include <openssl/aes.h>
- #include <openssl/rand.h>
- /* file testaes.cpp */
- static void hexdump(
- FILE *f,
- const char *title,
- const unsigned char *s,
- int l)
- {
- int n = 0;
- fprintf(f, "%s", title);
- for (; n < l; ++n) {
- if ((n % 16) == 0) {
- fprintf(f, "\n%04x", n);
- }
- fprintf(f, " %02x", s[n]);
- }
- fprintf(f, "\n");
- }
- int main(int argc, char **argv)
- {
- //128bits key.
- unsigned char rkey[16];
- //Internal key.
- AES_KEY key;
- //Testdata.
- // [yasi] Make static content instead of random text
- unsigned char plaintext[AES_BLOCK_SIZE * 4] =
- {
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i',
- '0', '1', '2', '3', '4', '5', '6', '7', '0', '1', '2', '3', '4', '5', '6', '7',
- 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'i',
- '0', '1', '2', '3', '4', '5', '6', '7', '0', '1', '2', '3', '4', '5', '6', '7'
- };
- unsigned char ciphertext[AES_BLOCK_SIZE * 4];
- unsigned char checktext[AES_BLOCK_SIZE * 4];
- //Init vector.
- unsigned char iv[AES_BLOCK_SIZE * 4];
- //Save vector.
- unsigned char saved_iv[AES_BLOCK_SIZE * 4];
- int nr_of_bits = 0;
- int nr_of_bytes = 0;
- //Zeror buffer.
- memset(ciphertext, 0, sizeof ciphertext);
- memset(checktext, 0, sizeof checktext);
- //Generate random
- RAND_pseudo_bytes(rkey, sizeof rkey);
- RAND_pseudo_bytes(saved_iv, sizeof saved_iv);
- hexdump(stdout, "== rkey ==",
- rkey,
- sizeof(rkey));
- hexdump(stdout, "== iv ==",
- saved_iv,
- sizeof(saved_iv));
- printf("\n");
- hexdump(stdout, "== plaintext ==",
- plaintext,
- sizeof(plaintext));
- printf("\n");
- //Entrypt
- memcpy(iv, saved_iv, sizeof(iv));
- nr_of_bits = 8 * sizeof(rkey);
- AES_set_encrypt_key(rkey, nr_of_bits, &key);
- nr_of_bytes = sizeof(plaintext);
- AES_cbc_encrypt(plaintext,
- ciphertext,
- nr_of_bytes,
- &key,
- iv,
- AES_ENCRYPT);
- hexdump(stdout, "== ciphertext ==",
- ciphertext,
- sizeof(ciphertext));
- printf("\n");
- // [yasi] iv is changed in encryption
- hexdump(stdout, "== iv changed ==",
- iv,
- sizeof(iv));
- printf("\n");
- //Decrypt
- memcpy(iv, saved_iv, sizeof(iv)); // [yasi] without this line, decrypt will fail because iv is changed in encryption
- nr_of_bits = 8 * sizeof(rkey);
- AES_set_decrypt_key(rkey, nr_of_bits, &key);
- nr_of_bytes = sizeof(ciphertext);
- AES_cbc_encrypt(ciphertext,
- checktext,
- nr_of_bytes,
- &key, iv,
- AES_DECRYPT);
- hexdump(stdout, "== checktext ==",
- checktext,
- sizeof(checktext));
- printf("\n");
- return 0;
- }
【yasi 运行结果】
- [root@ampcommons02 aes-codec]# ./codec
- == rkey ==
- 0000 81 ac 9b 38 1c 02 c5 c8 1d 7c a0 3f 87 be f2 c6
- == iv ==
- 0000 34 a2 f1 f5 f3 93 76 32 cd 77 ad fb c8 82 f2 1b
- 0010 f3 cc 51 f6 35 f3 49 8d 44 97 8c 2c 89 50 0d d7
- 0020 68 21 d7 2f 0a 90 29 c1 dd c9 39 bc 7c 4f 18 2f
- 0030 04 cc 42 5e 84 8e fe a9 c5 49 00 9f 30 55 94 c0
- == plaintext ==
- 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- == ciphertext ==
- 0000 c4 63 72 29 21 28 7b a2 27 24 4a e4 bb 95 1a d1
- 0010 b8 13 0e 77 0c 8a a4 09 2f ca 85 43 41 b5 5b d5
- 0020 a3 60 92 58 5b dd 45 0c e2 62 af f9 43 81 d7 06
- 0030 41 8e 85 28 3e eb 72 b5 ee 84 8c 27 7e 67 20 f6
- == iv changed ==
- 0000 41 8e 85 28 3e eb 72 b5 ee 84 8c 27 7e 67 20 f6
- 0010 f3 cc 51 f6 35 f3 49 8d 44 97 8c 2c 89 50 0d d7
- 0020 68 21 d7 2f 0a 90 29 c1 dd c9 39 bc 7c 4f 18 2f
- 0030 04 cc 42 5e 84 8e fe a9 c5 49 00 9f 30 55 94 c0
- == checktext ==
- 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
可见,encryption之后,IV立即被修改了。所以,为了能正确decrypt,在decrypt时,必须使用先前encrypt时的IV,即代码第98行。
- [root@ampcommons02 aes-codec]# ./codec
- == rkey ==
- 0000 29 68 75 4d a5 9e 83 9a ed f8 ec bc 2e b8 09 7e
- == iv ==
- 0000 b8 21 09 de 8f 58 6e be 73 be a7 10 fb 91 87 65
- 0010 65 9c d7 0e 4c 88 d2 65 ae de 0b 49 40 c7 75 df
- 0020 19 69 53 0b 11 5d ac e7 08 f6 ae df 16 66 e0 13
- 0030 75 41 f7 bb be 56 a1 dd a7 3e fb 4e 5d 9e e4 a2
- == plaintext ==
- 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- == ciphertext ==
- 0000 5e 85 9c e8 65 d6 3b f9 03 9a a0 b5 78 bd f6 d4
- 0010 11 70 94 c1 c3 78 9a 1d 12 9a 84 48 3a 70 88 13
- 0020 d6 b5 bf c6 e8 e1 76 dc 3c b9 b0 4e b9 bb c4 74
- 0030 35 3d ac fc 29 e3 a0 64 d7 76 ab 76 c7 af dd 39
- == iv changed ==
- 0000 35 3d ac fc 29 e3 a0 64 d7 76 ab 76 c7 af dd 39
- 0010 65 9c d7 0e 4c 88 d2 65 ae de 0b 49 40 c7 75 df
- 0020 19 69 53 0b 11 5d ac e7 08 f6 ae df 16 66 e0 13
- 0030 75 41 f7 bb be 56 a1 dd a7 3e fb 4e 5d 9e e4 a2
- == checktext ==
- 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
可见,两次运行,虽然encrypt的明码是一样的,但encrypt出来的结果是不同的。随机明码 改 静态明码 的目的就是为了比较两次encrypt的结果。即,相同的明码用不同的IV做encrypt,结果是不同的。
- [root@ampcommons02 aes-codec]# ./codec
- == rkey ==
- 0000 69 ef eb 49 25 5a c2 5e 0d 77 8a cb e6 fe ad 1d
- == iv ==
- 0000 8e 05 8c 50 2f 69 9d fb 64 3e cd e6 2d 38 26 1c
- 0010 6e 21 00 e6 32 3f c6 ca 93 8b c1 e3 47 9a bd 81
- 0020 d7 e5 0b 63 dc f8 9d 1f 13 49 35 25 70 4e 64 c2
- 0030 ea 0c d0 78 e7 6c 65 64 41 4d db 2b 50 4d b4 06
- == plaintext ==
- 0000 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- == ciphertext ==
- 0000 a4 ed ba 4b 9f e9 74 bd 6d f6 03 76 79 9f 17 4f
- 0010 0c cd f3 b8 da 69 44 81 c9 f2 8b 03 83 0d 9d 77
- 0020 12 48 ea 46 3f eb 58 fd 48 c5 cc 2d 74 6c 99 4f
- 0030 93 bd 0d 06 f3 55 40 11 cb e7 d4 29 3b 8f 15 76
- == iv changed ==
- 0000 93 bd 0d 06 f3 55 40 11 cb e7 d4 29 3b 8f 15 76
- 0010 6e 21 00 e6 32 3f c6 ca 93 8b c1 e3 47 9a bd 81
- 0020 d7 e5 0b 63 dc f8 9d 1f 13 49 35 25 70 4e 64 c2
- 0030 ea 0c d0 78 e7 6c 65 64 41 4d db 2b 50 4d b4 06
- == checktext ==
- 0000 7c da e2 32 b9 5a ba 83 ce bb 7a ab 73 d1 54 03
- 0010 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
- 0020 61 62 63 64 65 66 67 69 61 62 63 64 65 66 67 69
- 0030 30 31 32 33 34 35 36 37 30 31 32 33 34 35 36 37
可见,decrypt时使用和encrypt时不同的IV,不能正确decrypt出先前的明码。
- #ifndef ALGO_AES_H
- #define ALGO_AES_H
- int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
- unsigned char *iv, unsigned char *ciphertext);
- int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
- unsigned char *iv, unsigned char *plaintext);
- #endif
algo_aes.c
- #include <stdlib.h>
- #include <stdio.h>
- #include "algo_aes.h"
- #include <openssl/evp.h>
- void handleErrors(void)
- {
- ERR_print_errors_fp(stderr);
- abort();
- }
- int encrypt(unsigned char *plaintext, int plaintext_len, unsigned char *key,
- unsigned char *iv, unsigned char *ciphertext)
- {
- EVP_CIPHER_CTX *ctx;
- int len;
- int ciphertext_len;
- /* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
- /* Initialise the encryption operation. IMPORTANT - ensure you use a key
- * and IV size appropriate for your cipher
- * In this example we are using 256 bit AES (i.e. a 256 bit key). The
- * IV size for *most* modes is the same as the block size. For AES this
- * is 128 bits */
- if(1 != EVP_EncryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
- handleErrors();
- /* Provide the message to be encrypted, and obtain the encrypted output.
- * EVP_EncryptUpdate can be called multiple times if necessary
- */
- if(1 != EVP_EncryptUpdate(ctx, ciphertext, &len, plaintext, plaintext_len))
- handleErrors();
- ciphertext_len = len;
- /* Finalise the encryption. Further ciphertext bytes may be written at
- * this stage.
- */
- if(1 != EVP_EncryptFinal_ex(ctx, ciphertext + len, &len)) handleErrors();
- ciphertext_len += len;
- /* Clean up */
- EVP_CIPHER_CTX_free(ctx);
- return ciphertext_len;
- }
- int decrypt(unsigned char *ciphertext, int ciphertext_len, unsigned char *key,
- unsigned char *iv, unsigned char *plaintext)
- {
- EVP_CIPHER_CTX *ctx;
- int len;
- int plaintext_len;
- /* Create and initialise the context */
- if(!(ctx = EVP_CIPHER_CTX_new())) handleErrors();
- /* Initialise the decryption operation. IMPORTANT - ensure you use a key
- * and IV size appropriate for your cipher
- * In this example we are using 256 bit AES (i.e. a 256 bit key). The
- * IV size for *most* modes is the same as the block size. For AES this
- * is 128 bits */
- if(1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv))
- handleErrors();
- /* Provide the message to be decrypted, and obtain the plaintext output.
- * EVP_DecryptUpdate can be called multiple times if necessary
- */
- if(1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len))
- handleErrors();
- plaintext_len = len;
- /* Finalise the decryption. Further plaintext bytes may be written at
- * this stage.
- */
- if(1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) handleErrors();
- plaintext_len += len;
- /* Clean up */
- EVP_CIPHER_CTX_free(ctx);
- return plaintext_len;
- }
main.c
- #include "algo_aes.h"
- #include <stdio.h>
- #include <string.h>
- //#include <openssl/evp.h>
- int main(int arc, char *argv[])
- {
- /* Set up the key and iv. Do I need to say to not hard code these in a
- * real application? :-)
- */
- /* A 256 bit key */
- unsigned char *key = "01234567890123456789012345678901";
- /* A 128 bit IV */
- unsigned char *iv = "01234567890123456";
- /* Message to be encrypted */
- unsigned char *plaintext =
- "The quick brown fox jumps over the lazy dog1234";
- /* Buffer for ciphertext. Ensure the buffer is long enough for the
- * ciphertext which may be longer than the plaintext, dependant on the
- * algorithm and mode
- */
- unsigned char ciphertext[64];
- /* Buffer for the decrypted text */
- unsigned char decryptedtext[64];
- int decryptedtext_len, ciphertext_len;
- /* Initialise the library */
- /* ERR_load_crypto_strings();
- OpenSSL_add_all_algorithms();
- OPENSSL_config(NULL);*/
- printf("Plaintext is:\n%s~\n", plaintext);
- /* Encrypt the plaintext */
- ciphertext_len = encrypt(plaintext, strlen(plaintext), key, iv,
- ciphertext);
- /* Do something useful with the ciphertext here */
- printf("Ciphertext is %d bytes long:\n", ciphertext_len);
- BIO_dump_fp(stdout, ciphertext, ciphertext_len);
- /* Decrypt the ciphertext */
- decryptedtext_len = decrypt(ciphertext, ciphertext_len, key, iv,
- decryptedtext);
- /* Add a NULL terminator. We are expecting printable text */
- decryptedtext[decryptedtext_len] = '\0';
- /* Show the decrypted text */
- printf("Decrypted text is:\n");
- printf("%s~\n", decryptedtext);
- /* Clean up */
- EVP_cleanup();
- ERR_free_strings();
- return 0;
- }
Mekefile:
- OBJ_DIR = ./obj
- BIN_DIR = ./bin
- SRC_DIR = ./
- OBJS = \
- $(OBJ_DIR)/algo_aes.o \
- $(OBJ_DIR)/main.o
- TARGET = $(BIN_DIR)/main
- INC_OPT = -I./
- LNK_OPT = -lssl
- $(TARGET) : clean chkobjdir chkbindir $(OBJS)
- gcc -g -o $@ $(OBJS) $(LNK_OPT)
- $(OBJ_DIR)/%.o : $(SRC_DIR)/%.c
- gcc -g $(INC_OPT) -c -o $@ $<
- chkobjdir :
- @if test ! -d $(OBJ_DIR) ; \
- then \
- mkdir $(OBJ_DIR) ; \
- fi
- chkbindir :
- @if test ! -d $(BIN_DIR) ; \
- then \
- mkdir $(BIN_DIR) ; \
- fi
- clean :
- -rm -f $(TARGET)
- -rm -rf $(OBJ_DIR)
- Plaintext is:
- The quick brown fox jumps over the lazy dog1234~
- Ciphertext is 48 bytes long:
- 0000 - e0 6f 63 a7 11 e8 b7 aa-9f 94 40 10 7d 46 80 a1 .oc.......@.}F..
- 0010 - 17 99 43 80 ea 31 d2 a2-99 b9 53 02 d4 39 b9 70 ..C..1....S..9.p
- 0020 - e9 29 d5 a8 03 bd 71 31-b8 c3 6f 3d 39 3a 3d 3d .)....q1..o=9:==
- Decrypted text is:
- The quick brown fox jumps over the lazy dog1234~
注意:(参考)
AES算法的块(block)的长度固定为16字节。假设一个字符串在AES加密前的长度为cleanLen,加密后的长度为cipherLen,则二者有下面的关系,其中的“/”是整除。
cipherLen = (clearLen/16 + 1) * 16
clearLen | cipherLen |
---|---|
47 | 48 |
48 | 64 |
49 | 64 |
使用Openssl的AES加密算法的更多相关文章
- [转]使用Openssl的AES加密算法
转自:http://www.thinkemb.com/wordpress/?p=18 参考:http://blog.csdn.net/shuanyancao/article/details/89859 ...
- openssl之aes加密(源码分析 AES_encrypt 与 AES_cbc_encrypt ,加密模式)
首先要了解AES加密是什么,以及几种加密模式的区别.之后才是编程.具体的编程案例,在下面的链接. openssl之aes加密(AES_cbc_encrypt 与 AES_encrypt 的编程案例) ...
- php RSA和AES加密算法
一.RSA加密 RSA只说PHP中的应用,详细的算法原理解释,请自行百度,或者参考(RSA加密算法-详细解释以及公钥加密为什么每次都不一样) 总结:公钥加密.私钥解密.私钥签名.公钥验签. 注意: 1 ...
- AES加密算法C++实现
我从网上下载了一套AES加密算法的C++实现,代码如下: (1)aes.h #ifndef SRC_UTILS_AES_H #define SRC_UTILS_AES_H class AES { pu ...
- PHP android ios相互兼容的AES加密算法
APP项目用户密码传输一直没有用HTTPS,考虑到用户的隐私暂时先用AES对密码加密,以后也可以用于手机端与服务端加密交互. PHP的免费版phpAES项目,手机端解码各种不对. 好不容易找了PHP ...
- Qt使用AES加密算法对字符串进行加密
因工作需要,需要对字符串进行加密处理,在网上找了很长时间,终于找到了一个可以使用的aes加密算法.其源代码采用c++编写而成,但其头文件引用windows.h,经过修改部分代码,将#inc ...
- Android AES加密算法及事实上现
昨天老大叫我看看android加密算法.于是网上找了找,找到了AES加密算法.(当然还有MD5,BASE64什么的http://snowolf.iteye.com/blog/379860这篇文章列举了 ...
- iOS,Android,.NET通用AES加密算法
原文:iOS,Android,.NET通用AES加密算法 这两天为移动App开发API,结果实现加密验证时碰到一大坑.这里不得不吐槽下又臭又硬的iOS,Windows Server无法解密出正确的结果 ...
- Android AES加密算法,现在实际上
昨天,老板让我来看看android加密算法.于是在网上找了找,发现AES加密算法.(当然,MD5,BASE64什么http://snowolf.iteye.com/blog/379860这篇文章列举了 ...
随机推荐
- 《python源代码剖析》笔记 python中的List对象
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 1.PyListObject对象 --> 变长可变对象,可看作vector<Py ...
- advertisingIdentifier
iOS 7后Mac 地址就不能用了. 不过可以用advertisingIdentifier来取,再多个project 里测试是唯一的,但如果遇到系统升级或是重刷这个就不一定能唯一了.. 这里还要加一个 ...
- asp.net正则表达式
导入引用命名空间:using System.Text.RegularExpressions //Regex类,常用方法: //摘要:1.IsMatch(String);2.IsMatch(String ...
- Hbase master启动报错:Failed construction of Master: class org.apache.hadoop.hbase.master.HMaster Caused by: java.net.UnknownHostException:
Hbase master启动报错: java.lang.RuntimeException: Failed construction of Master: class org.apache.hadoop ...
- 使用Newtonsoft进行JSON序列化时将枚举序列化为字符串的方法
一.实体书写 将枚举类型的属性前面加上[JsonConverter(typeof(StringEnumConverter))]即可. 二.举例 [JsonConverter(typeof(String ...
- hadoop mahout 算法和API说明
org.apache.mahout.cf.taste.hadoop.item.RecommenderJob.main(args) --input 偏好数据路径,文本文件.格式 userid\t ite ...
- Echart 仪表盘和柱形图
我们来分布讲解: 1.首先编一写一个html,如下: <html> <body class=""> <div class="containe ...
- ES5学习笔记
转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/7234053.html 一:基础 1:语法 ECMAScript 中的变量无特定的类型,定义变量时只用 var ...
- CDB和PDB的创建、连接、启动、关闭
一.CDB和PDB基本管理 基本概念: Multitenant Environment:多租户环境 CDB(Container Database):数据库容器 PD(Pluggable Databas ...
- Microsoft Excel as a Source and Target as Oracle in ODI
创建测试表格和目标表 导出scott用户的emp表为EMP.xlsx作为测试的元数据,结果如下 打开EMP.xlsx 公式→定义名称 创建目标表(来自scott.sql) CREATE TABLE E ...