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");


  }

Reply via email to