当前位置: 首页 > 知识库问答 >
问题:

如何从它Java的任意字节数组派生AES 256位密钥?

赵志
2023-03-14

给定一个任意的Java字节数组,例如1024字节数组,我想导出一个AES-256位密钥。该数组由ECHD通过使用字节[]秘密=keyAgreement.generate秘密()通过javax.crypto.密钥协议生成

我目前的解决方案是将输入字节数组视为密码。使用PBKDF2密钥派生函数将输入数组用作密码和salt,如下所示。

更新:我已经将UTF-8设置为编码,以解决评论和答案中指出的问题。

private byte[] deriveAes256bitKey(byte[] secret)
    throws NoSuchAlgorithmException, InvalidKeySpecException {

    var secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA256");
    var password = new String(secret, UTF_8).toCharArray();
    var keySpec = new PBEKeySpec(password, secret, 1024, 256);
    return secretKeyFactory.generateSecret(keySpec).getEncoded();
}

有没有更好的方法在Java中获取字节数组并将其转换为AES-256位密钥?

共有2个答案

宗政元青
2023-03-14

这里需要的是KBKDF或基于密钥的密钥派生函数。KBKDF将包含足够熵的秘密值转换为特定大小的不同密钥。当使用密钥加强(使用salt和功因子或迭代计数)将熵可能太小的密码短语放入密钥时,使用PBKDF。如果输入值已经足够强大,不需要猜测/强制执行,则不需要使用功因数/迭代计数。

如果你只想要一个128位的结果值,SHA-256通常就足够了。然而,使用密钥派生函数仍然可以带来好处。首先,它是一个为函数显式定义的函数,因此更容易证明它是安全的。此外,通常可以向密钥导出功能添加额外数据,以便您可以导出更多密钥或密钥和IV。或者您可以扩展可配置的输出大小,为不同的密钥或密钥/IV输出足够的数据

也就是说,如果你使用SHA-256(或者SHA-512,以防你需要更多的位来表示key/IV),大多数密码学家不会太皱眉。输出仍然应该使用输入中所有可能的位进行随机化,并且不可能反转函数。

陈俊誉
2023-03-14

我对使用新字符串(输入). toCharArray()来创建密码持谨慎态度。它不可移植(它使用平台默认编码),如果输入中有无效的字符序列,它的行为是未定义的。

考虑一下:

    System.out.println(new String(new byte[] {(byte) 0xf0, (byte) 0x82, (byte) 0x82, (byte) 0xac}, StandardCharsets.UTF_8));

f08282ac是欧元符号(€)的超长编码。它被解码为替换字符(;0xfffd),因为它是一个非法序列。所有非法的UTF-8序列都将作为替换字符结束,这不是你想要的。

在将字节数组传递给SecretKeyFactory(base64编码)之前,可以通过序列化字节数组来避免解码问题,或者只需新的BigInteger(输入)。toString(字符最大基数))。但是,如果不使用SecretKeyFactory,可以避免这种情况。没必要。

PBKDF2(基于密码的密钥派生函数2)的设计目的是通过计算成本高和添加盐,使针对用户提供的密码的暴力攻击更加困难。

在这里你不需要(你的输入是大的和随机的;没有人会对它进行字典攻击)。你的问题只是输入长度不匹配所需的键长度。

您可以将输入散列到正确的长度:

MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] keyBytes = md.digest(input);
 类似资料:
  • 今天我了解到,“密码”往往意味着任意数量的字符的可记忆字符串,而“密钥”意味着高度随机的位字符串(基于所使用的加密算法的特定长度)。 所以今天我第一次听说了密钥派生函数的概念。 我对如何从任意长度的密码(在PHP中)派生32字节密钥感到困惑。 以下方法有效,但忽略了“[盐]应随机生成”的指示(钠也是如此): 以下方法也有效,但感觉也不太对: 在我的所有搜索中,我很惊讶我没有在PHP中找到一种“官方

  • 我从这里使用解决方案: 问题是当我这样做时: 我得到一个非常奇怪的字符串,类似于,但我想要一个可以保存在DB中的普通字符串。我错在哪里?

  • 问题内容: 我这样在Node.js中加密了一个字符串。 我注意到nodejs中的缓冲区就像十六进制,但每2个连续字符都成对出现。因此,如果我将其转换为十六进制,则长度只有一半。 例: 缓冲: 十六进制: 现在,我在aes256中使用的密钥的长度不能为64。这里,缓冲区的长度为32,十六进制的长度为64。 我想在golang中解密此密码,我将不得不使用此密钥和iv对其进行解密。 golang中的ae

  • 我正在尝试从ODT模板文件生成一个PDF,其中包含我需要填充的字段。 我想获得这个ODT模板的字节数组,它存在于我的项目的根文件夹中。我的应用程序是以这样一种方式提供字节数组来生成PDF。

  • 我正在尝试用python、ecrypt数据记录音频原始数据并将其发送到。NET服务器,我在其中解密接收到的数据并转换为字节数组。当我将接收到的数据转换为字节数组时,就像这样的编码。ASCII码。GetBytes(decryptedData)一切都很正常。但最大字节值为63,发送数据的最大字节值为255。发送和接收数据的示例: 发送数据 3, 0, 3, 0, 3, 0, 4, 0, 4, 0, 2

  • 问题内容: 首先,对英语不好对不起。 好吧,我想从torrent文件中读取散列信息。目前,我正在使用https://github.com/hyPiRion/java- bencode 这个bencode库来解码信息,但是我的问题是当我想将字符串转换为字节数组时。种子文件使用UTF-8编码。但是如果我这样做 很好。任何真正有用的东西。 另一方面,为了比较或尝试获取字符串,而不是获取字节,我已经阅读了