C語(yǔ)言使用openSSL庫(kù)AES模塊實(shí)現(xiàn)加密功能詳解
本文實(shí)例講述了C語(yǔ)言使用openSSL庫(kù)AES模塊實(shí)現(xiàn)加密功能。分享給大家供大家參考,具體如下:
概述
在密碼學(xué)里面一共有3中分類:
1.對(duì)稱加密/解密
對(duì)稱加密比較常見的有DES/AES。加密方和解密方都持有相同的密鑰。對(duì)稱的意思就是加密和解密都是用相同的密鑰。
2.非對(duì)稱加密/解密
常見的加密算法DSA/RSA。如果做過Google Pay的話,應(yīng)該不會(huì)陌生。非對(duì)稱意味著加密和解密使用的密鑰不是相同的。這種應(yīng)用的場(chǎng)合是需要保持發(fā)起方的權(quán)威性,比如Google中一次支付行為,只能Google通過私鑰來加密產(chǎn)出來,但是大家都能通過公鑰來認(rèn)證這個(gè)是真的。打個(gè)更加淺顯的比方:私鑰可以理解成美聯(lián)儲(chǔ)的印鈔機(jī),公鑰可以理解成在民間無數(shù)的美元驗(yàn)鈔機(jī)。
還有一個(gè)場(chǎng)合也是https使用證書方式登錄的時(shí)候,也是使用的雙向的非對(duì)稱加密模式來做的。
3.離散
這種只能被稱為驗(yàn)簽,而不是加密。因?yàn)檫@類算法只能一個(gè)方向(將輸入數(shù)據(jù)離散到某個(gè)特定的數(shù)字,反向解密是無法做到的。)。最常見的算法就是MD5。在寫php的時(shí)候大量的使用這種驗(yàn)簽來做認(rèn)證。他可以將字符串離散成32byte的16進(jìn)制的數(shù)字。
本次使用AES CBC方式來加密。CBC模式加密是SSL的通訊標(biāo)準(zhǔn),所以在做游戲的時(shí)候經(jīng)常會(huì)使用到。openSSL的基本用法可以參考這個(gè)
兩個(gè)細(xì)節(jié)
這種加密的需要了解下面兩個(gè)細(xì)節(jié):
1.加密的內(nèi)存塊一般按照16字節(jié)(這個(gè)也可以調(diào)整)對(duì)齊;當(dāng)原始內(nèi)存塊沒有對(duì)齊字節(jié)數(shù)的時(shí)候,需要填充;
2.加密解密不會(huì)引發(fā)內(nèi)存的膨脹或者縮?。?/p>
最近在使用Python,Java,c#都去看過AES的接口,最輕松的是c#,java。當(dāng)使用C來寫,才能明顯感受到在這些操作過程中,有多少次內(nèi)存的分配,多少的內(nèi)存拼接。啥事都有成本,封裝良好的語(yǔ)言損失掉的效率可能來自于這些便利。
準(zhǔn)備知識(shí)
函數(shù)接口
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); // 設(shè)置加密key AES_KEY aes; AES_set_encrypt_key(key,128,&aes);// 這里填寫的128是bit位,128bit=(128/8)bytes=16bytes,這個(gè)換算和32bit對(duì)應(yīng)int為內(nèi)存指針的原理一樣。 // 初始化自己的key char key[16]; // 加密函數(shù) 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 // 定義一個(gè)加密的初始化向量 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);
字串轉(zhuǎn)換
// 16進(jìn)制的字串轉(zhuǎn)換成16byte存儲(chǔ)起來 // 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");
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; } }
完整的代碼
c語(yǔ)言代碼
// main.c #include <aes.h> #include <stdio.h> #include <string.h> #include <assert.h> #include <stdlib.h> unsigned char* str2hex(char *str) { 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) { 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); 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腳本:
# SConstruct import glob env = Environment() env["CPPPATH"] = [ '/usr/include/openssl' ] env['LIBPATH'] = [ '/home/abel/lib/openssl-1.0.2f' ] env['CPPDEFINES'] = ['LINUX', '_DEBUG' ] env['CCFLAGS'] = '-g -std=gnu99' env['LIBS'] = [ 'm', 'crypto', 'dl' ] env.Program( target = "./test_aes", source = ( glob.glob( './*.c' ) ) )
輸出結(jié)果:
:!./test_aes ------------------raw_buf 6C 69 66 65 27 73 20 61 20 73 74 72 75 67 67 6C 65 ------------------after_padding_buf 6C 69 66 65 27 73 20 61 20 73 74 72 75 67 67 6C 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ------------------encrypt_buf DB 63 28 C5 2C 6A 3F 1B FD 4B C5 47 94 4E 24 9D D2 15 4C F2 6B 3B 1D C0 E7 D2 7B D6 1E 78 60 EA ------------------decrypt_buf 6C 69 66 65 27 73 20 61 20 73 74 72 75 67 67 6C 65 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
總結(jié)
代碼中還是有很多地方都是直接malloc內(nèi)存出來,這些點(diǎn)都能扣得更加細(xì)。在每次加密調(diào)用的時(shí)候IV內(nèi)存將會(huì)改變。
PS:關(guān)于加密解密感興趣的朋友還可以參考本站在線工具:
文字在線加密解密工具(包含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
希望本文所述對(duì)大家C語(yǔ)言程序設(shè)計(jì)有所幫助。
相關(guān)文章
詳解C語(yǔ)言求兩個(gè)數(shù)的最大公約數(shù)及最小公倍數(shù)的方法
這篇文章主要介紹了C語(yǔ)言求兩個(gè)數(shù)的最大公約數(shù)及最小公倍數(shù)的方法,輾轉(zhuǎn)相除法和輾轉(zhuǎn)相減法在解決這種問題時(shí)最常用到,需要的朋友可以參考下2016-03-03C語(yǔ)言實(shí)現(xiàn)注冊(cè)登錄系統(tǒng)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言實(shí)現(xiàn)注冊(cè)登錄系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-12-12C++實(shí)現(xiàn)LeetCode(100.判斷相同樹)
這篇文章主要介紹了C++實(shí)現(xiàn)LeetCode(100.判斷相同樹),本篇文章通過簡(jiǎn)要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下2021-07-07C語(yǔ)言學(xué)生成績(jī)管理系統(tǒng)小設(shè)計(jì)
這篇文章主要為大家詳細(xì)介紹了C語(yǔ)言學(xué)生成績(jī)管理系統(tǒng)小設(shè)計(jì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01關(guān)于C++友元函數(shù)的實(shí)現(xiàn)講解
今天小編就為大家分享一篇關(guān)于關(guān)于C++友元函數(shù)的實(shí)現(xiàn)講解,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧2018-12-12