Java NIST SP 800-56A串联/单步密钥派生功能的现有实现?
有人知道NIST SP 800-56A串联密钥派生函数/CONCAT KDF(最好是Java)的任何现有实现吗 NIST出版物第5.8.1节:使用离散对数加密的成对密钥建立方案建议中记录了密钥推导函数 链接此处: 微软的CNG有一个实现方案,但如果将微软实现的功能与NIST SP 800-56A中记录的参数进行比较,则两者不符,微软的实现方案不可用。我尝试在C++中实现一个示例程序,但是我不能匹配参数。 是否有人能够尝试实现它或知道任何现有的实现 我正在寻找一种能够证明其符合NIST规范的实施方案。我已经看到了一些实现,我觉得它们不符合NIST规范(缺少参数、无效逻辑流等) 如果您可以自己实现它,我总是很高兴分享我自己的源代码以供讨论。谢谢这将是对开源社区的一个很好的贡献 编辑: 多亏了@Rasmus Faber,我终于可以结束这个问题了,希望能回答和我一样的问题 以下是我根据@Rasmus Faber和我的原始代码编辑的代码: concatkeydrivationfunction.javaJava NIST SP 800-56A串联/单步密钥派生功能的现有实现?,java,c++,security,cryptography,cryptoapi,Java,C++,Security,Cryptography,Cryptoapi,有人知道NIST SP 800-56A串联密钥派生函数/CONCAT KDF(最好是Java)的任何现有实现吗 NIST出版物第5.8.1节:使用离散对数加密的成对密钥建立方案建议中记录了密钥推导函数 链接此处: 微软的CNG有一个实现方案,但如果将微软实现的功能与NIST SP 800-56A中记录的参数进行比较,则两者不符,微软的实现方案不可用。我尝试在C++中实现一个示例程序,但是我不能匹配参数。 是否有人能够尝试实现它或知道任何现有的实现 我正在寻找一种能够证明其符合NIST规范的实施方
import java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.security.MessageDigest;
导入java.security.NoSuchAlgorithmException;
/**
*
*级联密钥派生函数的实现
* http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
*
*/
公共类ConcatKeyDerivationFunction{
私有静态最终long MAX_HASH_INPUTLEN=long.MAX_值;
私有静态最终长无符号_INT_MAX_值=4294967295L;
私有静态消息摘要md;
public ConcatKeyDerivationFunction(字符串hashAlg)抛出NoSuchAlgorithmException{
md=MessageDigest.getInstance(hashAlg);
}
公共字节[]concatKDF(字节[]z,int keyDataLen,字节[]algorithmID,字节[]partyUInfo,字节[]partyVInfo,字节[]suppPubInfo,字节[]suppPrivInfo){
int hashLen=md.getDigestLength()*8;
如果(keyDataLen%8!=0){
抛出新的IllegalArgumentException(“keydatalen应该是8的倍数”);
}
if(keyDataLen>(长)hashLen*无符号整数最大值){
抛出新的IllegalArgumentException(“keydatalen太大”);
}
if(algorithmID==null | | partyUInfo==null | | partyVInfo==null){
抛出新的NullPointerException(“必需参数为null”);
}
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
试一试{
写入(算法ID);
编写(partyUInfo);
编写(PartyInfo);
如果(suppPubInfo!=null){
编写(suppPubInfo);
}
if(supplivinfo!=null){
编写(提供信息);
}
}捕获(IOE异常){
抛出新的运行时异常(e);
}
字节[]otherInfo=baos.toByteArray();
返回concatKDF(z、keyDataLen、otherInfo);
}
专用字节[]concatKDF(字节[]z,int-keyDataLen,字节[]otherInfo){
keyDataLen=keyDataLen/8;
字节[]键=新字节[keyDataLen];
int hashLen=md.getDigestLength();
int reps=keyDataLen/hashLen;
如果(重复>无符号输入最大值){
抛出新的IllegalArgumentException(“密钥派生失败”);
}
int计数器=1;
字节[]计数器InBytes=intToFourBytes(计数器);
if((counterInBytes.length+z.length+otherInfo.length)*8>MAX\u HASH\u INPUTLEN){
抛出新的IllegalArgumentException(“密钥派生失败”);
}
对于(int i=0;i>>24);
res[1]=(字节)((i>>>16)和0xFF);
res[2]=(字节)((i>>>8)和0xFF);
res[3]=(字节)(i&0xFF);
返回res;
}
}
@拉斯姆斯·费伯:谢谢你的努力。我完全相信你的上述代码。我对上述代码所做的是添加代码,按照NIST规范的要求执行验证
此外,我还修复了一个bug,其中传入的keyDataLen用于指定以位为单位的长度,但它被视为以字节为单位的长度。因此,生成的密钥最终要大8倍
这是通过添加一行keyDataLen=keyDataLen/8修复的第二个方法的第一行中的code>
我感谢大家的支持,并希望这段代码能对开源社区有很大帮助 不要认为您可以找到其他组件,然后从中测试验证组件实现列表中的所有组件
只有一家供应商用Java编写它们——委托
所有这些都在没有KDF的情况下进行验证:)。其余的工作由您决定。这里是一个快速而肮脏的实现:
public byte[] concatKDF(String hashAlg, byte[] z, int keyDataLen, byte[] algorithmID, byte[] partyUInfo, byte[] partyVInfo, byte[] suppPubInfo, byte[] suppPrivInfo) throws NoSuchAlgorithmException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
baos.write(algorithmID);
baos.write(partyUInfo);
baos.write(partyVInfo);
baos.write(suppPubInfo);
baos.write(suppPrivInfo);
} catch (IOException e) {
throw new RuntimeException(e);
}
byte[] otherInfo = baos.toByteArray();
return concatKDF(hashAlg, z, keyDataLen, otherInfo);
}
public byte[] concatKDF(String hashAlg, byte[] z, int keyDataLen, byte[] otherInfo) throws NoSuchAlgorithmException
{
byte[] key = new byte[keyDataLen];
MessageDigest md = MessageDigest.getInstance(hashAlg);
int hashLen = md.getDigestLength();
int reps = keyDataLen / hashLen;
for(int i=1;i<=reps;i++){
md.reset();
md.update(intToFourBytes(i));
md.update(z);
md.update(otherInfo);
byte[] hash = md.digest();
if(i<reps){
System.arraycopy(hash, 0, key, hashLen*(i-1), hashLen);
}else{
if(keyDataLen % hashLen == 0){
System.arraycopy(hash, 0, key, hashLen*(i-1), hashLen);
}else{
System.arraycopy(hash, 0, key, hashLen*(i-1), keyDataLen % hashLen);
}
}
}
return key;
}
public byte[] intToFourBytes(int i){
byte[] res = new byte[4];
res[0] = (byte) (i >>> 24);
res[1] = (byte) ((i >>> 16) & 0xFF);
res[2] = (byte) ((i >>> 8) & 0xFF);
res[3] = (byte) (i & 0xFF);
return res;
}
public byte[]concatKDF(字符串hashAlg,字节[]z,int-keyDataLen,字节[]algorithmID,字节[]partyUInfo,字节[]partyVInfo,字节[]suppPubInfo,字节[]supppprivinfo)抛出NoSuchAlgorithmException
{
ByteArrayOutputStream bas=新的ByteArrayOutputStream();
试一试{
写入(算法ID);
编写(partyUInfo);
编写(PartyInfo);
编写(suppPubInfo);
编写(提供信息);
}捕获(IOE异常){
抛出新的运行时异常(e);
}
字节[]otherInfo=baos.toByteArray();
返回concatKDF(hashAlg、z、keyDataLen、otherInfo);
}
公共字节[]concatKDF(字符串hashAlg,字节[]z,int-keyDataLen,字节[]otherInf
public byte[] concatKDF(String hashAlg, byte[] z, int keyDataLen, byte[] algorithmID, byte[] partyUInfo, byte[] partyVInfo, byte[] suppPubInfo, byte[] suppPrivInfo) throws NoSuchAlgorithmException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
baos.write(algorithmID);
baos.write(partyUInfo);
baos.write(partyVInfo);
baos.write(suppPubInfo);
baos.write(suppPrivInfo);
} catch (IOException e) {
throw new RuntimeException(e);
}
byte[] otherInfo = baos.toByteArray();
return concatKDF(hashAlg, z, keyDataLen, otherInfo);
}
public byte[] concatKDF(String hashAlg, byte[] z, int keyDataLen, byte[] otherInfo) throws NoSuchAlgorithmException
{
byte[] key = new byte[keyDataLen];
MessageDigest md = MessageDigest.getInstance(hashAlg);
int hashLen = md.getDigestLength();
int reps = keyDataLen / hashLen;
for(int i=1;i<=reps;i++){
md.reset();
md.update(intToFourBytes(i));
md.update(z);
md.update(otherInfo);
byte[] hash = md.digest();
if(i<reps){
System.arraycopy(hash, 0, key, hashLen*(i-1), hashLen);
}else{
if(keyDataLen % hashLen == 0){
System.arraycopy(hash, 0, key, hashLen*(i-1), hashLen);
}else{
System.arraycopy(hash, 0, key, hashLen*(i-1), keyDataLen % hashLen);
}
}
}
return key;
}
public byte[] intToFourBytes(int i){
byte[] res = new byte[4];
res[0] = (byte) (i >>> 24);
res[1] = (byte) ((i >>> 16) & 0xFF);
res[2] = (byte) ((i >>> 8) & 0xFF);
res[3] = (byte) (i & 0xFF);
return res;
}
// a shared secret provided by your protocol
byte[] sharedSecret = ...
// a salt; if you don't have access to a salt, use salt-less SingleStepKdf.fromSha256() or similar
byte[] salt = ...
// other info to bind the key to the context, see the NIST spec for more detail
byte[] otherInfo = "macKey".getBytes();
byte[] keyMaterial = SingleStepKdf.fromHmacSha256().derive(sharedSecret, 32, salt, otherInfo);
SecretKey secretKey = new SecretKeySpec(keyMaterial, "AES");
(z: afc4e154498d4770aa8365f6903dc83b, L: 16, fixedInfo: 662af20379b29d5ef813e655) = f0b80d6ae4c1e19e2105a37024e35dc6
(z: a3ce8d61d699ad150e196a7ab6736a63, L: 16, fixedInfo: ce5cd95a44ee83a8fb83f34c) = 5db3455a22b65edfcfde3da3e8d724cd
(z: a9723e56045f0847fdd9c1c78781c8b7, L: 16, fixedInfo: e69b6005b78f7d42d0a8ed2a) = ac3878b8cf357976f7fd8266923e1882
(z: a07a5e8df7ee1b2ce2a3d1348edfa8ab, L: 16, fixedInfo: e22a8ee34296dd39b56b31fb) = 70927d218b6d119268381e9930a4f256
(z: 3f892bd8b84dae64a782a35f6eaa8f00, L: 02, fixedInfo: ec3f1cd873d28858a58cc39e) = a7c0
(z: 3f892bd8b84dae64a782a35f6eaa8f00, L: 36, fixedInfo: ec3f1cd873d28858a58cc39e) = a7c0665298252531e0db37737a374651b368275f2048284d16a166c6d8a90a91a491c16f
(z: 3f892bd8b84dae64a782a35f6eaa8f00, L: 68, fixedInfo: ec3f1cd873d28858a58cc39e) = a7c0665298252531e0db37737a374651b368275f2048284d16a166c6d8a90a91a491c16f49641b9f516a03d9d6d0f4fe7b81ffdf1c816f40ecd74aed8eda2b8a3c714fa0
(z: 9ce5457e4a0eecc1c8709f7ef37a32e9, L: 16, fixedInfo: ) = 7d81e7d61acc06b90984ec4145469608
(z: 6ee6c00d70a6cd14bd5a4e8fcfec8386, L: 16, salt: 532f5131e0a2fecc722f87e5aa2062cb, fixedInfo: 861aa2886798231259bd0314) = 13479e9a91dd20fdd757d68ffe8869fb
(z: cb09b565de1ac27a50289b3704b93afd, L: 16, salt: d504c1c41a499481ce88695d18ae2e8f, fixedInfo: 5ed3768c2c7835943a789324) = f081c0255b0cae16edc6ce1d6c9d12bc
(z: 98f50345fd970639a1b7935f501e1d7c, L: 16, salt: 3691939461247e9f74382ae4ef629b17, fixedInfo: 6ddbdb1314663152c3ccc192) = 56f42183ed3e287298dbbecf143f51ac
(z: 02b40d33e3f685aeae677ac344eeaf77, L: 02, salt: 0ad52c9357c85e4781296a36ca72039c, fixedInfo: c67c389580128f18f6cf8592) = be32
(z: 02b40d33e3f685aeae677ac344eeaf77, L: 36, salt: 0ad52c9357c85e4781296a36ca72039c, fixedInfo: c67c389580128f18f6cf8592) = be32e7d306d891028be088f213f9f947c50420d9b5a12ca69818dd9995dedd8e6137c710
(z: 02b40d33e3f685aeae677ac344eeaf77, L: 68, salt: 0ad52c9357c85e4781296a36ca72039c, fixedInfo: c67c389580128f18f6cf8592) = be32e7d306d891028be088f213f9f947c50420d9b5a12ca69818dd9995dedd8e6137c7104d67f2ca90915dda0ab68af2f355b904f9eb0388b5b7fe193c9546d45849133d
(z: 2c2438b6321fed7a9eac200b91b3ac30, L: 56, salt: 6199187690823def2037e0632577c6b1, fixedInfo: ) = b402fda16e1c2719263be82158972c9080a7bafcbe0a3a6ede3504a3d5c8c0c0e00fe7e5f6bb3afdfa4d661b8fbe4bd7b950cfe0b2443bbd
(z: 0ffa4c40a822f6e3d86053aefe738eac, L: 64, salt: 6199187690823def2037e0632577c6b1, fixedInfo: ) = 0486d589aa71a603c09120fb76eeab3293eee2dc36a91b23eb954d6703ade8a7b660d920c5a6f7bf3898d0e81fbad3a680b74b33680e0cc6a16aa616d078b256
(z: a801d997ed539ae9aa05d17871eb7fab, L: 08, fixedInfo: 03697296e42a6fdbdb24b3ec) = 1a5efa3aca87c1f4
(z: e9624e112f9e90e7bf8a749cf37d920c, L: 16, fixedInfo: 03697296e42a6fdbdb24b3ec) = ee93ca3986cc43516ae4e29fd7a90ef1