Qualcuno sa di eventuali implementazioni esistenti per NIST SP 800-56A Funzione di derivazione chiave di concatenazione/CONCAT KDF (preferibilmente in Java)?Implementazioni esistenti per NIST SP 800-56A Funzione di derivazione chiave di concatenazione?
La funzione chiave di derivazione è documentata nella sezione 5.8.1 della pubblicazione del NIST: Raccomandazione per Pair-Wise chiave Schemi stabilimenti che utilizzino logaritmo discreto Cryptography
link qui: http://csrc.nist.gov/publications/nistpubs/800-56A/SP800-56A_Revision1_Mar08-2007.pdf
CNG di Microsoft ha un'implementazione here ma se si confronta la funzione implementata da Microsoft, rispetto ai parametri documentati in NIST SP 800-56A, questi non vengono calcolati e l'implementazione di Microsoft non è utilizzabile. Ho tentato di implementare un programma di esempio in C++, ma non ho potuto abbinare i parametri.
Qualcuno potrebbe tentare di implementarlo o conoscere eventuali implementazioni esistenti?
Sto cercando un'implementazione che sia in grado di giustificare il motivo della precisione con le specifiche NIST. Ho visto un paio di implementazioni là fuori e ritengo che non siano accurate rispetto alle specifiche NIST (parametri mancanti, flusso logico non valido ecc.).
Se è possibile implementarlo da soli, sono sempre lieto di condividere il mio codice sorgente per il dibattito. Grazie! Questo sarebbe un buon contributo per la comunità open source!
EDIT:
Grazie a @Rasmus Faber, posso finalmente portare la questione al termine, e la speranza di rispondere alla stessa domanda che tutti gli altri hanno di me.
Ecco il codice che ho modificato sulla base di @Rasmus Faber e i miei codici originali:
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: Grazie per il vostro sforzo. Ti do pieno credito per il codice di cui sopra. Quello che ho fatto con il codice sopra è stato quello di aggiungere codice per eseguire la convalida come richiesto dalle specifiche NIST.
Inoltre, ho corretto un bug in cui il keyDataLen è passato per specificare la lunghezza in bit, ma è stato trattato come la lunghezza in byte. Quindi, la chiave generata è risultata 8 volte più grande.
Ciò è stato risolto aggiungendo una riga keyDataLen = keyDataLen/8;
nella prima riga del secondo metodo.
Ringrazio tutti per il loro supporto e spero che questo pezzo di codice possa fare molto per la comunità open source!
Perché non si sente l'implementazione CNG è utilizzabile? –
Non è stato possibile associare i parametri tra l'implementazione CNG e i parametri definiti in NIST SP 800-56A. Ad esempio, l'implementazione CNG non richiede nemmeno l'utilizzo dell'algoritmo hash. –
L'implementazione Microsoft ha la funzione hash hardcoded, sì (e non riesco a vedere * quale * hash-function è hard-coded a). Questo lo rende inutilizzabile? Stai cercando un'altra implementazione per verificarne la tua? –