C语言使用openssl库进行加密
2017-11-24 19:22
459 查看
概述
在密码学里面一共有3中分类:
1.对称加密/解密
对称加密比较常见的有DES/AES。加密方和解密方都持有相同的密钥。对称的意思就是加密和解密都是用相同的密钥。
2.非对称加密/解密
常见的加密算法DSA/RSA。如果做过Google Pay的话,应该不会陌生。非对称意味着加密和解密使用的密钥不是相同的。这种应用的场合是需要保持发起方的权威性,比如Google中一次支付行为,只能Google通过私钥来加密产出来,但是大家都能通过公钥来认证这个是真的。打个更加浅显的比方:私钥可以理解成美联储的印钞机,公钥可以理解成在民间无数的美元验钞机。
还有一个场合也是https使用证书方式登录的时候,也是使用的双向的非对称加密模式来做的。
3.离散
这种只能被称为验签,而不是加密。因为这类算法只能一个方向(将输入数据离散到某个特定的数字,反向解密是无法做到的。)。最常见的算法就是MD5。在写php的时候大量的使用这种验签来做认证。他可以将字符串离散成32byte的16进制的数字。
使用MD5加密
我们以一个字符串为例,新建一个文件filename.txt,在文件内写入hello ,然后在Linux下可以使用命令md5sum filename.txt计算md5值 ==> b1946ac92492d2347c6235b4d2611184 。虽然写入的是hello这5个字符,但是我们使用命令xxd filename.txt后可以看出文件结尾处会有个0x0a这个回车符。所以在下面的代码中才会有\n。
新建一个cpp文件用于计算MD5值
编译选项为: g++ MD5test.cpp -lssl -o MD5test
运行后的结果为: B1946AC92492D2347C6235B4D2611184
注意这里用到openssl库,可以运行 yum install openssl 和 yum install openssl-devel 进行安装。
下面这个代码是对文件进行MD5计算。
运行得到结果后,我们可以使用md5sum命令进行验证。
使用SHA1加密
openssl里几个函数讲解
我们对上面的程序进行修改
MD5有128bit(16个char)*SHA1有160bit(20个char)*SHA256有256bit(32个char)*SHA244有244bit(28个char)*SHA512有512bit(64个char).所以要注意修改大小
使用AES CBC加密
CBC模式加密是SSL的通讯标准,所以在做游戏的时候经常会使用到。
这种加密的需要了解下面两个细节:
1.加密的内存块一般按照16字节(这个也可以调整)对齐;当原始内存块没有对齐字节数的时候,需要填充;
2.加密解密不会引发内存的膨胀或者缩小;
java,c#之类的语言可以很轻松的使用AES的接口。当使用C来写,才能明显感受到在这些操作过程中,有多少次内存的分配,多少的内存拼接。啥事都有成本,封装良好的语言损失掉的效率可能来自于这些便利。
编译scons脚本:
?
输出结果:
?
注释1:字串转换函数
注释2:padding算法
注释3:函数接口
附录:
文字在线加密解密工具(包含AES、DES、RC4等):
http://tools.jb51.net/password/txt_encode
MD5在线加密工具:
http://tools.jb51.net/password/CreateMD5Password
在线散列/哈希算法加密工具:
http://tools.jb51.net/password/hash_encrypt
在线MD5/hash/SHA-1/SHA-2/SHA-256/SHA-512/SHA-3/RIPEMD-160加密工具:
http://tools.jb51.net/password/hash_md5_sha
在线sha1/sha224/sha256/sha384/sha512加密工具:
http://tools.jb51.net/password/sha_encode
在密码学里面一共有3中分类:
1.对称加密/解密
对称加密比较常见的有DES/AES。加密方和解密方都持有相同的密钥。对称的意思就是加密和解密都是用相同的密钥。
2.非对称加密/解密
常见的加密算法DSA/RSA。如果做过Google Pay的话,应该不会陌生。非对称意味着加密和解密使用的密钥不是相同的。这种应用的场合是需要保持发起方的权威性,比如Google中一次支付行为,只能Google通过私钥来加密产出来,但是大家都能通过公钥来认证这个是真的。打个更加浅显的比方:私钥可以理解成美联储的印钞机,公钥可以理解成在民间无数的美元验钞机。
还有一个场合也是https使用证书方式登录的时候,也是使用的双向的非对称加密模式来做的。
3.离散
这种只能被称为验签,而不是加密。因为这类算法只能一个方向(将输入数据离散到某个特定的数字,反向解密是无法做到的。)。最常见的算法就是MD5。在写php的时候大量的使用这种验签来做认证。他可以将字符串离散成32byte的16进制的数字。
使用MD5加密
我们以一个字符串为例,新建一个文件filename.txt,在文件内写入hello ,然后在Linux下可以使用命令md5sum filename.txt计算md5值 ==> b1946ac92492d2347c6235b4d2611184 。虽然写入的是hello这5个字符,但是我们使用命令xxd filename.txt后可以看出文件结尾处会有个0x0a这个回车符。所以在下面的代码中才会有\n。
1 //打开/usr/include/openssl/md5.h这个文件我们可以看到一些函数 2 // 初始化 MD5 Contex, 成功返回1,失败返回0 3 int MD5_Init(MD5_CTX *c); 4 // 循环调用此函数,可以将不同的数据加在一起计算MD5,成功返回1,失败返回0 5 int MD5_Update(MD5_CTX *c, const void *data, size_t len); 6 // 输出MD5结果数据,成功返回1,失败返回0 7 int MD5_Final(unsigned char *md, MD5_CTX *c); 8 // MD5_Init,MD5_Update,MD5_Final三个函数的组合,直接计算出MD5的值 9 unsigned char *MD5(const unsigned char *d, size_t n, unsigned char *md); 10 // 内部函数,不需要调用 11 void MD5_Transform(MD5_CTX *c, const unsigned char *b);
新建一个cpp文件用于计算MD5值
1 #include <openssl/md5.h> 2 #include <string.h> 3 #include <stdio.h> 4 5 int main() 6 { 7 MD5_CTX ctx; 8 unsigned char outmd[16]; 9 int i=0; 10 11 memset(outmd,0,sizeof(outmd)); 12 MD5_Init(&ctx); 13 MD5_Update(&ctx,"hel",3); 14 MD5_Update(&ctx,"lo\n",3); 15 MD5_Final(outmd,&ctx); 16 for(i=0;i<16;i<i++) 17 { 18 printf("%02X",outmd[i]); 19 } 20 printf("\n"); 21 return 0; 22 }
编译选项为: g++ MD5test.cpp -lssl -o MD5test
运行后的结果为: B1946AC92492D2347C6235B4D2611184
注意这里用到openssl库,可以运行 yum install openssl 和 yum install openssl-devel 进行安装。
下面这个代码是对文件进行MD5计算。
1 #include <openssl/md5.h> 2 #include <string.h> 3 #include <stdio.h> 4 5 int main() 6 { 7 MD5_CTX ctx; 8 unsigned char outmd[16]; 9 char buffer[1024]; 10 char filename[32]; 11 int len=0; 12 int i; 13 FILE * fp=NULL; 14 memset(outmd,0,sizeof(outmd)); 15 memset(filename,0,sizeof(filename)); 16 memset(buffer,0,sizeof(buffer)); 17 printf("请输入文件名,用于计算MD5值:"); 18 scanf("%s",filename); 19 fp=fopen(filename,"rb"); 20 if(fp==NULL) 21 { 22 printf("Can't open file\n"); 23 return 0; 24 } 25 26 MD5_Init(&ctx); 27 while((len=fread(buffer,1,1024,fp))>0) 28 { 29 MD5_Update(&ctx,buffer,len); 30 memset(buffer,0,sizeof(buffer)); 31 } 32 MD5_Final(outmd,&ctx); 33 34 for(i=0;i<16;i<i++) 35 { 36 printf("%02X",outmd[i]); 37 } 38 printf("\n"); 39 return 0; 40 }
运行得到结果后,我们可以使用md5sum命令进行验证。
使用SHA1加密
openssl里几个函数讲解
1 //SHA1算法是对MD5算法的升级,计算结果为20字节(160位),使用方法如下: 2 //打开/usr/include/openssl/sha.h这个文件我们可以看到一些函数 3 // 初始化 SHA Contex, 成功返回1,失败返回0 4 int SHA_Init(SHA_CTX *c); 5 // 循环调用此函数,可以将不同的数据加在一起计算SHA1,成功返回1,失败返回0 6 int SHA_Update(SHA_CTX *c, const void *data, size_t len); 7 // 输出SHA1结果数据,成功返回1,失败返回0 8 int SHA_Final(unsigned char *md, SHA_CTX *c); 9 // SHA_Init,SHA_Update,SHA_Final三个函数的组合,直接计算出SHA1的值 10 unsigned char *SHA(const unsigned char *d, size_t n, unsigned char *md); 11 // 内部函数,不需要调用 12 void SHA_Transform(SHA_CTX *c, const unsigned char *data); 13 14 //上面的SHA可以改为SHA1,SHA224,SHA256,SHA384,SHA512就可以实现多种加密了
我们对上面的程序进行修改
1 #include <openssl/sha.h> 2 #include <string.h> 3 #include <stdio.h> 4 5 int main() 6 { 7 SHA_CTX stx; 8 unsigned char outmd[20];//注意这里的字符个数为20 9 char buffer[1024]; 10 char filename[32]; 11 int len=0; 12 int i; 13 FILE * fp=NULL; 14 memset(outmd,0,sizeof(outmd)); 15 memset(filename,0,sizeof(filename)); 16 memset(buffer,0,sizeof(buffer)); 17 printf("请输入文件名,用于计算SHA1值:"); 18 scanf("%s",filename); 19 fp=fopen(filename,"rb"); 20 if(fp==NULL) 21 { 22 printf("Can't open file\n"); 23 return 0; 24 } 25 26 SHA1_Init(&stx); 27 while((len=fread(buffer,1,1024,fp))>0) 28 { 29 SHA1_Update(&stx,buffer,len); 30 memset(buffer,0,sizeof(buffer)); 31 } 32 SHA1_Final(outmd,&stx); 33 34 for(i=0;i<20;i<i++) 35 { 36 printf("%02X",outmd[i]); 37 } 38 printf("\n"); 39 return 0; 40 }
MD5有128bit(16个char)*SHA1有160bit(20个char)*SHA256有256bit(32个char)*SHA244有244bit(28个char)*SHA512有512bit(64个char).所以要注意修改大小
使用AES CBC加密
CBC模式加密是SSL的通讯标准,所以在做游戏的时候经常会使用到。
这种加密的需要了解下面两个细节:
1.加密的内存块一般按照16字节(这个也可以调整)对齐;当原始内存块没有对齐字节数的时候,需要填充;
2.加密解密不会引发内存的膨胀或者缩小;
java,c#之类的语言可以很轻松的使用AES的接口。当使用C来写,才能明显感受到在这些操作过程中,有多少次内存的分配,多少的内存拼接。啥事都有成本,封装良好的语言损失掉的效率可能来自于这些便利。
// main.c #include <aes.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> unsigned char* str2hex(char *str) {//注释1 unsigned char *ret = NULL; int str_len = strlen(str); int i = 0; assert((str_len%2) == 0); ret = (char *)malloc(str_len/2); for (i =0;i < str_len; i = i+2 ) { sscanf(str+i,"%2hhx",&ret[i/2]); } return ret; } char *padding_buf(char *buf,int size, int *final_size) {//注释2 char *ret = NULL; int pidding_size = AES_BLOCK_SIZE - (size % AES_BLOCK_SIZE); int i; *final_size = size + pidding_size; ret = (char *)malloc(size+pidding_size); memcpy( ret, buf, size); if (pidding_size!=0) { for (i =size;i < (size+pidding_size); i++ ) { ret[i] = 0; } } return ret; } void printf_buff(char *buff,int size) { int i = 0; for (i=0;i<size;i ++ ) { printf( "%02X ", (unsigned char)buff[i] ); if ((i+1) % 8 == 0) { printf("\n"); } } printf("\n\n\n\n"); } void encrpyt_buf(char *raw_buf, char **encrpy_buf, int len ) { AES_KEY aes; unsigned char *key = str2hex("8cc72b05705d5c46f412af8cbed55aad"); unsigned char *iv = str2hex("667b02a85c61c786def4521b060265e8"); AES_set_encrypt_key(key,128,&aes);//注释3 AES_cbc_encrypt(raw_buf,*encrpy_buf,len,&aes,iv,AES_ENCRYPT); free(key); free(iv); } void decrpyt_buf(char *raw_buf, char **encrpy_buf, int len ) { AES_KEY aes; unsigned char *key = str2hex("8cc72b05705d5c46f412af8cbed55aad"); unsigned char *iv = str2hex("667b02a85c61c786def4521b060265e8"); AES_set_decrypt_key(key,128,&aes); AES_cbc_encrypt(raw_buf,*encrpy_buf,len,&aes,iv,AES_DECRYPT); free(key); free(iv); } int main(int argn, char *argv[] ) { char *raw_buf = NULL; char *after_padding_buf = NULL; int padding_size = 0; char *encrypt_buf = NULL; char *decrypt_buf = NULL; // 1 raw_buf = (char *)malloc(17); memcpy(raw_buf,"life's a struggle",17); printf("------------------raw_buf\n"); printf_buff(raw_buf,17); // 2 after_padding_buf = padding_buf(raw_buf,17,&padding_size); printf("------------------after_padding_buf\n"); printf_buff(after_padding_buf,padding_size); // 3 encrypt_buf = (char *)malloc(padding_size); encrpyt_buf(after_padding_buf,&encrypt_buf, padding_size); printf("------------------encrypt_buf\n"); printf_buff(encrypt_buf,padding_size); // 4 decrypt_buf = (char *)malloc(padding_size); decrpyt_buf(encrypt_buf,&decrypt_buf,padding_size); printf("------------------decrypt_buf\n"); printf_buff(decrypt_buf,padding_size); free(raw_buf); free(after_padding_buf); free(encrypt_buf); free(decrypt_buf); return 0; }
编译scons脚本:
?
?
// 16进制的字串转换成16byte存储起来 // hex string to byte in c const char hexstring[] = "deadbeef10203040b00b1e50", *pos = hexstring; unsigned char val[12]; size_t count = 0; /* WARNING: no sanitization or error-checking whatsoever */ for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) { sscanf(pos, "%2hhx", &val[count]); pos += 2; } printf("0x"); for(count = 0; count < sizeof(val)/sizeof(val[0]); count++) printf("%02x", val[count]); printf("\n");
注释2:padding算法
char *raw_buf = ...; int raw_size = ...; char *final_buf = NULL; int pidding_size = AES_BLOCK_SIZE - (raw_size % AES_BLOCK_SIZE); int i; final_buf = (char *)malloc(raw_size+pidding_size); if (pidding_size!=0) { memcpy( final_buf, raw_buf, raw_size); for (i =raw_size;i < (raw_size+pidding_size); i++ ) { // zero padding算法: final_buf[i] = 0; or // PKCS5Padding算法 final_buf[i] = pading; } }
注释3:函数接口
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); // 设置加密key AES_KEY aes; AES_set_encrypt_key(key,128,&aes);// 这里填写的128是bit位,128bit=(128/8)bytes=16bytes,这个换算和32bit对应int为内存指针的原理一样。 // 初始化自己的key char key[16]; // 加密函数 void AES_cbc_encrypt(const unsigned char *in, unsigned char *out, size_t length, const AES_KEY *key, unsigned char *ivec, const int enc); # define AES_BLOCK_SIZE 16 // aes.h 71 lines # define AES_ENCRYPT 1 // aes.h 63 lines # define AES_DECRYPT 0 // aes.h 64 lines // 定义一个加密的初始化向量 unsigned char iv[AES_BLOCK_SIZE]; // 加密 AES_cbc_encrypt(raw_buf,encrypt_buf,buf_size,&aes,iv,AES_ENCRYPT); // 解密 AES_cbc_encrypt(raw_buf,encrypt_buf,buf_size,&aes,iv,AES_DECRYPT);
附录:
文字在线加密解密工具(包含AES、DES、RC4等):
http://tools.jb51.net/password/txt_encode
MD5在线加密工具:
http://tools.jb51.net/password/CreateMD5Password
在线散列/哈希算法加密工具:
http://tools.jb51.net/password/hash_encrypt
在线MD5/hash/SHA-1/SHA-2/SHA-256/SHA-512/SHA-3/RIPEMD-160加密工具:
http://tools.jb51.net/password/hash_md5_sha
在线sha1/sha224/sha256/sha384/sha512加密工具:
http://tools.jb51.net/password/sha_encode
相关文章推荐
- 使用C语言,对OpenSSL命令行加密的文件进行解密
- 使用Java Base64解密算对openssl的base64加密字符串进行解密
- 使用openssl命令进行加密解密及散列运算的命令行
- C# 中使用 OpenSSL 的公钥/私钥进行加密和解密
- Linux下C语言使用openssl库进行MD5校验
- 使用openssl库进行AES算法的加密
- C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)
- 使用证书对数据进行签名、验签、加密、解密以及openssl的常用方法
- 使用openssl进行ssl/tls加密传输会话测试
- 使用openssl进行加密解密
- 在Linux环境下使用OpenSSL对消息和文件进行加密(转载)
- 使用openssl进行RSA加密解密
- 使用Python的OpenSSL库来进行RSA加密
- 在Linux环境下使用OpenSSL对消息和文件进行加密
- 在iOS中使用OpenSSL的Public Key 进行加密
- Android使用NDK调用C语言写的SO进行加密
- PHP 使用openssl 进行加密 解密
- Android 使用OpenSSL进行3DES加密 c与java互通
- C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)
- C/C++使用openssl进行摘要和加密解密(md5, sha256, des, rsa)