Java、PHP 和 Objective-C 中的 pbkdf2 pkcs5 兼容散列
Posted
技术标签:
【中文标题】Java、PHP 和 Objective-C 中的 pbkdf2 pkcs5 兼容散列【英文标题】:pbkdf2 pkcs5 compatible hashing in Java, PHP and Objective-C 【发布时间】:2018-01-15 06:22:56 【问题描述】:我正在开发一个需要 pbkdf2 pkcs5 进行密码散列的应用程序。我想我在 php 和 Java 中有一些工作代码,但我不确定它们为什么会产生不同的结果。
这里是代码。
PHP 代码:
function hash_password($password, $salt, $user_id, $iterations)
$user_id = (string) $user_id;
$raw_pass = $salt . $user_id . $password;
$hash = hash_pbkdf2("sha512", $raw_pass, $salt, $iterations, 64, false);
return $hash;
echo hash_password("password", $salt, 2058, 1);
echo PHP_EOL;
Java 代码:
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import java.nio.charset.StandardCharsets;
import java.lang.RuntimeException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.math.BigInteger;
import javax.xml.bind.DatatypeConverter;
public final class Testing
private static String mSalt = "fd6c3dc0165dc420b4e9225bc9bee9684387e9621b2e2c00cfffebf1ec7c30b4";
private static String hashPassword(String password, String salt, int userId, int iterations) throws RuntimeException
String uid = String.valueOf(userId);
StringBuilder pwBuilder = new StringBuilder(salt);
pwBuilder.append(uid);
pwBuilder.append(password);
String rawPass = pwBuilder.toString();
try
SecretKeyFactory skf = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA512");
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), mSalt.getBytes(), iterations, 256);
byte[] result = skf.generateSecret(spec).getEncoded();
StringBuilder hashBuilder = new StringBuilder(result.length * 2);
for (byte r : result)
hashBuilder.append(String.format("%02x", r));
return hashBuilder.toString();
catch (NoSuchAlgorithmException | InvalidKeySpecException e)
throw new RuntimeException( e );
public static void main(String[] args)
System.out.println(hashPassword("password", mSalt, 2058, 1000000));
System.out.println("\n");
PHP 输出为:3754036ea2f37af8160e45d15c2e4d6597157ead118f060e76152c0813f806e8
Java 输出为:8b135bb19263677b70f1d5cbda5a23bc16df38e5e1a624c6df9a462975cac899
你能推荐一个同时兼容实现的库或要点吗?
【问题讨论】:
因为它是PBKDF2WithHmacSHA512
,其中PBKDF2
表示基于密码的密钥派生函数2,在您的情况下是伪随机函数。您的 Java 代码将始终产生不同的哈希值,但是 sha512
将始终为您提供相同的结果。您不必担心哈希值不同,只需担心check
函数,它将确认密码的有效性。
@Axalix 我试过SecretKeyFactory.getInstance("SHA512");
,但它抛出了NoSuchAlgorithmException
。
【参考方案1】:
现有代码存在两个问题:
使用相同的迭代次数。
使用相同的串联密码。
在 PHP 中:
使用
var_dump(hash_password("password", $salt, 2058, 1000000));
而不是
var_dump(hash_password("password", $salt, 2058, 1));
在 Java 中:
使用
PBEKeySpec spec = new PBEKeySpec(rawPass.toCharArray(), mSalt.getBytes(), iterations, 256);
而不是
PBEKeySpec spec = new PBEKeySpec(password.toCharArray(), mSalt.getBytes(), iterations, 256);
进行这些更改后,两者都会产生相同的结果:
424a0b30ea0cdef2ff0185f49ce67ee44273ce7e41026044d527c85550b3a207其他问题:
切勿在没有特定字符集的情况下使用 String#getBytes
。否则,将使用系统默认值,在不同的 JVM 中可能不同。
如果您使用 PBKDF2 对密码进行哈希处理,则在验证重新输入的密码时需要比较两个哈希值。这需要一个恒定时间比较函数来防止基于时间的攻击。
【讨论】:
以上是关于Java、PHP 和 Objective-C 中的 pbkdf2 pkcs5 兼容散列的主要内容,如果未能解决你的问题,请参考以下文章