java-topology/test/jdk/sun/security/pkcs11/KDF/TestHKDF.java
russell@unturf.com 0a580b313d undefect. CWE-407 — 63 sites patched across 27 ecosystems
Authors: russell@unturf.com · brackishbert@gmail.com · foxhop.net · TimeHexOn.com

Patches, unit tests, benchmarks, whitepaper, and outreach briefs.
Public domain — no copyright claimed. Use freely.
2026-03-26 17:11:57 -04:00

682 lines
29 KiB
Java

/*
* Copyright (c) 2025, Red Hat, Inc.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
import javax.crypto.*;
import javax.crypto.spec.*;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.math.BigInteger;
import java.security.*;
import java.security.spec.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.HexFormat;
import java.util.List;
/*
* @test
* @bug 8328119
* @summary test HKDF key derivation in SunPKCS11
* @library /test/lib ..
* @run main/othervm/timeout=120 TestHKDF
*/
public final class TestHKDF extends PKCS11Test {
private static final boolean DEBUG = false;
private static final HexFormat hex = HexFormat.of().withLowerCase();
private static final byte[] knownBytes = hex.parseHex(
"000102030405060708090a0b0c0d0e0f10111213141516");
private static final OutputStream debugOut = new ByteArrayOutputStream();
private static final PrintWriter debugPrinter = new PrintWriter(debugOut);
private static boolean testFailed = false;
private static Provider p11Provider;
private static SecretKeyFactory p11GenericSkf;
private record TestContext(String hkdfAlg, String derivedKeyAlg,
Supplier<SecretKey> baseKey, byte[] salt, byte[] info,
byte[] expectedPRK, byte[] expectedOKM, byte[] expectedOpOut) {
// expectedOpOut value:
// - If derivedKeyAlg is AES, expectedOpOut is the result of encrypting
// knownBytes with derivedKey, using AES/CBC/PKCS5Padding and an IV
// of 16 zero bytes.
// - If derivedKeyAlg is Generic, expectedOpOut is the result of
// calculating the HmacSHA256 of knownBytes with derivedKey.
}
private static class HkdfTestAssertionException extends Exception {
HkdfTestAssertionException(String msg) {
super(msg);
}
}
private enum KdfParamSpecType {
EXTRACT,
EXPAND,
EXTRACT_EXPAND
}
private enum KeyMaterialType {
KEY,
DATA
}
private static final List<List<KeyMaterialType>> keyMaterialCombinations =
List.of(
List.of(KeyMaterialType.KEY),
List.of(KeyMaterialType.DATA),
List.of(KeyMaterialType.KEY, KeyMaterialType.KEY),
List.of(KeyMaterialType.KEY, KeyMaterialType.DATA),
List.of(KeyMaterialType.DATA, KeyMaterialType.KEY),
List.of(KeyMaterialType.DATA, KeyMaterialType.DATA)
);
private static void addKeyMaterial(
List<KeyMaterialType> keyMaterialCombination, byte[] keyMaterial,
Consumer<SecretKey> addKeyCb, Consumer<byte[]> addDataCb)
throws Exception {
if (keyMaterial.length < keyMaterialCombination.size()) {
throw new Exception("Key material is not enough to fulfill the " +
"combination requirement.");
}
int dataStart = 0, dataEnd;
for (int i = 0; i < keyMaterialCombination.size(); i++) {
dataEnd =
keyMaterial.length - keyMaterialCombination.size() + i + 1;
byte[] chunk = Arrays.copyOfRange(keyMaterial, dataStart, dataEnd);
if (keyMaterialCombination.get(i) == KeyMaterialType.KEY) {
addKeyCb.accept(p11GenericSkf.generateSecret(
new SecretKeySpec(chunk, "Generic")));
} else {
addDataCb.accept(chunk);
}
dataStart = dataEnd;
}
}
private static List<AlgorithmParameterSpec> generateKdfParamSpecs(
TestContext ctx, KdfParamSpecType type) throws Exception {
List<AlgorithmParameterSpec> kdfParamSpecs = new ArrayList<>();
if (type == KdfParamSpecType.EXTRACT ||
type == KdfParamSpecType.EXTRACT_EXPAND) {
for (List<KeyMaterialType> keyMaterialCombination :
keyMaterialCombinations) {
final HKDFParameterSpec.Builder b =
HKDFParameterSpec.ofExtract();
SecretKey baseKey = ctx.baseKey.get();
if (baseKey instanceof SecretKeySpec) {
addKeyMaterial(keyMaterialCombination, baseKey.getEncoded(),
b::addIKM, b::addIKM);
} else if (baseKey != null) {
b.addIKM(baseKey);
}
if (ctx.salt != null) {
addKeyMaterial(keyMaterialCombination, ctx.salt, b::addSalt,
b::addSalt);
}
if (type == KdfParamSpecType.EXTRACT) {
kdfParamSpecs.add(b.extractOnly());
} else {
kdfParamSpecs.add(b.thenExpand(ctx.info,
ctx.expectedOKM.length));
}
if (ctx.salt == null && !(baseKey instanceof SecretKeySpec)) {
// If the salt is null and the IKM is a non-SecretKeySpec
// (i.e. is a P11Key.P11SecretKey), the key material
// cannot be split and there will be a single
// HKDFParameterSpec to test.
break;
}
}
} else {
assert type == KdfParamSpecType.EXPAND : "Unexpected type.";
kdfParamSpecs.add(HKDFParameterSpec.expandOnly(
new SecretKeySpec(ctx.expectedPRK, "Generic"), ctx.info,
ctx.expectedOKM.length));
}
return kdfParamSpecs;
}
private static void checkOpWithDerivedKey(TestContext ctx,
SecretKey derivedKey, Provider p) throws Exception {
byte[] opOut;
switch (ctx.derivedKeyAlg) {
case "AES" -> {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", p);
cipher.init(Cipher.ENCRYPT_MODE, derivedKey,
new IvParameterSpec(new byte[16]));
opOut = cipher.doFinal(knownBytes);
}
case "Generic" -> {
Mac hmac = Mac.getInstance("HmacSHA256", p);
hmac.init(derivedKey);
opOut = hmac.doFinal(knownBytes);
}
default -> throw new RuntimeException(
"Unexpected derived key algorithm.");
}
printByteArrayAssertion("Operation output", opOut, ctx.expectedOpOut);
if (!Arrays.equals(opOut, ctx.expectedOpOut)) {
throw new HkdfTestAssertionException(
"Operation with derived key failure.");
}
}
private static void checkDerivationData(String derivationType,
byte[] derivedKey, byte[] derivedData, byte[] expectedData)
throws Exception {
printByteArrayAssertion(derivationType + " key derivation", derivedKey,
expectedData);
printByteArrayAssertion(derivationType + " data derivation",
derivedData, expectedData);
if (!Arrays.equals(derivedKey, expectedData) ||
!Arrays.equals(derivedData, expectedData)) {
throw new HkdfTestAssertionException(
derivationType + " derivation failure.");
}
}
private static void executeDerivationForKdfParamSpec(TestContext ctx,
KdfParamSpecType type, KDF kdf, AlgorithmParameterSpec kdfParamSpec,
Provider p) throws Exception {
printDerivationInfo(ctx, type, kdfParamSpec, p);
printHeader("HKDF derivation: output", '-', 10);
String derivedKeyAlg = type == KdfParamSpecType.EXTRACT ?
"Generic" : ctx.derivedKeyAlg;
SecretKey derivedKey = kdf.deriveKey(derivedKeyAlg, kdfParamSpec);
byte[] derivedData = kdf.deriveData(kdfParamSpec);
if (type == KdfParamSpecType.EXPAND ||
type == KdfParamSpecType.EXTRACT_EXPAND) {
checkDerivationData("Extract", derivedKey.getEncoded(),
derivedData, ctx.expectedOKM);
checkOpWithDerivedKey(ctx, derivedKey, p);
} else {
assert type == KdfParamSpecType.EXTRACT : "Unexpected type.";
checkDerivationData("Expand", derivedKey.getEncoded(),
derivedData, ctx.expectedPRK);
}
}
private static void crossCheckTestExpectedData(TestContext ctx,
KdfParamSpecType type, AlgorithmParameterSpec kdfParamSpec)
throws Exception {
try {
Provider sunJCE = Security.getProvider("SunJCE");
KDF kdf = KDF.getInstance(ctx.hkdfAlg, sunJCE);
executeDerivationForKdfParamSpec(ctx, type, kdf, kdfParamSpec,
sunJCE);
} catch (HkdfTestAssertionException e) {
// Fail if derivation was possible and the assertion data in this
// test is inconsistent with SunJCE. This should never happen.
throw e;
} catch (Exception e) {
// Cross-checking of the expected data in this test is a
// best-effort. If derivation was not possible (e.g. SunJCE does
// not support the HKDF algorithm), do not fail.
}
}
private static void reportTestFailure(Exception e) {
testFailed = true;
printHeader("TEST FAILED", 'x', 10);
e.printStackTrace(debugPrinter);
}
private static void executeDerivation(TestContext ctx,
KdfParamSpecType type) {
try {
KDF kdf = KDF.getInstance(ctx.hkdfAlg, p11Provider);
List<AlgorithmParameterSpec> kdfParamSpecs =
generateKdfParamSpecs(ctx, type);
crossCheckTestExpectedData(ctx, type, kdfParamSpecs.get(0));
for (AlgorithmParameterSpec kdfParamSpec : kdfParamSpecs) {
executeDerivationForKdfParamSpec(ctx, type, kdf, kdfParamSpec,
p11Provider);
}
} catch (Exception e) {
reportTestFailure(e);
}
}
private static byte[] hexStringToByteArray(String hexString) {
return hexString != null ? hex.parseHex(hexString) : null;
}
private static void executeTest(String testHeader, String hkdfAlg,
String derivedKeyAlg, SecretKey baseKey, String saltHex,
String infoHex, String expectedPRKHex, String expectedOKMHex,
String expectedOpOutHex) {
executeTest(testHeader, hkdfAlg, derivedKeyAlg, ()-> baseKey, saltHex,
infoHex, expectedPRKHex, expectedOKMHex, expectedOpOutHex);
}
private static void executeTest(String testHeader, String hkdfAlg,
String derivedKeyAlg, String baseKeyHex, String saltHex,
String infoHex, String expectedPRKHex, String expectedOKMHex,
String expectedOpOutHex) {
executeTest(testHeader, hkdfAlg, derivedKeyAlg,
()-> new SecretKeySpec(hexStringToByteArray(baseKeyHex),
"Generic"), saltHex, infoHex, expectedPRKHex,
expectedOKMHex, expectedOpOutHex);
}
private static void executeTest(String testHeader, String hkdfAlg,
String derivedKeyAlg, Supplier<SecretKey> baseKey, String saltHex,
String infoHex, String expectedPRKHex, String expectedOKMHex,
String expectedOpOutHex) {
printTestHeader(testHeader);
TestContext ctx = new TestContext(hkdfAlg, derivedKeyAlg, baseKey,
hexStringToByteArray(saltHex),
hexStringToByteArray(infoHex),
hexStringToByteArray(expectedPRKHex),
hexStringToByteArray(expectedOKMHex),
hexStringToByteArray(expectedOpOutHex));
executeDerivation(ctx, KdfParamSpecType.EXTRACT_EXPAND);
executeDerivation(ctx, KdfParamSpecType.EXTRACT);
executeDerivation(ctx, KdfParamSpecType.EXPAND);
}
private static void executeInvalidKeyDerivationTest(String testHeader,
String keyAlg, int keySize, String errorMsg) {
printTestHeader(testHeader);
try {
KDF k = KDF.getInstance("HKDF-SHA256", p11Provider);
k.deriveKey(keyAlg, HKDFParameterSpec.ofExtract()
.thenExpand(null, keySize));
throw new Exception("No exception thrown.");
} catch (InvalidAlgorithmParameterException iape) {
// Expected.
} catch (Exception e) {
reportTestFailure(new Exception(errorMsg + " expected to throw " +
"InvalidAlgorithmParameterException for key algorithm '" +
keyAlg + "'.", e));
}
}
private static void printTestHeader(String testHeader) {
debugPrinter.println();
debugPrinter.println("=".repeat(testHeader.length()));
debugPrinter.println(testHeader);
debugPrinter.println("=".repeat(testHeader.length()));
}
private static void printHeader(String header, char sepChar, int sepCount) {
String sepBlock = String.valueOf(sepChar).repeat(sepCount);
debugPrinter.println(sepBlock + " " + header + " " + sepBlock);
}
private static void printDerivationKeyMaterial(String header,
List<SecretKey> keyMaterial, KdfParamSpecType type) {
if (keyMaterial != null && !keyMaterial.isEmpty()) {
debugPrinter.println(header + ":");
for (SecretKey km : keyMaterial) {
debugPrinter.print(" ".repeat(2));
if (km instanceof SecretKeySpec) {
debugPrinter.println(hex.formatHex(km.getEncoded()));
} else {
debugPrinter.println(km);
}
}
} else if (type == KdfParamSpecType.EXTRACT ||
type == KdfParamSpecType.EXTRACT_EXPAND) {
debugPrinter.println(header + ": NULL");
}
}
private static void printDerivationInfo(TestContext ctx,
KdfParamSpecType type, AlgorithmParameterSpec kdfParamSpec,
Provider p) {
debugPrinter.println();
printHeader("HKDF derivation: input", '-', 10);
debugPrinter.println("Algorithm: " + ctx.hkdfAlg);
debugPrinter.println("Provider: " + p.getName());
debugPrinter.println("Derivation type: " + type);
List<SecretKey> ikms = null;
List<SecretKey> salts = null;
byte[] info = null;
Integer length = null;
switch (kdfParamSpec) {
case HKDFParameterSpec.Extract asExtract -> {
debugPrinter.println("Derived key type: PRK (Generic)");
salts = asExtract.salts();
ikms = asExtract.ikms();
}
case HKDFParameterSpec.ExtractThenExpand asExtractExpand -> {
debugPrinter.println("Derived key type: " + ctx.derivedKeyAlg);
salts = asExtractExpand.salts();
ikms = asExtractExpand.ikms();
info = asExtractExpand.info();
length = asExtractExpand.length();
}
case HKDFParameterSpec.Expand asExpand -> {
debugPrinter.println("Derived key type: " + ctx.derivedKeyAlg);
info = asExpand.info();
length = asExpand.length();
}
case null, default -> throw new RuntimeException(
"Unrecognized AlgorithmParameterSpec class.");
}
printDerivationKeyMaterial("Salts", salts, type);
printDerivationKeyMaterial("IKMs", ikms, type);
if (info != null) {
debugPrinter.println("Info: " + hex.formatHex(info));
} else if (type == KdfParamSpecType.EXPAND ||
type == KdfParamSpecType.EXTRACT_EXPAND) {
debugPrinter.println("Info: NULL");
}
if (length != null) {
debugPrinter.println("Length: " + length);
}
}
private static void printByteArrayAssertion(String desc, byte[] actual,
byte[] expected) {
debugPrinter.println(desc + " (actual):");
debugPrinter.println(actual != null ? hex.formatHex(actual) : "null");
debugPrinter.println(desc + " (expected):");
debugPrinter.println(expected != null ? hex.formatHex(expected) :
"null");
}
private static SecretKey doKeyAgreement(String algorithm, PrivateKey privK,
PublicKey pubK) throws Exception {
KeyAgreement ka = KeyAgreement.getInstance(algorithm, p11Provider);
ka.init(privK);
ka.doPhase(pubK, true);
return ka.generateSecret("TlsPremasterSecret");
}
private static SecretKey getTlsPremasterSecretWithDHExchange(String xHex,
String yHex, String pHex, String gHex) throws Exception {
KeyFactory kf = KeyFactory.getInstance("DH", p11Provider);
BigInteger p = new BigInteger(pHex, 16);
BigInteger g = new BigInteger(gHex, 16);
PrivateKey privK = kf.generatePrivate(new DHPrivateKeySpec(
new BigInteger(xHex, 16), p, g));
PublicKey pubK = kf.generatePublic(new DHPublicKeySpec(
new BigInteger(yHex, 16), p, g));
return doKeyAgreement("DH", privK, pubK);
}
private static SecretKey getTlsPremasterSecretWithECDHExchange(String s,
String wx, String wy) throws Exception {
AlgorithmParameters p =
AlgorithmParameters.getInstance("EC", p11Provider);
p.init(new ECGenParameterSpec("secp256r1"));
ECParameterSpec params = p.getParameterSpec(ECParameterSpec.class);
KeyFactory kf = KeyFactory.getInstance("EC", p11Provider);
PrivateKey privK = kf.generatePrivate(new ECPrivateKeySpec(
new BigInteger(s), params));
ECPoint publicPoint = new ECPoint(new BigInteger(wx),
new BigInteger(wy));
PublicKey pubK = kf.generatePublic(new ECPublicKeySpec(
publicPoint, params));
return doKeyAgreement("ECDH", privK, pubK);
}
private static void test_RFC_5869_case_1() {
executeTest("RFC 5869 - Test Case 1",
"HKDF-SHA256",
"Generic",
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
"000102030405060708090a0b0c",
"f0f1f2f3f4f5f6f7f8f9",
"077709362c2e32df0ddc3f0dc47bba6390b6c73bb50f9c3122ec844ad7c2" +
"b3e5",
"3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4" +
"c5bf34007208d5b887185865",
"ad9e90d0c59d47539899647a3baf0fd364c54eeb5f4d0b80e1f39579e434" +
"e801");
}
private static void test_RFC_5869_case_2() {
executeTest("RFC 5869 - Test Case 2",
"HKDF-SHA256",
"Generic",
"000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d" +
"1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b" +
"3c3d3e3f404142434445464748494a4b4c4d4e4f",
"606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d" +
"7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b" +
"9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccd" +
"cecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaeb" +
"ecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
"06a6b88c5853361a06104c9ceb35b45cef760014904671014a193f40c15f" +
"c244",
"b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19af" +
"a97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9" +
"aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87",
"eabe8bc548bf430aedc423e9d7df94125eacff3dbb3b95b50379246c2546" +
"01da");
}
private static void test_RFC_5869_case_3() {
executeTest("RFC 5869 - Test Case 3",
"HKDF-SHA256",
"Generic",
"0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
null,
null,
"19ef24a32c717b167f33a91d6f648bdf96596776afdb6377ac434c1c293c" +
"cb04",
"8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c73" +
"8d2d9d201395faa4b61a96c8",
"06828b5679679681be59aa2822869cb1a174319e53a545e3301bd832ae3e" +
"513f");
}
private static void test_AES_HKDFWithHmacSHA256() {
executeTest("AES - HKDF-SHA256",
"HKDF-SHA256",
"AES",
"000102030405060708090a0b0c0d0e0f",
"101112131415161718191a1b1c1d1e1f",
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"0ecd9f09ddfc6b7bcad2646fa6bc10f922e5489a4ea755ec87ec1b7df379" +
"85ca",
"b97b1b4ce098f8e22f2f38b60d9f7a0e5902a1193602a876c010d73009dd" +
"0701",
"646e0175bcef43b9ebd2a3884699ad40b34d4b011e91679c5f25f0721d36" +
"7f6a");
}
private static void test_AES_HKDFWithHmacSHA384() {
executeTest("AES - HKDF-SHA384",
"HKDF-SHA384",
"AES",
"000102030405060708090a0b0c0d0e0f",
"101112131415161718191a1b1c1d1e1f",
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"31ca88a527220f8271d78df4ce6c4d973f135ad37973b96644b4d52d499d" +
"0a2b03d53c875b1176b089e1e6161ab6d92b",
"ba91a67e4d7640495194916ef1252418a651103fbddb0f2ec8b9d1f44f7a" +
"7a0d",
"f3cfcb44d7b36dce96f584c74118b434e714a13448321063241fd24ace11" +
"f2a0");
}
private static void test_AES_HKDFWithHmacSHA512() {
executeTest("AES - HKDF-SHA512",
"HKDF-SHA512",
"AES",
"000102030405060708090a0b0c0d0e0f",
"101112131415161718191a1b1c1d1e1f",
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"f6e6b1ddb24ea0f0ede0f533d1f350c86bf78966b0e5fd2af34dd00dae39" +
"01d6279fe8111d6572e3cd05f2f0eeabb9144dc0da9437cdf37b0c6d7f3b" +
"1064ab2b",
"302212eb57ae758874e0e52fbdfa4eee29d7c694f181b21d8a8b571a43ce" +
"aad5",
"94459a6593f9c2cfea2ad32970efb8506f3a927927ba283fb6bfd7111aa8" +
"63fc");
}
private static void test_AES_HKDFWithHmacSHA256_EmptyBaseKey() {
executeTest("AES - HKDF-SHA256 (empty base key)",
"HKDF-SHA256",
"AES",
(SecretKey) null,
"101112131415161718191a1b1c1d1e1f",
"a0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
"cc267bd9515c1eba2cf6aaa1fc8380677f4351fcbea6d70873df5a334efc" +
"ee0d",
"cf353a33460b146c0eae3f0788ee281e5a0be15280fbeba107472aa1cd58" +
"d111",
"326e9028f51c05c1919215bad6e35668c94c88040c3777e8e6f8b6acdece" +
"85fa");
}
private static void test_AES_HKDFWithHmacSHA256_EmptyBaseKeySaltInfo() {
executeTest("AES - HKDF-SHA256 (empty base key, salt, and info)",
"HKDF-SHA256",
"AES",
(SecretKey) null,
null,
null,
"b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292" +
"c5ad",
"eb70f01dede9afafa449eee1b1286504e1f62388b3f7dd4f956697b0e828" +
"fe18",
"3fdcf83994f6e0a6f6f482d097e242355e255a8ed17e661a71ca2d592c7a" +
"884e");
}
private static void test_HKDF_after_DH_HkdfSHA256() throws Exception {
SecretKey tlsPremasterSecret = getTlsPremasterSecretWithDHExchange(
"00bcb8fa0a6b569961782a394599a1a02a05532a836819908a9a9000ed",
"58ceab52f470026eaea24eb250e08d7cc23f21dda57ad628d14eab788633" +
"cebc78c565f9292e6cfe9910d51c4878f590c46cbf380e19acf55cd468ab" +
"672afb29c09b7edfd522d034019eadae75ea99bacf1e166548f092a5d371" +
"930a275cbcb4bb02cb1d1b7a8bf3751dc85e61fb674059deef54e8ebbd36" +
"3bdac4f85c5e49cb7dc8720a8088f047f319a63c2722a720e187f827578b" +
"2545041bb5e640454e791f683622bb5aba4ab9bc51001c59bba5cd6cc0e2" +
"aec00b0a5313a27454a93d3bd3f2ae5ab1c13165d1564e3b2d60629302b3" +
"6bf44c1991bad279d3bd51b142294007f0c8828c9060d8b9b4cc6d335bcc" +
"ce31d4e6aa18fd3ce99cb92aec09de2d",
"00ffffffffffffffffc90fdaa22168c234c4c6628b80dc1cd129024e088a" +
"67cc74020bbea63b139b22514a08798e3404ddef9519b3cd3a431b302b0a" +
"6df25f14374fe1356d6d51c245e485b576625e7ec6f44c42e9a637ed6b0b" +
"ff5cb6f406b7edee386bfb5a899fa5ae9f24117c4b1fe649286651ece45b" +
"3dc2007cb8a163bf0598da48361c55d39a69163fa8fd24cf5f83655d23dc" +
"a3ad961c62f356208552bb9ed529077096966d670c354e4abc9804f1746c" +
"08ca18217c32905e462e36ce3be39e772c180e86039b2783a2ec07a28fb5" +
"c55df06f4c52c9de2bcbf6955817183995497cea956ae515d2261898fa05" +
"1015728e5a8aacaa68ffffffffffffffff",
"02"
);
executeTest("Test HKDF-SHA256 after DH exchange (TLS)",
"HKDF-SHA256",
"Generic",
tlsPremasterSecret,
null,
null,
"e3cf8e5e0892ad251a5863c7f6ddc4fb988b1a723a30d3fe1ac235799caf" +
"86e1",
"86e508974080cdad9fa4407e253d35ae48f40e0e266c91dd04c775538c17" +
"0eacd71bb4d54ba0c5065091",
"2e94c8c852d318887fa94dac544c369bc25879efd39683a9dc5eda55f565" +
"88c0");
}
private static void test_HKDF_after_ECDH_HkdfSHA256() throws Exception {
SecretKey tlsPremasterSecret = getTlsPremasterSecretWithECDHExchange(
"312092587041182431404764856027482553256569653405119712868911" +
"21589605635583946",
"851398477998049170325388348439523125186814652510003800309225" +
"34333070929362623",
"531080873930420952237875954830357399317339863932672261700603" +
"26242234504331049");
executeTest("Test HKDF-SHA256 after ECDH exchange (TLS)",
"HKDF-SHA256",
"Generic",
tlsPremasterSecret,
null,
null,
"638d8874237f12e42b366090ee8a0207d28a1ac8fd12b6a753ecb58c31cd" +
"6a5e",
"348a1afabe9560d3a0a6577e8bd66f0e8dc43b4ad52037f692ea5d28fbb2" +
"bc963ef59eba65a83befc465",
"bab55b2106b4fee07b7afc905ed7c1e84889e941fbc12f132c706addcfc0" +
"6e09");
}
private static void test_unknown_key_algorithm_derivation() {
executeInvalidKeyDerivationTest(
"Test derivation of an unknown key algorithm",
"UnknownAlgorithm",
32,
"Derivation of an unknown key algorithm");
}
private static void test_invalid_key_algorithm_derivation() {
executeInvalidKeyDerivationTest(
"Test derivation of an invalid key algorithm",
"PBKDF2WithHmacSHA1",
32,
"Derivation of an invalid key algorithm");
}
private static void test_invalid_aes_key_algorithm_derivation() {
executeInvalidKeyDerivationTest(
"Test derivation of an invalid AES key",
"PBEWithHmacSHA224AndAES_256",
32,
"Derivation of an invalid AES key");
}
private static void test_invalid_AES_key_size() {
executeInvalidKeyDerivationTest(
"Test derivation of an invalid AES key size",
"AES",
31,
"Derivation of an AES key of invalid size (31 bytes)");
}
public void main(Provider p) throws Exception {
p11Provider = p;
p11GenericSkf = SecretKeyFactory.getInstance("Generic", p11Provider);
for (Method m : TestHKDF.class.getDeclaredMethods()) {
if (m.getName().startsWith("test")) {
m.invoke(null);
}
}
if (DEBUG || testFailed) {
debugPrinter.flush();
System.out.println(debugOut);
}
if (testFailed) {
throw new Exception("TEST FAILED");
}
System.out.println("TEST PASS - OK");
}
public static void main(String[] args) throws Exception {
main(new TestHKDF(), args);
}
}