TooLazy
TooLazy

Reputation: 906

Android keypair generation

OpenSsl generates a private key in DER format with 118 bytes length. (openssl ecparam -genkey -name secp256k1 and so on).

In android KeyPairGenerator initialized like:

 KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "SC");
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            keyPairGenerator.initialize(spec, new SecureRandom());
            return keyPairGenerator.generateKeyPair();

returns a private key with a 144 length. But i need 118. Where is a difference? Is smh added in android implementation? How could i get 118 key length? Cannot find implementation to figure out.

Upvotes: 0

Views: 2190

Answers (2)

TooLazy
TooLazy

Reputation: 906

Found a way to do this. Generate key pair:

KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("ECDSA", "SC");
            ECGenParameterSpec spec = new ECGenParameterSpec("secp256k1");
            keyPairGenerator.initialize(spec, new SecureRandom());
           KeyPair kp =  keyPairGenerator.generateKeyPair();

Get private key bytes array:

byte[] privateK = kp.getPrivate();

Then convert private key to PKCS1:

 byte[] privBytes = privateKey.getEncoded();
            PrivateKeyInfo pkInfo = PrivateKeyInfo.getInstance(privBytes);
            ASN1Encodable encodable = pkInfo.parsePrivateKey();
            ASN1Primitive primitive = encodable.toASN1Primitive();
            byte[] privBytesEncoded =  primitive.getEncoded();

Upvotes: 2

President James K. Polk
President James K. Polk

Reputation: 41958

It's a little bit of good news/bad news. The good news is that the bytes you want are a subsequence of the bytes returned by PrivateKey.getEncoded(). The bad news is that there's no good way that I'm aware of to get at them. Well, there is one easy way: the bytes you want are always at the end of PrivateKey.getEncoded(), so if you know the length of the byte sequence is n (e.g. 118 in your example) then just take the last n bytes of PrivateKey.getEncoded().

A slightly harder way is to parse through the encoding using the Spongycastle/Bouncycastle ASN1 routines, as in the following snippet:

private static byte[] encodePrivateKey(PrivateKey privateKey) throws Exception{
    ASN1InputStream asn1InputStream = new ASN1InputStream(privateKey.getEncoded());
    ASN1Primitive asn1Primitive = asn1InputStream.readObject();
    DLSequence seq = (DLSequence) asn1Primitive;
    ASN1OctetString octetString = (ASN1OctetString) seq.getObjectAt(2);
    return octetString.getOctets();
}

I offer this as an example but I have to warn you that this is brittle: I haven't made any real effort to follow the PKCS#8 specification, I just eyeballed the ASN.1 structure to grab the bytes I knew were needed.

Upvotes: 0

Related Questions