天天看点

密码学系列之: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/​​ 最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现! 欢迎关注我的公众号:「程序那些事」,懂技术,更懂你!