天天看點

密碼學系列之:Argon2加密算法詳解

簡介

argon2是一個密鑰推導函數,在2015年7月被選為密碼哈希大賽的冠軍,它由盧森堡大學的alex biryukov、daniel dinu和dmitry khovratovich設計,argon2的實作通常是以creative commons cc0許可(即公共領域)或apache license 2.0釋出,并提供了三個相關版本,分别是argon2d,argon2i和argon2id。

本文将會讨論一下argon2的原理和使用。

密鑰推導函數key derivation function

在密碼學中,密鑰推導函數(kdf)是一種密碼學哈希函數,它使用僞随機函數從一個秘密值(如主密鑰、密碼或密碼)中推導出一個或多個密鑰。 kdf可用于将密鑰拉伸成更長的密鑰,或獲得所需格式的密鑰,例如将diffie-hellman密鑰交換的結果轉換為用于aes的對稱密鑰。

password hashing competition

密碼學雖然是研究密碼的,但是其加密算法是越公開越好,隻有公開才能去檢視該算法的好壞,隻有經過大家的徹底研究,才能夠讓該算法得以在業界使用和傳播。

最出名的密碼算法大賽肯定是由nist在2001年為了指定标準的aes算法舉辦的大賽,該大賽的目的尋找最新的加密算法來替代老的des算法。在這次大賽中,湧現了許多優秀的算法,包括cast-256, crypton, deal, dfc, e2, frog, hpc, loki97, magenta, mars, rc6, rijndael, safer+, serpent, 和 twofish等。最終rijndael算法被選為最終的aes算法實作。

同樣的phc也是一個這樣的算法比賽,和nist舉辦的算法比賽不同的是,這是一個非官方的,由密碼學家們組織的比賽。它是在由jean-philippe aumasson于2012年秋季發起。

2013年第一季度,釋出了征集意見書的通知,到2014年3月31日截止日期,共收到24份意見書。2014年12月,确定了9個入圍名單。2015年7月,宣布argon2為優勝者。

argon2算法

argon2 的設計很簡單,旨在實作最高的記憶體填充率和對多個計算單元的有效利用,同時還能提供對 tradeoff attacks 的防禦(通過利用處理器的緩存和記憶體)。

argon2有三個變種。argon2i、argon2d和argon2id。argon2d速度更快,并且使用資料依賴的記憶體通路方式,這使得它對gpu破解攻擊有很強的抵抗力,适合沒有side-channel timing attacks威脅的應用(例如加密貨币)。

argon2i則使用資料無關的記憶體通路,這對于密碼哈希和基于密碼的密鑰推導算法來說是首選,其特點是速度較慢,因為它在記憶體上運作了更多的處理邏輯,以防止 tradeoff attacks 。

argon2id是argon2i和argon2d的混合體,采用資料依賴型和資料獨立型記憶體通路相結合的方式,進而可以同時抵禦side-channel timing attacks和gpu破解攻擊的能力。

argon2有兩類輸入參數,分别是primary inputs和secondary inputs。

primary inputs包括要加密的消息p和nonce s,分别代表password和salt。

p的長度是0到232-1位元組,s的長度是8到232-1位元組(如果是做密碼hash,推薦16位元組)。

之是以叫做primary inputs,是因為這兩個參數是必須輸入的。

剩下的參數叫做secondary inputs,他們包括:

并行程度p,表示同時可以有多少獨立的計算鍊同時運作,取值是1到224-1。

tag長度 τ, 長度從4到232-1位元組。‘

記憶體大小 m, 機關是兆,值取 8p到232-1。

疊代器的個數t,提升運作速度。取值1到232-1。

版本号v,一個位元組,取值0x13。

安全值 k , 長度是0到232-1位元組。

附加資料 x,長度是0到232-1位元組。

argon2的類型,0代表argon2d,1代表argon2i,2代表argon2id。

這些輸入可以用下面的代碼來表示:

我們先來看一下非并行的argon2的算法流程:

密碼學系列之:Argon2加密算法詳解

非并行的argon2是最簡單的。

上圖中g表示的是一個壓縮函數,接收兩個1024byte的輸入,輸出一個1024byte。

i表示的是執行的步數,上面的φ(i) 就是輸入,取自記憶體空間。

作為一個memory-hard的算法,一個很重要的工作就是建構初始記憶體。接下來,我們看一下如何建構初始記憶體空間。

首先,我們需要建構 h0 ,這是一個 64-byte 的block值,通過h0,可以去建構更多的block。計算h0的公式如下:

h0 = h(p,τ,m,t,v,y,⟨p⟩,p,⟨s⟩,s,⟨k⟩,k,⟨x⟩,x)

它是前面我們提到的輸入參數的h函數。h0的大小是64byte。

看下h0的代碼生成:

對于輸入參數并行程度p來說,需要将記憶體分成一個記憶體矩陣​<code>​b[i][j]​</code>​, 它是一個 p 行的矩陣。

計算矩陣b的值:

密碼學系列之:Argon2加密算法詳解

其中h′ 是一個基于h的變長hash算法。

我們給一下這個算法的實作:

如果我們的疊代次數多于一次,也就是說t &gt; 1, 我們這樣計算下一次疊代的 b :

密碼學系列之:Argon2加密算法詳解

最終周遊t次之後,我們得到最終的b :

b_{\text {final }}=b^{t}[0][q-1] \oplus b^{t}[1][q-1] \oplus \cdots \oplus b^{t}[p-1][q-1]

密碼學系列之:Argon2加密算法詳解

最後得到輸出:

\mathrm{tag} \leftarrow h^{\prime}\left(b_{\text {final }}\right)

密碼學系列之:Argon2加密算法詳解

這段邏輯也可以用代碼來表示:

本文已收錄于 ​​http://www.flydean.com/40-argon2/​​ 最通俗的解讀,最深刻的幹貨,最簡潔的教程,衆多你不知道的小技巧等你來發現! 歡迎關注我的公衆号:「程式那些事」,懂技術,更懂你!