Skip to content
Permalink
Browse files

8237218: Support NIST Curves verification in java implementation

Reviewed-by: ascarpino
  • Loading branch information
wangweij committed Feb 22, 2020
1 parent 2596e83 commit 533649b8ca0e3ad9e918fb3cb3fa8cf4e98387c8
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -34,6 +34,17 @@

public final class ECUtil {

// Used by SunEC
public static byte[] sArray(BigInteger s, ECParameterSpec params) {
byte[] arr = s.toByteArray();
ArrayUtil.reverse(arr);
int byteLength = (params.getOrder().bitLength() + 7) / 8;
byte[] arrayS = new byte[byteLength];
int length = Math.min(byteLength, arr.length);
System.arraycopy(arr, 0, arrayS, 0, length);
return arrayS;
}

// Used by SunPKCS11 and SunJSSE.
public static ECPoint decodePoint(byte[] data, EllipticCurve curve)
throws IOException {
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -32,6 +32,7 @@

import java.security.ProviderException;
import java.security.spec.*;
import java.util.Arrays;
import java.util.Optional;

public class ECDSAOperations {
@@ -164,10 +165,7 @@ public static AffinePoint toAffinePoint(ECPoint point,
IntegerModuloP r = R.asAffine().getX();
// put r into the correct field by fully reducing to an array
byte[] temp = new byte[length];
r.asByteArray(temp);
r = orderField.getElement(temp);
// store r in result
r.asByteArray(temp);
r = b2a(r, orderField, temp);
byte[] result = new byte[2 * length];
ArrayUtil.reverse(temp);
System.arraycopy(temp, 0, result, 0, length);
@@ -198,5 +196,68 @@ public static AffinePoint toAffinePoint(ECPoint point,
return result;

}
public boolean verifySignedDigest(byte[] digest, byte[] sig, ECPoint pp) {

IntegerFieldModuloP field = ecOps.getField();
IntegerFieldModuloP orderField = ecOps.getOrderField();
int length = (orderField.getSize().bitLength() + 7) / 8;

byte[] r;
byte[] s;

int encodeLength = sig.length / 2;
if (sig.length %2 != 0 || encodeLength > length) {
return false;
} else if (encodeLength == length) {
r = Arrays.copyOf(sig, length);
s = Arrays.copyOfRange(sig, length, length * 2);
} else {
r = new byte[length];
s = new byte[length];
System.arraycopy(sig, 0, r, length - encodeLength, encodeLength);
System.arraycopy(sig, encodeLength, s, length - encodeLength, encodeLength);
}

ArrayUtil.reverse(r);
ArrayUtil.reverse(s);
IntegerModuloP ri = orderField.getElement(r);
IntegerModuloP si = orderField.getElement(s);
// z
int lengthE = Math.min(length, digest.length);
byte[] E = new byte[lengthE];
System.arraycopy(digest, 0, E, 0, lengthE);
ArrayUtil.reverse(E);
IntegerModuloP e = orderField.getElement(E);

IntegerModuloP sInv = si.multiplicativeInverse();
ImmutableIntegerModuloP u1 = e.multiply(sInv);
ImmutableIntegerModuloP u2 = ri.multiply(sInv);

AffinePoint pub = new AffinePoint(field.getElement(pp.getAffineX()),
field.getElement(pp.getAffineY()));

byte[] temp1 = new byte[length];
b2a(u1, orderField, temp1);

byte[] temp2 = new byte[length];
b2a(u2, orderField, temp2);

MutablePoint p1 = ecOps.multiply(basePoint, temp1);
MutablePoint p2 = ecOps.multiply(pub, temp2);

ecOps.setSum(p1, p2.asAffine());
IntegerModuloP result = p1.asAffine().getX();
result = result.additiveInverse().add(ri);

b2a(result, orderField, temp1);
return ECOperations.allZero(temp1);
}

static public ImmutableIntegerModuloP b2a(IntegerModuloP b,
IntegerFieldModuloP orderField, byte[] temp1) {
b.asByteArray(temp1);
ImmutableIntegerModuloP b2 = orderField.getElement(temp1);
b2.asByteArray(temp1);
return b2;
}
}
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -374,13 +374,14 @@ private static boolean isCompatible(ECParameterSpec sigParams,
return ECUtil.equals(sigParams, keyParams);
}


private byte[] signDigestImpl(ECDSAOperations ops, int seedBits,
byte[] digest, ECPrivateKeyImpl privImpl, SecureRandom random)
byte[] digest, ECPrivateKey priv, SecureRandom random)
throws SignatureException {

byte[] seedBytes = new byte[(seedBits + 7) / 8];
byte[] s = privImpl.getArrayS();
byte[] s = priv instanceof ECPrivateKeyImpl
? ((ECPrivateKeyImpl)priv).getArrayS()
: ECUtil.sArray(priv.getS(), priv.getParams());

// Attempt to create the signature in a loop that uses new random input
// each time. The chance of failure is very small assuming the
@@ -401,13 +402,9 @@ private static boolean isCompatible(ECParameterSpec sigParams,
}


private Optional<byte[]> signDigestImpl(ECPrivateKey privateKey,
private Optional<byte[]> signDigestAvailable(ECPrivateKey privateKey,
byte[] digest, SecureRandom random) throws SignatureException {

if (! (privateKey instanceof ECPrivateKeyImpl)) {
return Optional.empty();
}
ECPrivateKeyImpl privImpl = (ECPrivateKeyImpl) privateKey;
ECParameterSpec params = privateKey.getParams();

// seed is the key size + 64 bits
@@ -418,7 +415,7 @@ private static boolean isCompatible(ECParameterSpec sigParams,
return Optional.empty();
} else {
byte[] sig = signDigestImpl(opsOpt.get(), seedBits, digest,
privImpl, random);
privateKey, random);
return Optional.of(sig);
}
}
@@ -461,7 +458,7 @@ private static boolean isCompatible(ECParameterSpec sigParams,
}

byte[] digest = getDigestValue();
Optional<byte[]> sigOpt = signDigestImpl(privateKey, digest, random);
Optional<byte[]> sigOpt = signDigestAvailable(privateKey, digest, random);
byte[] sig;
if (sigOpt.isPresent()) {
sig = sigOpt.get();
@@ -480,31 +477,60 @@ private static boolean isCompatible(ECParameterSpec sigParams,
@Override
protected boolean engineVerify(byte[] signature) throws SignatureException {

byte[] w;
ECParameterSpec params = publicKey.getParams();
// DER OID
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);

if (publicKey instanceof ECPublicKeyImpl) {
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
} else { // instanceof ECPublicKey
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
}

byte[] sig;
if (p1363Format) {
sig = signature;
} else {
sig = ECUtil.decodeSignature(signature);
}

try {
return verifySignedDigest(sig, getDigestValue(), w, encodedParams);
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not verify signature", e);
byte[] digest = getDigestValue();
Optional<Boolean> verifyOpt
= verifySignedDigestAvailable(publicKey, sig, digest);

if (verifyOpt.isPresent()) {
return verifyOpt.get();
} else {
byte[] w;
ECParameterSpec params = publicKey.getParams();
// DER OID
byte[] encodedParams = ECUtil.encodeECParameterSpec(null, params);

if (publicKey instanceof ECPublicKeyImpl) {
w = ((ECPublicKeyImpl) publicKey).getEncodedPublicValue();
} else { // instanceof ECPublicKey
w = ECUtil.encodePoint(publicKey.getW(), params.getCurve());
}

try {
return verifySignedDigest(sig, digest, w, encodedParams);
} catch (GeneralSecurityException e) {
throw new SignatureException("Could not verify signature", e);
}
}
}

private Optional<Boolean> verifySignedDigestAvailable(
ECPublicKey publicKey, byte[] sig, byte[] digestValue) {

ECParameterSpec params = publicKey.getParams();

Optional<ECDSAOperations> opsOpt =
ECDSAOperations.forParameters(params);
if (opsOpt.isEmpty()) {
return Optional.empty();
} else {
boolean result = verifySignedDigestImpl(opsOpt.get(), digestValue,
publicKey, sig);
return Optional.of(result);
}
}

private boolean verifySignedDigestImpl(ECDSAOperations ops,
byte[] digest, ECPublicKey pub, byte[] sig) {
return ops.verifySignedDigest(digest, sig, pub.getW());
}

// set parameter, not supported. See JCA doc
@Override
@Deprecated
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2006, 2020, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -153,12 +153,7 @@ public BigInteger getS() {

public byte[] getArrayS() {
if (arrayS == null) {
byte[] arr = getS().toByteArray();
ArrayUtil.reverse(arr);
int byteLength = (params.getOrder().bitLength() + 7) / 8;
arrayS = new byte[byteLength];
int length = Math.min(byteLength, arr.length);
System.arraycopy(arr, 0, arrayS, 0, length);
arrayS = ECUtil.sArray(getS(), params);
}
return arrayS.clone();
}

0 comments on commit 533649b

Please sign in to comment.