用開源加密庫Libgcrypt實現AES加密

2021-09-20 06:08:10 字數 3791 閱讀 7884

libgcrypt是著名的開源加密軟體gnupg的底層庫,是乙個非常成熟的加密演算法庫,支援多種對稱和非對稱加密演算法。現在自己隨便造輪子地寫乙個加密演算法程式顯然是非常不安全的,雖然openssl出現了heartbleed漏洞,但是用已經成熟的加密演算法庫還是會比不成熟的東西好很多的。最近看了看它最基本的一些功能,嘗試寫了乙個aes的demo,中間還是學到蠻多東西的,所以寫這篇手記。本文是以我寫的乙個gcrypt_demo為例,也可以當作這個demo的解釋。

寫個加密程式的第一步是開始加密,第二步是解密?你太天真了!第一步實際上是傳入金鑰。libgcrypt的對稱加密需要兩個重要的引數,乙個是金鑰key,乙個是初始化向量initialization vector。後者一般由加密程式決定,而前者則需要使用者來提供。如果我們直接拿使用者輸入的明文作為加密和解密的金鑰,實在太不安全了,必須要經過乙個搞亂的過程。而libgcrypt提供的用來搞亂金鑰的函式是gcry_kdf_derive。

gpg_error_t gcry_kdf_derive ( const void *passphrase, size_t passphraselen, int algo, int subalgo, const void *salt, size_t saltlen, unsigned long iterations, size_t keysize, void *keybuffer )
別看它很長很複雜,其實引數只有四部分:1.傳入的金鑰明文和長度;2.打亂用的演算法;3.鹽串和鹽串的長度、迭代次數等打亂用的引數;4.生成的打亂後的金鑰串。利用這個函式就能得到乙個很好的金鑰串了。舉個例子,我把明文金鑰放在buf裡面,而輸出的金鑰放在buf裡面,選用pbkdf2和sha512演算法進行雜湊,鹽串存在salt裡面,迭代次數為iter。

gpg_error_t err = gcry_kdf_derive(buf, strlen(buf), gcry_kdf_pbkdf2, gcry_md_sha512,salt, sizeof(salt), iter, len_of_retkey, outbuf);
基本上所有libgcrypt的函式返回值都是錯誤控制代碼,接收它用來判錯就好。

在獲得金鑰之後,我們就需要對加密的控制代碼進行設定。我們需要選定加密演算法,順便開好用來加密的快取區間。我們採用比較簡單的塊模式進行加密,所以首先我們需要知道我們選定的加密演算法所接受的金鑰長度和塊長度。在libgcrypt中,加密演算法用巨集來標識,你需要傳遞指定的巨集,來告知它你想用哪種加密演算法。我的demo程式用的是aes256演算法,但是為了通用起見,我們還是用乙個cipher_algo來指代我們用的加密演算法的具體名字。

首先我們需要得到基本的資料:

size_t key_size = gcry_cipher_get_algo_keylen(cipher_algo);

size_t block_size = gcry_cipher_get_algo_blklen(cipher_algo);

size_t block_required=file_size/block_size;

if (file_size % block_size != 0)

file_size是要被加密的資料檔案的總大小。利用get_algo_keylen()和get_algo_blklen()兩個函式我們可以得到選定的演算法的金鑰長度和塊長度,然後計算總共有多少個塊。

有了這些資訊,我們就可以建乙個控制代碼:

cipher_err=gcry_cipher_open(&cipher_hd, cipher_algo, gcry_cipher_mode_cbc, gcry_cipher_cbc_cts);

cipher_err=gcry_cipher_setkey(cipher_hd,key,key_size);

cipher_err=gcry_cipher_setiv(cipher_hd, iv, block_size);

第一句建立加密控制代碼。第乙個引數cipher_hd是加密用的控制代碼,型別是gcry_cipher_hd_t;第二個引數是加密演算法,第三個引數和第四個引數指定加密的模式是塊模式,詳細的內容可以看libgcrypt的文件。第二句設定金鑰,第三句設定初始化向量。這裡接收的初始化向量是隨便的乙個字串,只要足夠長,超過block_size一般就沒什麼問題了,當然,能和block_size一樣長就最好好。最後建立好讀入快取和輸出快取區就好。

