c語言通過openssl aes對稱加解密和base64編解碼將密碼儲存成密文
阿新 • • 發佈:2018-12-02
今天遇到這樣一個問題,將客戶端中的一個密碼儲存到檔案中以供下次使用,但是儲存的密碼不能直接儲存明文,需要進行加密處理,再三考慮之後,這個加密的過程需要雙向的可逆的過程,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; }
編譯執行過程: