java hkdf 算法生成密钥
hkdf算法包含两个过程,‘提取’ 和 ‘扩展’,来生成任意长度的,更随机的密码。
生成密码需要的元素
名称|类型|例子|说明
-|-|-|-|-
password|byte[]|”abc”.getBytes()|用户输入的密码
salt|byte[]|new byte[]{1,5,7,6,41,85,63,7,89}|用于提取密码
info|byte[]|”product-info”.getByte()|使生成密码更随机
length|int|64|希望生成的密钥长度
1.提取
创建hkdfExtract函数,用salt摘要password,示例代码如下:
伪代码: prk = hkdfExtract(salt,password)
1 2 3 4 5 6 7 8 9 10
| private static byte[] hkdfExtract(byte[] salt, byte[] passsword) throws NoSuchAlgorithmException, InvalidKeyException { Mac mac = Mac.getInstance("HmacSHA1"); SecretKeySpec keySpec = new SecretKeySpec(salt, "HmacSHA1"); mac.init(keySpec); return mac.doFinal(passsword); }
|
上面的意思就是用salt做sha算法的密钥,对password进行摘要,得到的结果作为提取
步骤的结果prk
2.扩展
原理:key = hkdfExpand(prk,info,length)
具体逻辑,伪代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| result = new byte[length]; byte t = 1; digest=new byte[0]
Mac sha = Mac.getInstance("HmacSHA1"); sha.init(prk);
whilt(true){ sha.update(digest) sha.update(info) sha.update(t) digest = sha.doFinal(); t++; result+=digest; }
|
这里的意思是,以上一步生成的prk作为sha的密钥,对digtest、info、t进行摘要,将摘要结果保存在result中,
比如sha1每次摘要结果长度是20,如果参数length >20 则再次对digtest、info、t摘要,将结果叠加进去
注意第二次的digtest为上一次摘要的结果,t也递增了,最终获得的长度将大于length,取前length个作为hkdf的返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
private static byte[] hkdfExpand(byte[] prk, byte[] info, int length) throws NoSuchAlgorithmException, InvalidKeyException { Mac mac = Mac.getInstance("HmacSHA1"); SecretKeySpec keySpec = new SecretKeySpec(prk, "HmacSHA1"); mac.init(keySpec); byte[] result = new byte[length]; int pos = 0; byte[] digest = new byte[0]; byte t = 1; while (pos < result.length) { mac.update(digest); mac.update(info); mac.update(t); digest = mac.doFinal(); System.arraycopy(digest, 0, result, pos, Math.min(digest.length, length - pos)); pos += digest.length; t++; } return result; }
|
3.调用
经过上面两步操作,可以由给定的salt
password
info
keySize
1 2 3 4 5 6 7
| public static byte[] createHkdfKey(String password,String info, byte[] salt, int keySize) throws GeneralSecurityException { byte[] prk = hkdfExtract(salt, passwoed.getBytes()); return hkdfExpand(prk, info, keySize); }
|
4.总结
总之hkdf算法还是比较简单的,且可以生成任意长度的密钥,可以搭配其他的摘要算法如hkdfSha1,hkdfSha256,hkdfMd5
都是可以的。