今天遇到这样一个问题,将客户端中的一个密码存储到文件中以供下次使用,但是存储的密码不能直接存储明文,需要进行加密处理,再三考虑之后,这个加密的过程需要双向的可逆的过程,MD5等方式是不适用的,因为记住密码意味着下次我还需要还原这个密码进行使用,所以最后选择了openssl的aes算法,然而aes可行然而用遇到另外一个问题,aes编码字符串之后是乱码,只能用16进制数来显示,这样我使用的glib的keyfile parser配置文件接口又读不起来乱码,所有中间又加了一层,base64编解码,大概流程如下:
密码字符串->openssl aes编码->base64编码->存文件----------读文件->base64解码->openssl aes解码->得到原始字符串
下面是代码,具体的分析写在注释上:
#include
#include
#include
#include "openssl/pem.h"
#include "openssl/bio.h"
#include "openssl/evp.h"
#include "openssl/aes.h"
/*这个是你自己写的一个十六字节的秘钥,aes加密解密都用这同一个*/
unsigned char key[AES_BLOCK_SIZE] = "123456789abcdef";
#define AES_BITS 10240
#define MSG_LEN 10240
/**********************************************************
函数名:getlen
参数:char *result --字符串地址
返回值:int --字符串长度
说明: --获取字符串长度
***********************************************************/
int getlen(char *result) {
int i = 0;
while (result[i] != '\0') {
i++;
}
return i;
}
/**********************************************************
函数名:aes_encrypt
参数:const char* str_in --输入字符
参数:unsigned char* key --key
参数:unsigned char* out --输出字符
返回值:int --0失败 1成功
说明:加密
***********************************************************/
int aes_encrypt(char* str_in, char* out)
{
if (!str_in || !key || !out) return 0;
//加密的初始化向量
unsigned char iv[AES_BLOCK_SIZE];
//这个也是加密解密同一个确保十六字节里面的内容加密解密一样就ok
for (int i = 0; i < 16; ++i)
iv[i] = 0;
//通过自己的秘钥获得一个aes秘钥以供下面加密使用,128表示16字节
AES_KEY aes;
if (AES_set_encrypt_key((unsigned char*)key, 128, &aes) < 0)
{
return 0;
}
int len = getlen(str_in);
//这边是加密接口,使用之前获得的aes秘钥
AES_cbc_encrypt((unsigned char*)str_in, (unsigned char*)out, len, &aes, iv, AES_ENCRYPT);
return 1;
}
/**********************************************************
函数名:aes_decrypt
参数:const char* str_in --输入
参数:unsigned char* key --key
参数:unsigned char* out --输出
返回值:int --0失败 1成功
说明: --解密
***********************************************************/
int aes_decrypt(char* str_in, char* out)
{
if (!str_in || !key || !out)
return 0;
unsigned char iv[AES_BLOCK_SIZE];
//这个也是加密解密同一个确保十六字节里面的内容加密解密一样就ok
for (int i = 0; i < 16; ++i)
iv[i] = 0;
//通过自己的秘钥获得一个aes秘钥以供下面解密使用,128表示16字节
AES_KEY aes;
if (AES_set_decrypt_key((unsigned char*)key, 128, &aes) < 0)
{
return 0;
}
int len = getlen(str_in);
//这边是解密接口,使用之前获得的aes秘钥
AES_cbc_encrypt((unsigned char*)str_in, (unsigned char*)out, len, &aes, iv, AES_DECRYPT);
return 1;
}
//base64加密
int base64_encode(char *in_str, int in_len, char *out_str)
{
BIO *b64, *bio;
BUF_MEM *bptr = NULL;
size_t size = 0;
if (in_str == NULL || out_str == NULL)
return -1;
b64 = BIO_new(BIO_f_base64());
bio = BIO_new(BIO_s_mem());
bio = BIO_push(b64, bio);
BIO_write(bio, in_str, in_len);
BIO_flush(bio);
BIO_get_mem_ptr(bio, &bptr);
memcpy(out_str, bptr->data, bptr->length);
out_str[bptr->length] = '\0';
size = bptr->length;
BIO_free_all(bio);
return size;
}
//base64解密
int base64_decode(char *in_str, int in_len, char *out_str)
{
BIO *b64, *bio;
BUF_MEM *bptr = NULL;
int counts;
int size = 0;
if (in_str == NULL || out_str == NULL)
return -1;
b64 = BIO_new(BIO_f_base64());
BIO_set_flags(b64, BIO_FLAGS_BASE64_NO_NL);
bio = BIO_new_mem_buf(in_str, in_len);
bio = BIO_push(b64, bio);
size = BIO_read(bio, out_str, in_len);
out_str[size] = '\0';
BIO_free_all(bio);
return size;
}
int main(int argc, char *argv[])
{
if (argc < 2)
{
printf("please input origin str\n");
return 0;
} else
{
printf("origin-str:%s\n", argv[1]);
}
//aes加密
char aes_encode_out[30] = {0};
aes_encrypt(argv[1], aes_encode_out);
printf("aes_encode_out:%s\n", aes_encode_out);
//base64加密
char base64_encode_out[1024] = {0};
base64_encode(aes_encode_out, strlen(aes_encode_out), base64_encode_out);
printf("base64_encode_out:%s\n", base64_encode_out);
//base64解密
char base64_decode_out[1024] = {0};
base64_decode(base64_encode_out, strlen(base64_encode_out), base64_decode_out);
printf("base64_decode_out:%s\n", base64_decode_out);
//aes解密
char aes_decode_out[30] = {0};
aes_decrypt(base64_decode_out, aes_decode_out);
printf("aes_decode_out:%s\n", aes_decode_out);
return 0;
}
编译运行过程: