in src/main/java/com/amazonaws/encryptionsdk/internal/TrailingSignatureAlgorithm.java [135:178]
public PublicKey decompressPublicKey(final byte[] decodedKey) {
notNull(decodedKey, "decodedKey is required");
final BigInteger x = new BigInteger(1, Arrays.copyOfRange(decodedKey, 1, decodedKey.length));
final byte compressedY = decodedKey[0];
final BigInteger yOrder;
if (compressedY == TWO.byteValue()) {
yOrder = ZERO;
} else if (compressedY == THREE.byteValue()) {
yOrder = ONE;
} else {
throw new IllegalArgumentException("Compressed y value was invalid");
}
final BigInteger p = ((ECFieldFp) ecParameterSpec.getCurve().getField()).getP();
final BigInteger a = ecParameterSpec.getCurve().getA();
final BigInteger b = ecParameterSpec.getCurve().getB();
// alpha must be equal to y^2, this is validated below
final BigInteger alpha = x.modPow(THREE, p).add(a.multiply(x).mod(p)).add(b).mod(p);
final BigInteger beta;
if (p.mod(FOUR).equals(THREE)) {
beta = alpha.modPow(p.add(ONE).divide(FOUR), p);
} else {
throw new IllegalArgumentException("Curve not supported at this time");
}
final BigInteger y = beta.mod(TWO).equals(yOrder) ? beta : p.subtract(beta);
// Validate that Y is a root of Y^2 to prevent invalid point attacks
if (!alpha.equals(y.modPow(TWO, p))) {
throw new IllegalArgumentException("Y was invalid");
}
try {
return KeyFactory.getInstance(ELLIPTIC_CURVE_ALGORITHM)
.generatePublic(new ECPublicKeySpec(new ECPoint(x, y), ecParameterSpec));
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
throw new IllegalStateException("Invalid algorithm", e);
}
}