char *input_buf = (char*)malloc(file_size);

char *cipher_buffer = malloc(block_size*block_required);

memset(cipher_buffer, 0, block_size*block_required);

做了這麼多準備工作,終於開始加密了呢!假設fin是源資料流,而fout是輸出流,都是檔案,那麼我們可以這樣寫加密的程式:

fread(input_buf,1,file_size,fin);

//將資料讀入輸入快取

memcpy(cipher_buffer,input_buf,block_required*block_size);

//將資料複製到輸出快取中

cipher_err=gcry_cipher_encrypt(cipher_hd,cipher_buffer,

//在輸出快取上進行加密

block_required*block_size,null,0);

fwrite(cipher_buffer,1,block_required*block_size,fout);

//講輸出快取輸出到檔案

gcry_cipher_close(cipher_hd);

fclose(fin);

fclose(fout);

//關閉加密控制代碼和檔案流

要注意的是加密用的函式gcry_cipher_encrypt():

gcry_error_t gcry_cipher_encrypt (gcry_cipher_hd_t h, unsigned char *out, size_t outsize, const unsigned char *in, size_t inlen)
它接收的引數分為輸出快取和源資料。但是當源資料的指標為null時,它會直接以輸出快取中的資料為源資料,加密後放回去。加密到此結束,戛然而止。準備工作佔了大頭,真正的最核心的工作其實就這麼一點。

對稱加密完自然要解密,不然就沒有意義了。解密的初始化工作和加密基本一致,只要用相同的金鑰和初始化向量,就可以解密了。只要用gcry_cipher_decrypt()替代加密用的函式就可以了。我這裡簡單化處理了,如果最後全是0,那麼就擷取尾端。其實這麼做是有問題的,應該加乙個魔數標誌結束啥的,不過demo嘛,就偷懶一下吧。加密純文字檔案的時候也沒有這個問題。

fread(decry_buf,1,file_size,fin);

cipher_err=gcry_cipher_decrypt(cipher_hd,decry_buf,file_size,null,0);

while (decry_buf[file_size-1]==0)

fwrite(decry_buf,1,file_size,fout);

gcry_cipher_close(cipher_hd);

fclose(fin);

fclose(fout);

利用aes對稱加密可以建造乙個最基本的安全的資料交換體系。到目前為止,aes256演算法還沒有有效的破解手段,應該說還是很安全的。這個demo很簡陋,有很多問題,不過作為demo已經足夠了。不造輪子,而是使用成熟的庫,應該算是優秀工程師的基本素養吧。最後希望大家喜歡(*^^)v

用開源加密庫Libgcrypt實現AES加密

libgcrypt是著名的開源加密軟體gnupg的底層庫,是乙個非常成熟的加密演算法庫,支援多種對稱和非對稱加密演算法。現在自己隨便造輪子地寫乙個加密演算法程式顯然是非常不安全的,雖然openssl出現了heartbleed漏洞,但是用已經成熟的加密演算法庫還是會比不成熟的東西好很多的。最近看了看它...

用開源加密庫Libgcrypt實現AES加密

libgcrypt是著名的開源加密軟體gnupg的底層庫,是乙個非常成熟的加密演算法庫,支援多種對稱和非對稱加密演算法。現在自己隨便造輪子地寫乙個加密演算法程式顯然是非常不安全的,雖然openssl出現了heartbleed漏洞,但是用已經成熟的加密演算法庫還是會比不成熟的東西好很多的。最近看了看它...

蘋果開源三個加密庫

蘋果宣布開源其作業系統的安全子系統中三個主要元件,其中乙個庫使用的具有限制性約束的許可證引發了爭議,此次宣告也對該爭議作出相應解釋。三個被開源的元件是 common crypto 乙個為常見加密操作 如對稱加密 基於雜湊的訊息身份認證 摘要加密等 提供支援的庫,為ios和os x提供加密服務。安全框...