package org.uic.barcode.test; import java.math.BigInteger; import java.security.InvalidAlgorithmParameterException; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.Provider; import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; import java.security.interfaces.ECPublicKey; import java.security.spec.ECGenParameterSpec; import java.util.Arrays; import org.bouncycastle.asn1.sec.SECNamedCurves; import org.bouncycastle.asn1.x9.ECNamedCurveTable; import org.bouncycastle.asn1.x9.X9ECParameters; import org.bouncycastle.crypto.generators.ECKeyPairGenerator; import org.bouncycastle.crypto.params.ECDomainParameters; import org.bouncycastle.crypto.params.ECKeyGenerationParameters; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.math.ec.ECCurve; import org.bouncycastle.math.ec.ECPoint; import org.bouncycastle.util.encoders.Hex; import org.junit.Before; import org.junit.Test; import org.uic.barcode.utils.AlgorithmNameResolver; import org.uic.barcode.utils.ECKeyEncoder; public class ECKeyEncoderTest { public static Provider provider = null; @Before public void initialize() { provider = new BouncyCastleProvider(); Security.addProvider(provider); } @Test public void testEncodeCompressed() throws Exception { for (int i = 0; i < 10; i++) { String name = "secp256k1"; AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); ECPublicKey key = createECPublicKey(name); // some additional encoding tricks byte[] compressedBC = getCompressed(key,name); String compressedHexBC = Hex.toHexString(compressedBC); byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_COMPRESSED); String compressedHex = Hex.toHexString(publicKeyBytes); if (!compressedHexBC.equals(compressedHex)) { assert(compressedHexBC.equals(compressedHex)); } assert(Arrays.equals(compressedBC, publicKeyBytes)); assert(compressedHexBC.equals(compressedHex)); } } @Test public void testDecodeCompressed() throws Exception { for (int i = 0; i < 10; i++) { String name = "secp256k1"; AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); ECPublicKey key = createECPublicKey(name); // some additional encoding tricks byte[] compressedBC = getCompressed(key,name); //String compressedHex = Hex.toHexString(compressedBC); PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider); compareKeys((ECPublicKey) publicKey, key); } } @Test public void testEncodeUnCompressed() throws Exception { for (int i = 0; i < 10; i++) { String name = "secp256k1"; AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); ECPublicKey key = createECPublicKey(name); byte[] uncompressedBC = getUnCompressed(key,name); //String uncompressedHex = Hex.toHexString(uncompressedBC); byte[] publicKeyUnComp = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X962_UNCOMPESSED); assert(Arrays.equals(uncompressedBC, publicKeyUnComp)); } } @Test public void testDecodeUnCompressed() throws Exception { for (int i = 0; i < 10; i++) { String name = "secp256k1"; AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); ECPublicKey key = createECPublicKey(name); // some additional encoding tricks byte[] compressedBC = getUnCompressed(key,name); //String compressedHex = Hex.toHexString(compressedBC); PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider); compareKeys((ECPublicKey) publicKey, key); } } @Test public void testEncodeX509() throws Exception { for (int i = 0; i < 10; i++) { String name = "secp256k1"; AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); ECPublicKey key = createECPublicKey(name); byte[] publicKeyBcX509 = key.getEncoded(); byte[] publicKeyBytes = ECKeyEncoder.getEncoded(key, ECKeyEncoder.ENCODING_X509); assert(Arrays.equals(publicKeyBcX509, publicKeyBytes)); } } @Test public void testDecodeX509() throws Exception { for (int i = 0; i < 10; i++) { String name = "secp256k1"; AlgorithmNameResolver.addMap(AlgorithmNameResolver.TYPE_KEY_GENERATOR_ALG, "1.3.132.0.10", "EC"); ECPublicKey key = createECPublicKey(name); // some additional encoding tricks byte[] compressedBC = key.getEncoded(); //String compressedHex = Hex.toHexString(compressedBC); PublicKey publicKey = ECKeyEncoder.fromEncoded(compressedBC, "1.3.132.0.10", provider); compareKeys((ECPublicKey) publicKey, key); } } private ECPublicKey createECPublicKey(String name) throws NoSuchAlgorithmException, NoSuchProviderException, InvalidAlgorithmParameterException { ECKeyPairGenerator gen = new ECKeyPairGenerator(); SecureRandom secureRandom = new SecureRandom(); X9ECParameters secnamecurves = SECNamedCurves.getByName(name); ECDomainParameters ecParams = new ECDomainParameters(secnamecurves.getCurve(), secnamecurves.getG(), secnamecurves.getN(), secnamecurves.getH()); ECKeyGenerationParameters keyGenParam = new ECKeyGenerationParameters(ecParams, secureRandom); gen.init(keyGenParam); KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "BC"); ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec("secp256k1"); kpg.initialize(ecGenParameterSpec); ECPublicKey key = (ECPublicKey) kpg.generateKeyPair().getPublic(); return key; } private byte[] getCompressed(ECPublicKey key, String name) { byte[] x = key.getW().getAffineX().toByteArray(); byte[] y = key.getW().getAffineY().toByteArray(); // assumes that x and y are (unsigned) big endian encoded BigInteger xbi = new BigInteger(1, x); BigInteger ybi = new BigInteger(1, y); X9ECParameters x9 = ECNamedCurveTable.getByName(name); ECCurve curve = x9.getCurve(); ECPoint point = curve.createPoint(xbi, ybi); return point.getEncoded(true); } private byte[] getUnCompressed(ECPublicKey key, String name) { byte[] x = key.getW().getAffineX().toByteArray(); byte[] y = key.getW().getAffineY().toByteArray(); // assumes that x and y are (unsigned) big endian encoded BigInteger xbi = new BigInteger(1, x); BigInteger ybi = new BigInteger(1, y); X9ECParameters x9 = ECNamedCurveTable.getByName(name); ECCurve curve = x9.getCurve(); ECPoint point = curve.createPoint(xbi, ybi); return point.getEncoded(false); } private void compareKeys(ECPublicKey key1, ECPublicKey key2) { assert(key1.getW().getAffineX().equals(key2.getW().getAffineX()) ); assert(key1.getW().getAffineY().equals(key2.getW().getAffineY()) ); } }