我被赋予了为我们的项目创建一个登录API的任务,我应该使用PBKDF2与HMACSHA256作为PRF.明文密码使用MD5散列,然后馈入PBKDF2以生成派生密钥.问题是,我无法获得与项目文档告诉我相同的输出.
这是Java中的PBKDF2实现:
public class PBKDF2 { public static byte[] deriveKey( byte[] password,byte[] salt,int iterationCount,int dkLen ) throws java.security.NoSuchAlgorithmException,java.security.InvalidKeyException { SecretKeySpec keyspec = new SecretKeySpec( password,"HmacSHA256" ); Mac prf = Mac.getInstance( "HmacSHA256" ); prf.init( keyspec ); // Note: hLen,dkLen,l,r,T,F,etc. are horrible names for // variables and functions in this day and age,but they // reflect the terse symbols used in RFC 2898 to describe // the PBKDF2 algorithm,which improves validation of the // code vs. the RFC. // // dklen is expressed in bytes. (16 for a 128-bit key) int hLen = prf.getMacLength(); // 20 for SHA1 int l = Math.max( dkLen,hLen); // 1 for 128bit (16-byte) keys int r = dkLen - (l-1)*hLen; // 16 for 128bit (16-byte) keys byte T[] = new byte[l * hLen]; int ti_offset = 0; for (int i = 1; i <= l; i++) { F( T,ti_offset,prf,salt,iterationCount,i ); ti_offset += hLen; } if (r < hLen) { // Incomplete last block byte DK[] = new byte[dkLen]; System.arraycopy(T,DK,dkLen); return DK; } return T; } private static void F( byte[] dest,int offset,Mac prf,byte[] S,int c,int blockIndex ) { final int hLen = prf.getMacLength(); byte U_r[] = new byte[ hLen ]; // U0 = S || INT (i); byte U_i[] = new byte[S.length + 4]; System.arraycopy( S,U_i,S.length ); INT( U_i,S.length,blockIndex ); for( int i = 0; i < c; i++ ) { U_i = prf.doFinal( U_i ); xor( U_r,U_i ); } System.arraycopy( U_r,dest,offset,hLen ); } private static void xor( byte[] dest,byte[] src ) { for( int i = 0; i < dest.length; i++ ) { dest[i] ^= src[i]; } } private static void INT( byte[] dest,int i ) { dest[offset + 0] = (byte) (i / (256 * 256 * 256)); dest[offset + 1] = (byte) (i / (256 * 256)); dest[offset + 2] = (byte) (i / (256)); dest[offset + 3] = (byte) (i); } // ctor private PBKDF2 () {} }
我使用这里找到的测试向量PBKDF2-HMAC-SHA2 test vectors来验证实现的正确性,并且全部检出.我不知道为什么我使用MD5散列密码不能得到相同的结果.
参数:
Salt: 000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F Iterations Count: 1000 DKLen: 16 (128-bit derived key)
使用“foobar”作为明文密码,预期结果如下:
PWHash = MD5(PlaintextPassword) = 3858f62230ac3c915f300c664312c63f PWKey = PBKDF2(PWHash,Salt,IterationsCount,DKLen) = 33C37758EFA6780C5E52FAB3B50F329C
我得到的
PWHash = 3858f62230ac3c915f300c664312c63f PWKey = 0bd0c7d8339df2c66ce4b6e1e91ed3f1
解决方法
迭代次数应该是4096,而不是1000.