ricmoo / GMEllipticCurveCrypto

Elliptic Curve Cryptography library for iOS (ECDSA and ECDH)
BSD 2-Clause "Simplified" License
122 stars 46 forks source link

Add support for DER encoded keys #9

Open ricmoo opened 9 years ago

ricmoo commented 9 years ago

A lot of people use Java on their server side, which stores keys DER encoded.

It should be fairly simple to add ASN.1 identifiers and bit strings to the DER decoder. I do need to research what various identifiers Java will use to specify the payload though.

user454322 commented 9 years ago

In the meantime, how can I use keys generated by Bouncy Castle in GMEllipticCurveCrypto?

ricmoo commented 9 years ago

Here is a quick example. I'm not really a Java guy, so I'm dumping it out as a hex encoded string to make it easier to see what you get, but it should be fairly simple to adapt to your needs... (i.e. base64 or binary)

import java.math.BigInteger;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.ECPoint;
import java.security.spec.EllipticCurve;
import org.bouncycastle.jce.ECNamedCurveTable;
import org.bouncycastle.jce.spec.ECParameterSpec;

public class KeyEncoder {

    final protected static char[] hexArray = "0123456789ABCDEF".toCharArray();

    private static String numberToString(BigInteger value, int size) {
        byte bytes[] = value.toByteArray();

        // Initialize the output with 0's
        char output[] = new char[size * 2];
        for (int i = 0; i < size * 2; i++) {
            output[i] = '0';
        }

        // Place the number in the output right-aligned
        int back = output.length - 1;
        for (int i = bytes.length - 1; i >= 0; i--) {
            if (back < 1) { break; }
            int v = bytes[i] & 0xFF;
            output[back--] = hexArray[v & 0x0F];
            output[back--] = hexArray[v >>> 4];
        }

        return new String(output);
    }

    public static String encodePublicKey(ECPublicKey publicKey) {
        int bits = publicKey.getParams().getCurve().getField().getFieldSize();

        ECPoint point = publicKey.getW();
        String x = numberToString(point.getAffineX(), bits / 8);
        String y = numberToString(point.getAffineY(), bits / 8);

        return "04" + x + y;
    }

    public static String encodePrivateKey(ECPrivateKey privateKey) {
        int bits = privateKey.getParams().getCurve().getField().getFieldSize();
        return numberToString(privateKey.getS(), bits / 8);
    }

    public static KeyPair generate(String name) throws Exception {
        ECParameterSpec ecSpec = ECNamedCurveTable.getParameterSpec(name);
        KeyPairGenerator g = KeyPairGenerator.getInstance("ECDSA", "BC");
        g.initialize(ecSpec, new SecureRandom());
        return g.generateKeyPair();
    }

    public static void main(String[] argv) {
        Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
        KeyPair pair;
        try {
            pair = generate("secp128r1");
            System.out.println("secp128k1 pub: " + encodePublicKey((ECPublicKey)(pair.getPublic())));
            System.out.println("secp128k1 priv: " + encodePrivateKey((ECPrivateKey)(pair.getPrivate())));

            pair = generate("secp192r1");
            System.out.println("secp192k1 pub: " + encodePublicKey((ECPublicKey)(pair.getPublic())));
            System.out.println("secp192k1 priv: " + encodePrivateKey((ECPrivateKey)(pair.getPrivate())));

            pair = generate("secp256r1");
            System.out.println("secp256k1 pub: " + encodePublicKey((ECPublicKey)(pair.getPublic())));
            System.out.println("secp256k1 priv: " + encodePrivateKey((ECPrivateKey)(pair.getPrivate())));

            pair = generate("secp384r1");
            System.out.println("secp384k1 pub: " + encodePublicKey((ECPublicKey)(pair.getPublic())));
            System.out.println("secp384k1 priv: " + encodePrivateKey((ECPrivateKey)(pair.getPrivate())));

        } catch (Exception e) {
            System.out.println(e);

        }
    }
}
user454322 commented 9 years ago

Thanks!

It is working now.

This is what I'm doing:

System.out.println("private:" + BaseEncoding.base64().encode(
                        Crypto.encodePrivateKey(keyPair.getPrivate())
                        ));

System.out.println("public:" + BaseEncoding.base64().encode(
                        Crypto.encodePublicKey(keyPair.getPublic())
                        ));

which produces something like:

private:gPMSvSgCTuwdDKETYHwhIUYeGsa+aMTF5A7zndqgVR4= public:BKw6bRNWHpjZ/jq8vSUAwEEOHCWeKClN6GUlBT1qIOlL7Ya2C8vngYhqj1f906JZHN5jlIpD9TPN5hwQThlIKpA=

  • Then in Objective-C
GMEllipticCurveCrypto *keyPair = [GMEllipticCurveCrypto cryptoForKeyBase64:@"BKw6bRNWHpjZ/jq8vSUAwEEOHCWeKClN6GUlBT1qIOlL7Ya2C8vngYhqj1f906JZHN5jlIpD9TPN5hwQThlIKpA="];
keyPair.privateKeyBase64 = @"gPMSvSgCTuwdDKETYHwhIUYeGsa+aMTF5A7zndqgVR4=";
fullfiction commented 7 years ago

Hello there,

pls give me some example how can I generate keypair, send public to server in DER format and verify it with BC

passuf commented 6 years ago

Hi everyone,

Is there any update on this? I am currently trying to export the public key in DER format.

Thanks for any input!