On 2/28/2020 3:05 PM, Michael StJohns wrote:
Sorry - running behind on this thread.
In ECUtil.decodePoint(),
Since this code is open, I'm wondering if it might be useful to add
the checks specified in NIST SP800-186 Appendix D.1. or SP800-56Ar1
5.6.2.3 E.g.
D.1.2 Montgomery Curves
D.1.2.1 Partial Public Key Validation
Inputs:
1. Montgomery curve MA,B defined over the prime field GF(p)
2. Point Q=(u, v) 1712
Output: ACCEPT or REJECT Q as an affine point on MA,B.
Process:
1. If Q is the point at infinity ∅, output REJECT.
2. Verify that both u and v are integers in the interval [0, p−1].
Output REJECT if verification fails.
3. Verify that (u, v) is a point on the MA,B by checking that (u, v)
satisfies the defining equation v2 = u (u2 + A u + 1) where
computations are carried out in GF(p). Output REJECT if verification
fails.
4. Otherwise output ACCEPT.
D.1.2.2 Full Public Key Validation
Inputs:
1. Montgomery curve MA,B defined over the prime field GF(p)
2. Point Q
Output: ACCEPT or REJECT Q as a point on MA,B of order n.
Process:
1. Perform partial public key validation on Q using the procedure of
Appendix D.1.2.1. Output REJECT if this procedure outputs REJECT.
2. Verify that n Q = ∅. Output REJECT if verification fails.
3. Otherwise output ACCEPT.
This mainly ensures that the X/Y provided is actually a point on the
curve. The threat to receiving a bad public key is more on the ECDH
side, but this appears to be the code that would need to be modified
so...
Later, Mike
Here's the function I use in my application code - the last check
(needed for full verification) uses BouncyCastle as I didn't have access
to the internal methods in the SunEC provider. Would have to be
refactored slightly to be used in ECUtil.decodePoint().
/**
* This function performs the checks described in NIST SP800-56A,
* section 5.6.2.5 over an ECPublicKey. It throws a
* GeneralSecurityException if the key does not validate
*
* @param k the key to validate
*
* @throws InvalidKeyException if the key is invalid
*/
public static void checkECPublicKey (ECPublicKey k)
throws InvalidKeyException {
// Step 0 - not in the SP document, but we don't support F2M
// curves
if (!((k.getParams().getCurve().getField()) instanceof ECFieldFp)) {
throw new InvalidKeyException ("ECPublicKey is not on a Prime
Curve - not supported");
}
ECPoint point = k.getW();
// Step 1:
if (point.equals(ECPoint.POINT_INFINITY)) {
throw new InvalidKeyException ("ECPublic key is point at Infinity");
}
// Step 2:
EllipticCurve curve = k.getParams().getCurve();
BigInteger p = ((ECFieldFp)curve.getField()).getP();
BigInteger x = point.getAffineX();
BigInteger y = point.getAffineY();
if (x.compareTo(BigInteger.ZERO) <= 0 || x.compareTo(p) >= 0)
throw new InvalidKeyException ("ECPublicKey X out of Range");
if (y.compareTo(BigInteger.ZERO) <= 0 || y.compareTo(p) >= 0)
throw new InvalidKeyException ("ECPublicKey Y out of Range");
// Step 3:
BigInteger y2 = y.pow(2).mod(p);
BigInteger x3 = x.pow(3);
BigInteger ax = curve.getA().multiply(x);
BigInteger sum = x3.add(ax).add(curve.getB()).mod(p);
if (!y2.equals(sum))
throw new InvalidKeyException ("ECPublicKey Point is not on Curve");
// Step 4: check nQ == INFINITY
BigInteger n = k.getParams().getOrder();
org.bouncycastle.math.ec.ECPoint bcPoint =
// EC5Util.convertPoint(k.getParams(), point, false); A/O 1.64
EC5Util.convertPoint(k.getParams(), point);
org.bouncycastle.math.ec.ECPoint testPoint =
bcPoint.multiply(n);
if (!testPoint.isInfinity())
throw new InvalidKeyException ("ECPublicKey invalid order");
}