Skip to content

Commit

Permalink
Counter KDF: NIST SP 800-108r1-upd1
Browse files Browse the repository at this point in the history
  • Loading branch information
amirhosv committed Aug 27, 2024
1 parent 10e8edd commit 65892ec
Show file tree
Hide file tree
Showing 12 changed files with 1,112 additions and 12 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## 2.5.0

### Minor
* [PR 397:](https://github.com/corretto/amazon-corretto-crypto-provider/pull/397) Support for Concatenation KDFs
* [PR 399:](https://github.com/corretto/amazon-corretto-crypto-provider/pull/399) Support for Counter KDFs

## 2.4.1

### Patch
Expand Down
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -284,7 +284,8 @@ if(FIPS)
else()
set(TEST_FIPS_PROPERTY "-DFIPS=false")
set(C_SRC ${C_SRC}
csrc/concatenation_kdf.cpp)
csrc/concatenation_kdf.cpp
csrc/counter_kdf.cpp)
endif()

add_library(amazonCorrettoCryptoProvider SHARED ${C_SRC})
Expand Down
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ SecretKeyFactory:
* ConcatenationKdfWithSHA512 (not available in FIPS builds)
* ConcatenationKdfWithHmacSHA256 (not available in FIPS builds)
* ConcatenationKdfWithHmacSHA512 (not available in FIPS builds)
* CounterKdfWithHmacSHA256 (not available in FIPS builds)
* CounterKdfWithHmacSHA384 (not available in FIPS builds)
* CounterKdfWithHmacSHA512 (not available in FIPS builds)

SecureRandom:
* ACCP's SecureRandom uses [AWS-LC's DRBG implementation](https://github.com/aws/aws-lc/blob/main/crypto/fipsmodule/rand/rand.c).
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ plugins {
}

group = 'software.amazon.cryptools'
version = '2.4.1'
version = '2.5.0'
ext.isFips = Boolean.getBoolean('FIPS')
if (ext.isFips) {
ext.awsLcGitVersionId = 'AWS-LC-FIPS-2.0.13'
Expand Down
32 changes: 32 additions & 0 deletions csrc/counter_kdf.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
#include "buffer.h"
#include "env.h"
#include "generated-headers.h"
#include <openssl/evp.h>
#include <openssl/kdf.h>

using namespace AmazonCorrettoCryptoProvider;

extern "C" JNIEXPORT void Java_com_amazon_corretto_crypto_provider_CounterKdfSpi_nKdf(JNIEnv* env,
jclass,
jint digestCode,
jbyteArray jSecret,
jint secretLen,
jbyteArray jInfo,
jint infoLen,
jbyteArray jOutput,
jint outputLen)
{
try {
EVP_MD const* digest = digest_code_to_EVP_MD(digestCode);
JBinaryBlob secret(env, nullptr, jSecret);
JBinaryBlob info(env, nullptr, jInfo);
JBinaryBlob output(env, nullptr, jOutput);
if (KBKDF_ctr_hmac(output.get(), outputLen, digest, secret.get(), secretLen, info.get(), infoLen) != 1) {
throw_openssl(EX_RUNTIME_CRYPTO, "KBKDF_ctr_hmac failed.");
}
} catch (java_ex& ex) {
ex.throw_to_java(env);
}
}
2 changes: 1 addition & 1 deletion examples/gradle-kt-dsl/lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
val accpVersion = "2.4.1"
val accpVersion = "2.5.0"
val accpLocalJar: String by project
val fips: Boolean by project
val PLATFORMS_WITHOUT_FIPS_SUPPORT = setOf("osx-x86_64", "osx-aarch_64")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
import static com.amazon.corretto.crypto.provider.ConcatenationKdfSpi.CKDF_WITH_SHA256;
import static com.amazon.corretto.crypto.provider.ConcatenationKdfSpi.CKDF_WITH_SHA384;
import static com.amazon.corretto.crypto.provider.ConcatenationKdfSpi.CKDF_WITH_SHA512;
import static com.amazon.corretto.crypto.provider.CounterKdfSpi.CNTRKDF_WITH_SHA256;
import static com.amazon.corretto.crypto.provider.CounterKdfSpi.CNTRKDF_WITH_SHA384;
import static com.amazon.corretto.crypto.provider.CounterKdfSpi.CNTRKDF_WITH_SHA512;
import static com.amazon.corretto.crypto.provider.HkdfSecretKeyFactorySpi.HKDF_WITH_SHA1;
import static com.amazon.corretto.crypto.provider.HkdfSecretKeyFactorySpi.HKDF_WITH_SHA256;
import static com.amazon.corretto.crypto.provider.HkdfSecretKeyFactorySpi.HKDF_WITH_SHA384;
Expand Down Expand Up @@ -94,12 +97,17 @@ private void buildServiceMap() {

// Once these KDFs are added to a FIPS branch of AWS-LC, we can remove this check.
if (!Loader.FIPS_BUILD) {
final String concatenationKdfSpi = "ConcatenationKdf";
final String concatenationKdfSpi = "ConcatenationKdfSpi";
addService("SecretKeyFactory", CKDF_WITH_SHA256, concatenationKdfSpi, false);
addService("SecretKeyFactory", CKDF_WITH_SHA384, concatenationKdfSpi, false);
addService("SecretKeyFactory", CKDF_WITH_SHA512, concatenationKdfSpi, false);
addService("SecretKeyFactory", CKDF_WITH_HMAC_SHA256, concatenationKdfSpi, false);
addService("SecretKeyFactory", CKDF_WITH_HMAC_SHA512, concatenationKdfSpi, false);

final String counterKdfSpi = "CounterKdfSpi";
addService("SecretKeyFactory", CNTRKDF_WITH_SHA256, counterKdfSpi, false);
addService("SecretKeyFactory", CNTRKDF_WITH_SHA384, counterKdfSpi, false);
addService("SecretKeyFactory", CNTRKDF_WITH_SHA512, counterKdfSpi, false);
}

addService("KeyPairGenerator", "RSA", "RsaGen");
Expand Down Expand Up @@ -330,6 +338,12 @@ public Object newInstance(final Object constructorParameter) throws NoSuchAlgori
if (ckdfSpi != null) {
return ckdfSpi;
}

final CounterKdfSpi cntrKdfSpi =
CounterKdfSpi.INSTANCES.get(CounterKdfSpi.getSpiFactoryForAlgName(algo));
if (cntrKdfSpi != null) {
return cntrKdfSpi;
}
}

if ("KeyGenerator".equalsIgnoreCase(type) && "AES".equalsIgnoreCase(algo)) {
Expand Down
54 changes: 54 additions & 0 deletions src/com/amazon/corretto/crypto/provider/CounterKdfSpec.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package com.amazon.corretto.crypto.provider;

import java.security.spec.KeySpec;
import java.util.Objects;

/**
* Represents the inputs to CounterKdfSpec algorithms.
*
* <p>If info is not provided, an empty byte array is used.
*
* <p>The algorithmName is the name of algorithm used to create SecretKeySpec.
*/
public class CounterKdfSpec implements KeySpec {
private final byte[] secret;
private final byte[] info;
private final int outputLen;
private final String algorithName;

public CounterKdfSpec(
final byte[] secret, final byte[] info, final int outputLen, final String algorithName) {
this.secret = Objects.requireNonNull(secret);
if (this.secret.length == 0) {
throw new IllegalArgumentException("Secret must be byte array with non-zero length.");
}
this.info = Objects.requireNonNull(info);
if (outputLen <= 0) {
throw new IllegalArgumentException("Output size must be greater than zero.");
}
this.outputLen = outputLen;
this.algorithName = Objects.requireNonNull(algorithName);
}

public CounterKdfSpec(final byte[] secret, final int outputLen, final String algorithName) {
this(secret, Utils.EMPTY_ARRAY, outputLen, algorithName);
}

public byte[] getSecret() {
return secret;
}

public byte[] getInfo() {
return info;
}

public int getOutputLen() {
return outputLen;
}

public String getAlgorithName() {
return algorithName;
}
}
66 changes: 66 additions & 0 deletions src/com/amazon/corretto/crypto/provider/CounterKdfSpi.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
package com.amazon.corretto.crypto.provider;

import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;

class CounterKdfSpi extends KdfSpi {
private final int digestCode;

CounterKdfSpi(final int digestCode) {
this.digestCode = digestCode;
}

@Override
protected SecretKey engineGenerateSecret(final KeySpec keySpec) throws InvalidKeySpecException {
if (!(keySpec instanceof CounterKdfSpec)) {
throw new InvalidKeySpecException("Expected a key spec of type CounterKdfSpec");
}
final CounterKdfSpec spec = (CounterKdfSpec) keySpec;

final byte[] secret = spec.getSecret();

final byte[] info = spec.getInfo();

final byte[] output = new byte[spec.getOutputLen()];

nKdf(digestCode, secret, secret.length, info, info.length, output, output.length);

return new SecretKeySpec(output, spec.getAlgorithName());
}

private static native void nKdf(
int digestCode,
byte[] secret,
int secretLen,
byte[] info,
int infoLen,
byte[] output,
int outputLen);

static final Map<String, CounterKdfSpi> INSTANCES = getInstances();

private static final String CNTR_KDF = "CounterKdf";
private static final String WITH_HMAC = "WithHmac";
static final String CNTRKDF_WITH_SHA256 = CNTR_KDF + WITH_HMAC + "SHA256";
static final String CNTRKDF_WITH_SHA384 = CNTR_KDF + WITH_HMAC + "SHA384";
static final String CNTRKDF_WITH_SHA512 = CNTR_KDF + WITH_HMAC + "SHA512";

private static Map<String, CounterKdfSpi> getInstances() {
final Map<String, CounterKdfSpi> kdfs = new HashMap<>();
kdfs.put(getSpiFactoryForAlgName(CNTRKDF_WITH_SHA256), new CounterKdfSpi(Utils.SHA256_CODE));
kdfs.put(getSpiFactoryForAlgName(CNTRKDF_WITH_SHA384), new CounterKdfSpi(Utils.SHA384_CODE));
kdfs.put(getSpiFactoryForAlgName(CNTRKDF_WITH_SHA512), new CounterKdfSpi(Utils.SHA512_CODE));
return Collections.unmodifiableMap(kdfs);
}

static String getSpiFactoryForAlgName(final String alg) {
return alg.toUpperCase();
}
}
Loading

0 comments on commit 65892ec

Please sign in to comment.