Skip to content

Commit

Permalink
Merge pull request #671 from KostasTsiounis/eckeygen
Browse files Browse the repository at this point in the history
Add support for EC key generation using native OpenSSL library and restructure ECDH key agreement
  • Loading branch information
keithc-ca authored Jun 6, 2023
2 parents df57de3 + 8a7c6dd commit 8d28321
Show file tree
Hide file tree
Showing 10 changed files with 831 additions and 342 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ public class NativeCrypto {
public static final int SHA5_384 = 3;
public static final int SHA5_512 = 4;

/* Define constants for the EC field types. */
public static final int ECField_Fp = 0;
public static final int ECField_F2m = 1;

public static final long OPENSSL_VERSION_1_0_0 = 0x1_00_00_000L;
public static final long OPENSSL_VERSION_1_1_0 = 0x1_01_00_000L;
public static final long OPENSSL_VERSION_3_0_0 = 0x3_00_00_000L;
Expand Down Expand Up @@ -320,6 +324,15 @@ public final native int RSAEP(byte[] k,
long RSAPublicKey);

/* Native EC interfaces */
public final native int ECGenerateKeyPair(long key,
byte[] x,
int xLen,
byte[] y,
int yLen,
byte[] s,
int sLen,
int fieldType);

public final native int ECCreatePublicKey(long key,
byte[] x,
int xLen,
Expand All @@ -331,35 +344,21 @@ public final native int ECCreatePrivateKey(long key,
byte[] s,
int sLen);

public final native long ECEncodeGFp(byte[] a,
int aLen,
byte[] b,
int bLen,
byte[] p,
int pLen,
byte[] x,
int xLen,
byte[] y,
int yLen,
byte[] n,
int nLen,
byte[] h,
int hLen);

public final native long ECEncodeGF2m(byte[] a,
int aLen,
byte[] b,
int bLen,
byte[] p,
int pLen,
byte[] x,
int xLen,
byte[] y,
int yLen,
byte[] n,
int nLen,
byte[] h,
int hLen);
public final native long ECEncodeGF(int fieldType,
byte[] a,
int aLen,
byte[] b,
int bLen,
byte[] p,
int pLen,
byte[] x,
int xLen,
byte[] y,
int yLen,
byte[] n,
int nLen,
byte[] h,
int hLen);

public final native int ECDestroyKey(long key);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

/*
* ===========================================================================
* (c) Copyright IBM Corp. 2022, 2022 All Rights Reserved
* (c) Copyright IBM Corp. 2022, 2023 All Rights Reserved
* ===========================================================================
*/

Expand Down Expand Up @@ -62,12 +62,9 @@
*/
public final class NativeECDHKeyAgreement extends KeyAgreementSpi {

private static final NativeCrypto nativeCrypto = NativeCrypto.getNativeCrypto();
private static NativeCrypto nativeCrypto;
private static final boolean nativeCryptTrace = NativeCrypto.isTraceEnabled();

/* false if OPENSSL_NO_EC2M is defined, true otherwise */
private static final boolean nativeGF2m = nativeCrypto.ECNativeGF2m();

/* stores whether a curve is supported by OpenSSL (true) or not (false) */
private static final Map<String, Boolean> curveSupported = new ConcurrentHashMap<>();

Expand Down Expand Up @@ -106,35 +103,19 @@ protected void engineInit(Key key, SecureRandom random)
this.publicKey = null;

ECParameterSpec params = this.privateKey.getParams();
if (params instanceof NamedCurve) {
this.curve = ((NamedCurve) params).getName();
this.curve = NativeECUtil.getCurveName(params);
if ((this.curve != null) && NativeECUtil.isCurveSupported(this.curve, params)) {
this.javaImplementation = null;
} else {
/* use the OID */
try {
AlgorithmParameters algParams = AlgorithmParameters.getInstance("EC");
algParams.init(params);
this.curve = algParams.getParameterSpec(ECGenParameterSpec.class).getName();
} catch (InvalidParameterSpecException | NoSuchAlgorithmException e) {
/* should not happen */
throw new InternalError(e);
}
}

if ((!nativeGF2m) && this.privateKey.isECFieldF2m()) {
/* only print the first time a curve is used */
if ((curveSupported.putIfAbsent("EC2m", Boolean.FALSE) == null) && nativeCryptTrace) {
System.err.println("EC2m is not supported by OpenSSL, using Java crypto implementation.");
}
this.initializeJavaImplementation(key, random);
} else if (Boolean.FALSE.equals(curveSupported.get(this.curve))) {
this.initializeJavaImplementation(key, random);
} else {
this.javaImplementation = null;
}
} else {
if ((curveSupported.putIfAbsent("ECKeyImpl", Boolean.FALSE) == null) && nativeCryptTrace) {
System.err.println("Only ECPrivateKeyImpl and ECPublicKeyImpl are supported by the native implementation,"
+ " using Java crypto implementation.");
boolean absent = NativeECUtil.putCurveIfAbsent("ECKeyImpl", Boolean.FALSE);
/* only print the first time a curve is used */
if (absent && nativeCryptTrace) {
System.err.println("Only ECPrivateKeyImpl and ECPublicKeyImpl" +
" are supported by the native implementation, " +
"using Java crypto implementation for key agreement.");
}
this.initializeJavaImplementation(key, random);
}
Expand Down Expand Up @@ -180,9 +161,12 @@ protected Key engineDoPhase(Key key, boolean lastPhase)

return null;
} else {
if ((curveSupported.putIfAbsent("ECKeyImpl", Boolean.FALSE) == null) && nativeCryptTrace) {
System.err.println("Only ECPrivateKeyImpl and ECPublicKeyImpl are supported by the native implementation,"
+ " using Java crypto implementation.");
boolean absent = NativeECUtil.putCurveIfAbsent("ECKeyImpl", Boolean.FALSE);
/* only print the first time a curve is used */
if (absent && nativeCryptTrace) {
System.err.println("Only ECPrivateKeyImpl and ECPublicKeyImpl" +
" are supported by the native implementation, " +
"using Java crypto implementation for key agreement.");
}
this.initializeJavaImplementation(this.privateKey, null);
return this.javaImplementation.engineDoPhase(key, lastPhase);
Expand Down Expand Up @@ -210,22 +194,27 @@ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
if (this.javaImplementation != null) {
return this.javaImplementation.engineGenerateSecret(sharedSecret, offset);
}

boolean absent;
if ((offset + this.secretLen) > sharedSecret.length) {
throw new ShortBufferException("Need " + this.secretLen
+ " bytes, only " + (sharedSecret.length - offset)
+ " available");
+ " bytes, only " + (sharedSecret.length - offset)
+ " available");
}
if ((this.privateKey == null) || (this.publicKey == null)) {
throw new IllegalStateException("Not initialized correctly");
}
long nativePublicKey = this.publicKey.getNativePtr();
long nativePrivateKey = this.privateKey.getNativePtr();
if ((nativePublicKey == -1) || (nativePrivateKey == -1)) {
if (curveSupported.putIfAbsent(this.curve, Boolean.FALSE) != null) {
absent = NativeECUtil.putCurveIfAbsent(this.curve, Boolean.FALSE);
if (!absent) {
throw new ProviderException("Could not convert keys to native format");
}
/* only print the first time a curve is used */
if (nativeCryptTrace) {
System.err.println(this.curve + " is not supported by OpenSSL, using Java crypto implementation.");
System.err.println(this.curve +
" is not supported by OpenSSL, using Java crypto implementation for preparing agreement.");
}
try {
this.initializeJavaImplementation(this.privateKey, null);
Expand All @@ -236,10 +225,16 @@ protected int engineGenerateSecret(byte[] sharedSecret, int offset)
}
return this.javaImplementation.engineGenerateSecret(sharedSecret, offset);
}
if ((curveSupported.putIfAbsent(this.curve, Boolean.TRUE) == null) && nativeCryptTrace) {
System.err.println(this.curve + " is supported by OpenSSL, using native crypto implementation.");
absent = NativeECUtil.putCurveIfAbsent(this.curve, Boolean.TRUE);
if (absent && nativeCryptTrace) {
System.err.println(this.curve +
" is supported by OpenSSL, using native crypto implementation for generating secret.");
}

int ret;
if (nativeCrypto == null) {
nativeCrypto = NativeCrypto.getNativeCrypto();
}
synchronized (this.privateKey) {
ret = nativeCrypto.ECDeriveKey(nativePublicKey, nativePrivateKey, sharedSecret, offset, this.secretLen);
}
Expand Down
Loading

0 comments on commit 8d28321

Please sign in to comment.