今天遇到這樣一個問題,將客戶端中的一個密碼存儲到文件中以供下次使用,但是存儲的密碼不能直接存儲明文,需要進行加密處理,再三考慮之後,這個加密的過程需要雙向的可逆的過程,MD5等方式是不適用的,因爲記住密碼意味着下次我還需要還原這個密碼進行使用,所以最後選擇了openssl的aes算法,然而aes可行然而用遇到另外一個問題,aes編碼字符串之後是亂碼,只能用16進制數來顯示,這樣我使用的glib的keyfile parser配置文件接口又讀不起來亂碼,所有中間又加了一層,base64編解碼,大概流程如下:
密碼字符串->openssl aes編碼->base64編碼->存文件----------讀文件->base64解碼->openssl aes解碼->得到原始字符串
下面是代碼,具體的分析寫在註釋上:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#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] = 32 + i;
//通過自己的祕鑰獲得一個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] = 32 + i;
//通過自己的祕鑰獲得一個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;
}
編譯運行過程: