当前位置: 首页 > 面试题库 >

PBKDF2和Java中的Bouncycastle

池庆
2023-03-14
问题内容

我试图将密码安全地存储在数据库中,为此,我选择存储使用PBKDF2函数生成的哈希值。我想使用弹性城堡库来执行此操作,但是我不知道为什么我无法通过使用JCE接口来使其工作…问题是,以三种不同的方式生成哈希值:
1.使用PBKDF2WithHmacSHA1秘密密钥由sun提供的工厂
。2.直接
使用有弹性的城堡api。3.通过JCE使用有弹性的城堡会
产生2个不同的值:前两个值相同,第三个值相同。

这是我的代码:

    //Mode 1

    SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
    KeySpec keyspec = new PBEKeySpec("password".toCharArray(), salt, 1000, 128);
    Key key = factory.generateSecret(keyspec);
    System.out.println(key.getClass().getName());
    System.out.println(Arrays.toString(key.getEncoded()));

    //Mode 2

    PBEParametersGenerator generator = new PKCS5S2ParametersGenerator();
    generator.init(PBEParametersGenerator.PKCS5PasswordToUTF8Bytes(("password").toCharArray()), salt, 1000);
    KeyParameter params = (KeyParameter)generator.generateDerivedParameters(128);
    System.out.println(Arrays.toString(params.getKey()));

    //Mode 3

    SecretKeyFactory factorybc = SecretKeyFactory.getInstance("PBEWITHHMACSHA1", "BC");
    KeySpec keyspecbc = new PBEKeySpec("password".toCharArray(), salt, 1000, 128);
    Key keybc = factorybc.generateSecret(keyspecbc);
    System.out.println(keybc.getClass().getName());
    System.out.println(Arrays.toString(keybc.getEncoded()));
    System.out.println(keybc.getAlgorithm());

我知道PBKDF2是使用HMAC SHA1实现的,所以这就是为什么我在最后一种方法中选择了我从有弹性的城堡java文档中选择的“
PBEWITHHMACSHA1”作为算法的原因。

输出如下:

com.sun.crypto.provider.SunJCE_ae
[-53, 29, 113, -110, -25, 76, 115, -127, -64, 74, -63, 102, 75, 81, -21, 74]
[-53, 29, 113, -110, -25, 76, 115, -127, -64, 74, -63, 102, 75, 81, -21, 74]
org.bouncycastle.jce.provider.JCEPBEKey
[14, -47, -87, -16, -117, -31, 91, -121, 90, -68, -82, -31, -27, 5, -93, -67, 30, -34, -64, -40]
PBEwithHmacSHA

有任何想法吗?


问题答案:

简而言之,差异的原因是模式#1和#2中的PBKDF2算法使用PKCS#5 v2方案2(PKCS5S2)来生成迭代密钥,但是模式#3中用于“
PBEWITHHMACSHA1”的BouncyCastle提供程序使用了PKCS#而是使用12
v1(PKCS12)算法。这些是完全不同的密钥生成算法,因此您将获得不同的结果。

下面将详细说明为何如此以及为什么您得到不同大小的结果。

首先,在构造JCE
KeySpec时,keyLength参数仅向提供者“偏好”表示所需的密钥大小。从API文档:

注意:这用于指示密钥长度可变的密钥对密钥长度的偏好。实际密钥大小取决于每个提供程序的实现。

从JCEPBEKey的来源来看,Bouncy
Castle提供程序似乎并不尊重此参数,因此,在使用JCE API时,您应该期望从使用SHA-1的任何BC提供程序获取160位密钥。

您可以通过以编程方式访问测试代码中getKeySize()返回的keybc变量上的方法来确认这一点:

Key keybc = factorybc.generateSecret(keyspecbc);
// ...
Method getKeySize = JCEPBEKey.class.getDeclaredMethod("getKeySize");
getKeySize.setAccessible(true);
System.out.println(getKeySize.invoke(keybc)); // prints '160'

现在,要了解“
PBEWITHHMACSHA1”提供程序的含义,可以在BouncyCastleProvider的源代码中找到以下内容:

