Существующие реализации для функции вывода Конкатенационного ключа NIST SP 800-56A?
кто-нибудь знает о каких-либо существующих реализациях для функции вывода Конкатенационного ключа NIST SP 800-56A / CONCAT KDF (предпочтительно в Java)?
функция вывода ключа документирована в разделе 5.8.1 публикации NIST: рекомендация для парных схем установления Ключей с использованием дискретной логарифмической криптографии
Ссылка здесь: http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
CNG Microsoft имеет реализацию здесь но если вы сравните функцию, реализованную Microsoft, по сравнению с параметрами, задокументированными в NIST SP 800-56A, они не соответствуют, и реализация Microsoft непригодна для использования. Я также попытался реализовать пример программы на C++, но я не мог соответствовать параметрам.
будет ли кто-нибудь в состоянии попытаться реализовать его или знать о каких-либо существующих реализациях?
Я ищу реализацию, которая может оправдать, почему она точна в спецификациях NIST. Я видел пару реализаций, и я чувствую, что они не точны в спецификациях NIST (отсутствующие параметры, недопустимый логический поток и т. д.).
Если вы можете реализовать его самостоятельно, я всегда рад поделиться своим исходным кодом для обсуждения. Спасибо! Это было бы хорошо вклад в сообщество с открытым исходным кодом!
EDIT:
благодаря @Rasmus Faber я могу, наконец, завершить этот вопрос и надеюсь ответить на тот же вопрос, что и у всех остальных.
вот код, который я отредактировал на основе @Rasmus Faber и моих оригинальных кодов:
ConcatKeyDerivationFunction.java
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
*
* Implementation of Concatenation Key Derivation Function<br/>
* http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
*
*/
public class ConcatKeyDerivationFunction {
private static final long MAX_HASH_INPUTLEN = Long.MAX_VALUE;
private static final long UNSIGNED_INT_MAX_VALUE = 4294967295L;
private static MessageDigest md;
public ConcatKeyDerivationFunction(String hashAlg) throws NoSuchAlgorithmException {
md = MessageDigest.getInstance(hashAlg);
}
public byte[] concatKDF(byte[] z, int keyDataLen, byte[] algorithmID, byte[] partyUInfo, byte[] partyVInfo, byte[] suppPubInfo, byte[] suppPrivInfo) {
int hashLen = md.getDigestLength() * 8;
if (keyDataLen % 8 != 0) {
throw new IllegalArgumentException("keydatalen should be a multiple of 8");
}
if (keyDataLen > (long) hashLen * UNSIGNED_INT_MAX_VALUE) {
throw new IllegalArgumentException("keydatalen is too large");
}
if (algorithmID == null || partyUInfo == null || partyVInfo == null) {
throw new NullPointerException("Required parameter is null");
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try {
baos.write(algorithmID);
baos.write(partyUInfo);
baos.write(partyVInfo);
if (suppPubInfo != null) {
baos.write(suppPubInfo);
}
if (suppPrivInfo != null) {
baos.write(suppPrivInfo);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
byte[] otherInfo = baos.toByteArray();
return concatKDF(z, keyDataLen, otherInfo);
}
private byte[] concatKDF(byte[] z, int keyDataLen, byte[] otherInfo) {
keyDataLen = keyDataLen / 8;
byte[] key = new byte[keyDataLen];
int hashLen = md.getDigestLength();
int reps = keyDataLen / hashLen;
if (reps > UNSIGNED_INT_MAX_VALUE) {
throw new IllegalArgumentException("Key derivation failed");
}
int counter = 1;
byte[] counterInBytes = intToFourBytes(counter);
if ((counterInBytes.length + z.length + otherInfo.length) * 8 > MAX_HASH_INPUTLEN) {
throw new IllegalArgumentException("Key derivation failed");
}
for (int i = 0; i <= reps; i++) {
md.reset();
md.update(intToFourBytes(i + 1));
md.update(z);
md.update(otherInfo);
byte[] hash = md.digest();
if (i < reps) {
System.arraycopy(hash, 0, key, hashLen * i, hashLen);
} else {
System.arraycopy(hash, 0, key, hashLen * i, keyDataLen % hashLen);
}
}
return key;
}
private 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;
}
}
@Rasmus Faber: Спасибо за ваши усилия. Я отдаю вам должное за вышеуказанный код. То, что я сделал с кодом выше, - это добавить код для выполнения проверки в соответствии с требованиями спецификаций NIST.
кроме того, я исправил ошибку, когда keyDataLen передавался, чтобы указать длину в битах, но он рассматривался как длина в байтах. Следовательно, сгенерированный ключ оказался в 8 раз больше.
Это было исправлено путем добавления строки keyDataLen = keyDataLen/8;
в первой строке второй способ.
Я благодарю всех за их поддержку и надеюсь, что этот кусок код пройдет долгий путь к сообществу с открытым исходным кодом!
2 ответов
вот быстрая и грязная реализация:
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;
}
Не думаю, что вы можете найти их другие, а затем проверить все в списке Validated Component Implementations
от http://csrc.nist.gov/groups/STM/cavp/documents/components/componentval.html.
есть только один поставщик, пишущий их на Java-Entrust http://www.entrust.com.
все они проверяются без KDF :). Остальная работа за вами.