Java compact representation of ECC PublicKey

后端 未结 4 1408
没有蜡笔的小新
没有蜡笔的小新 2021-01-06 08:30

java.security.PublicKey#getEncoded() returns X509 representation of key which in case of ECC adds a lot of overhead compared to raw ECC values.

I\'d lik

4条回答
  •  伪装坚强ぢ
    2021-01-06 09:15

    This functionality is also present in Bouncy Castle, but I'll show how to go through this using just Java in case somebody needs it:

    import java.math.BigInteger;
    import java.security.KeyFactory;
    import java.security.KeyPair;
    import java.security.KeyPairGenerator;
    import java.security.interfaces.ECPublicKey;
    import java.security.spec.ECParameterSpec;
    import java.security.spec.ECPoint;
    import java.security.spec.ECPublicKeySpec;
    import java.util.Arrays;
    
    public class Curvy {
    
        private static final byte UNCOMPRESSED_POINT_INDICATOR = 0x04;
    
        public static ECPublicKey fromUncompressedPoint(
                final byte[] uncompressedPoint, final ECParameterSpec params)
                throws Exception {
    
            int offset = 0;
            if (uncompressedPoint[offset++] != UNCOMPRESSED_POINT_INDICATOR) {
                throw new IllegalArgumentException(
                        "Invalid uncompressedPoint encoding, no uncompressed point indicator");
            }
    
            int keySizeBytes = (params.getOrder().bitLength() + Byte.SIZE - 1)
                    / Byte.SIZE;
    
            if (uncompressedPoint.length != 1 + 2 * keySizeBytes) {
                throw new IllegalArgumentException(
                        "Invalid uncompressedPoint encoding, not the correct size");
            }
    
            final BigInteger x = new BigInteger(1, Arrays.copyOfRange(
                    uncompressedPoint, offset, offset + keySizeBytes));
            offset += keySizeBytes;
            final BigInteger y = new BigInteger(1, Arrays.copyOfRange(
                    uncompressedPoint, offset, offset + keySizeBytes));
            final ECPoint w = new ECPoint(x, y);
            final ECPublicKeySpec ecPublicKeySpec = new ECPublicKeySpec(w, params);
            final KeyFactory keyFactory = KeyFactory.getInstance("EC");
            return (ECPublicKey) keyFactory.generatePublic(ecPublicKeySpec);
        }
    
        public static byte[] toUncompressedPoint(final ECPublicKey publicKey) {
    
            int keySizeBytes = (publicKey.getParams().getOrder().bitLength() + Byte.SIZE - 1)
                    / Byte.SIZE;
    
            final byte[] uncompressedPoint = new byte[1 + 2 * keySizeBytes];
            int offset = 0;
            uncompressedPoint[offset++] = 0x04;
    
            final byte[] x = publicKey.getW().getAffineX().toByteArray();
            if (x.length <= keySizeBytes) {
                System.arraycopy(x, 0, uncompressedPoint, offset + keySizeBytes
                        - x.length, x.length);
            } else if (x.length == keySizeBytes + 1 && x[0] == 0) {
                System.arraycopy(x, 1, uncompressedPoint, offset, keySizeBytes);
            } else {
                throw new IllegalStateException("x value is too large");
            }
            offset += keySizeBytes;
    
            final byte[] y = publicKey.getW().getAffineY().toByteArray();
            if (y.length <= keySizeBytes) {
                System.arraycopy(y, 0, uncompressedPoint, offset + keySizeBytes
                        - y.length, y.length);
            } else if (y.length == keySizeBytes + 1 && y[0] == 0) {
                System.arraycopy(y, 1, uncompressedPoint, offset, keySizeBytes);
            } else {
                throw new IllegalStateException("y value is too large");
            }
    
            return uncompressedPoint;
        }
    
        public static void main(final String[] args) throws Exception {
    
            // just for testing
    
            final KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
            kpg.initialize(163);
    
            for (int i = 0; i < 1_000; i++) {
                final KeyPair ecKeyPair = kpg.generateKeyPair();
    
                final ECPublicKey ecPublicKey = (ECPublicKey) ecKeyPair.getPublic();
                final ECPublicKey retrievedEcPublicKey = fromUncompressedPoint(
                        toUncompressedPoint(ecPublicKey), ecPublicKey.getParams());
                if (!Arrays.equals(retrievedEcPublicKey.getEncoded(),
                        ecPublicKey.getEncoded())) {
                    throw new IllegalArgumentException("Whoops");
                }
            }
        }
    }
    

提交回复
热议问题