put("SecretKeyFactory.PBEWITHHMACSHA1", 
    "org.bouncycastle.jce.provider.JCESecretKeyFactory$PBEWithSHA");

JCESecretKeyFactory.PBEWithSHA的实现如下所示:

public static class PBEWithSHA
    extends PBEKeyFactory
{
    public PBEWithSHA()
    {
        super("PBEwithHmacSHA", null, false, PKCS12, SHA1, 160, 0);
    }
}

您可以在上方看到该密钥工厂使用PKCS#12
v1(PKCS12)算法来生成迭代密钥。但是,您要用于密码哈希处理的PBKDF2算法改为使用PKCS#5
v2方案2(PKCS5S2)。这就是为什么您获得不同结果的原因。

我快速浏览了注册的JCE提供程序BouncyCastleProvider,但是根本看不到 任何
使用PKCS5S2的密钥生成算法,更不用说将其与HMAC-SHA-1一起使用了。

因此,我想您要么会使用Sun实现(上面的模式1)并失去在其他JVM上的可移植性,要么直接使用Bouncy
Castle类(上面的模式2)并在运行时需要BC库。

无论哪种方式,您都应该切换到160位密钥,这样就不会不必要地截断生成的SHA-1哈希。



 类似资料:
  • 问题内容: 有没有一种方法可以解密Java中的密码。Java将算法实现为。我得到了创建密码哈希的代码。我在下面提到了哈希技术的链接: http://howtodoinjava.com/security/how-to-generate-secure-password-hash- md5-sha-pbkdf2-bcrypt-examples/ 我的要求是以加密格式存储第三方FTP服务器密码,并在需要登

  • 我正在进行一个Java项目,我必须确保用户密码保存在明文文件中的保密性和完整性。 为此,我将只在文件中写入密码的散列。更具体地说,我的意图是编写密码和随机salt的散列,再加上随机salt本身,以避免使用rainbow和lookup表。我还想使用PBKDF2进行键拉伸,以使散列的计算变得昂贵。最后,我想使用键控哈希算法HMAC作为最后一层保护。 我试图在Java代码中实现我的想法,我找到了上面介绍

  • 尽管我有点困惑,我是否应该将salt输入到我的PBKDF2函数中,并将salt存储在一列中,而将PBKDF2的密码存储在另一列中。 我也在使用CodeIgniter,并找到了一个用于PBKDF2的库(https://github.com/hashemqolami/codeigniter-pbkdf2-library),它声称我不需要单独存储salt。 使用作为推荐的用户密码注册用户;无需单独存储用

  • 我使用以下方法从NodeJS中的crypto lib创建加盐和散列密码: 对于randomBytes调用(创建SALT)我应该使用多大的大小?我听说过128位的盐,可能最多256位。看起来这个函数使用的是字节大小,那么我可以假设32(256位)的大小就足够了吗? 对于pbkdf2调用,什么是好的迭代次数,什么是好的密钥长度(keylen)?

  • 问题内容: 我正在用Java进行基于密码的文件加密;我正在使用AES作为底层加密算法,并使用以下代码(我是从该网站的另一位慷慨的海报获得者)从盐和密码的组合中得出密钥的。 我吃了盐,用户在两端输入密码,加密和解密工作正常:-)我的问题是,我希望能够在进入(可能很长)之前验证用户输入的密码是否正确解密过程。我知道PBKD规范包含一个可选的2字节验证值,但是我不确定如何使用上述方法生成该值。Java是

  • 我使用mitsuhiko的pbkdf2实现进行密码哈希: 此函数返回二进制摘要,然后将其编码在bas64中并保存到数据库中。此外,当用户登录时,Base64字符串被设置为cookie。 此函数用于密码哈希比较: 我想知道在安全性方面,二进制哈希和Base64字符串的比较是否有任何不同?例如,当用户登录时,我会计算提交密码的二进制摘要,从数据库中解码Base64字符串,然后比较两个二进制哈希,但是如