Skip to content

Instantly share code, notes, and snippets.

@pavlo
Created November 22, 2016 14:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save pavlo/0a3089029f047e509a1e4c8a42f809e3 to your computer and use it in GitHub Desktop.
Save pavlo/0a3089029f047e509a1e4c8a42f809e3 to your computer and use it in GitHub Desktop.
package com.foo;
import sun.security.ec.ECPrivateKeyImpl;
import sun.security.ec.ECPublicKeyImpl;
import javax.crypto.KeyAgreement;
import java.math.BigInteger;
import java.security.*;
import java.security.interfaces.ECPrivateKey;
import java.security.interfaces.ECPublicKey;
import java.security.spec.*;
import static javax.xml.bind.DatatypeConverter.printHexBinary;
import static javax.xml.bind.DatatypeConverter.parseHexBinary;
// iOS - https://github.com/ricmoo/GMEllipticCurveCrypto?
// C - https://github.com/esxgx/easy-ecc
// NodeJS - https://github.com/indutny/elliptic
// Java - http://connect2id.com/products/nimbus-jose-jwt
public class ECCStuff {
private static final String DS_PUBLIC_KEY_X509 = "3059301306072A8648CE3D020106082A8648CE3D030107034200049ECCEB1FB448414F9C9AFF4F5734005A2A63D568ED48725B024CD9B715ACCA6600FB9AF5635B67BB419EBCD635E71ED7079D341502C14DDF74C3AE4054E0CD70";
private static final String DS_PRIVATE_KEY_PKCS8 = "3041020100301306072A8648CE3D020106082A8648CE3D030107042730250201010420CC309591D17EBF867DCB803E6A9561C30692A0971B108D75AA0D8ECC61D5CC7C";
private static final String DS_PUBLIC_KEY_X = "71827489642506658763456034709171400250620549744728167720189312821359981415014";
private static final String DS_PUBLIC_KEY_Y = "444548097847232459367223840555011063388349913266591690778394366523838877040";
private static final String DS_PRIVATE_KEY = "92357662061556054328491863583938855342013559809943355423498537461705352793212";
private static final String SDK_PUBLIC_KEY_X509 = "3059301306072A8648CE3D020106082A8648CE3D030107034200040B1C126D81DA304FB874F75EC78EFA849996FD9021B1F10CF1029E2368C4AA26DD0174E3D53ECF17E52ACD066048A88852CE356E835C9800F5320DC5AD92B66C";
private static final String SDK_PRIVATE_KEY_PKCS8 = "3041020100301306072A8648CE3D020106082A8648CE3D03010704273025020101042036744775F4184AE94F2598D9FB918D5F841F8BF66DD54429C962728144BD45CF";
private static final String SDK_PUBLIC_KEY_X = "5025040235973197239960723894005321281855226418603980498414503140147262171686";
private static final String SDK_PUBLIC_KEY_Y = "99963713128908127595637622677267196565662543684710841894296137816645752239724";
private static final String SDK_PRIVATE_KEY = "24630341287021252313437466753111713222299261312837557397825311892032817284559";
// This stands for Content Encryption Key in JWA spec - is a product of key exchange, see exchange() method below
private static final String CEK = "3CE3782643528C8B553720252153B741C19590799B5A0E186EE26232ACDED5D8";
public static void main(String[] args) throws Exception {
// ECCStuff.generateEcKeys();
// ECCStuff.validatePublicKey(DS_PUBLIC_KEY_X509);
// System.out.println("----------------------------------------------");
// ECCStuff.validatePrivateKey(DS_PRIVATE_KEY_PKCS8);
//
// System.out.println("----------------------------------------------");
// System.out.println("----------------------------------------------");
// ECCStuff.validatePublicKey(SDK_PUBLIC_KEY_X509);
// System.out.println("----------------------------------------------");
// ECCStuff.validatePrivateKey(SDK_PRIVATE_KEY_PKCS8);
exchange();
}
// partially based up on https://neilmadden.wordpress.com/2016/05/20/ephemeral-elliptic-curve-diffie-hellman-key-agreement-in-java/
private static void exchange() throws Exception {
KeyFactory keyFactory = java.security.KeyFactory.getInstance("EC"); //ECDH
byte[] sdkPrivateKeyBytes = parseHexBinary(SDK_PRIVATE_KEY_PKCS8);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(sdkPrivateKeyBytes);
ECPrivateKey skdPrivateKey = (ECPrivateKey) keyFactory.generatePrivate(keySpec);
byte[] dsPublicKeyBytes = parseHexBinary(DS_PUBLIC_KEY_X509);
X509EncodedKeySpec dsPublicKeySpec = new X509EncodedKeySpec(dsPublicKeyBytes);
ECPublicKey dsPublicKey = (ECPublicKey) keyFactory.generatePublic(dsPublicKeySpec);
KeyAgreement ka = KeyAgreement.getInstance("ECDH");
ka.init(skdPrivateKey);
ka.doPhase(dsPublicKey, /* the last phase in the agreement? */ true);
byte[] sharedSecret = ka.generateSecret();
System.out.println("Shared secret: " + printHexBinary(sharedSecret));
// TODO:
// The security considerations section of RFC 7748 advises to derive a key
// from the shared secret plus both public keys if we intend to use
// the key for authentication
// Designers using these curves should be aware that for each public
// key, there are several publicly computable public keys that are
// equivalent to it, i.e., they produce the same shared secrets. Thus
// using a public key as an identifier and knowledge of a shared secret
// as proof of ownership (without including the public keys in the key
// derivation) might lead to subtle vulnerabilities.
}
private static void generateEcKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC", "SunEC");
ECGenParameterSpec ecSpec = new ECGenParameterSpec("secp256r1"); // I am not quite sure here but it looks like it
kpg.initialize(ecSpec);
KeyPair keyPair = kpg.genKeyPair();
PrivateKey privateKey = keyPair.getPrivate();
PublicKey publicKey = keyPair.getPublic();
byte[] encodedPublicKey = publicKey.getEncoded(); // X.509
byte[] encodedPrivateKey = privateKey.getEncoded(); // PKCS8
// Display our public key
System.out.println("Encoded public key: " + printHexBinary(encodedPublicKey));
System.out.println("Encoded private key: " + printHexBinary(encodedPrivateKey));
System.out.println("Private Key as BigInteger: " + ((ECPrivateKeyImpl) privateKey).getS()); // an integer
BigInteger x = ((ECPublicKeyImpl) publicKey).getW().getAffineX();
BigInteger y = ((ECPublicKeyImpl) publicKey).getW().getAffineY();
System.out.println("Public Key X/Y: " + x + "/" + y); // x and y on the curve
}
// just to make sure we encode and decode the keys properly
private static void validatePublicKey(String keyString) throws Exception {
byte[] keyBytes = parseHexBinary(keyString);
X509EncodedKeySpec key = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = java.security.KeyFactory.getInstance("EC"); //ECDH
ECPublicKey publicKey = (ECPublicKey) kf.generatePublic(key);
System.out.println("X: " + publicKey.getW().getAffineX());
System.out.println("Y: " + publicKey.getW().getAffineY());
}
private static void validatePrivateKey(String keyString) throws Exception {
byte[] keyBytes = parseHexBinary(keyString);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
KeyFactory kf = java.security.KeyFactory.getInstance("EC"); //ECDH
ECPrivateKey pk = (ECPrivateKey) kf.generatePrivate(keySpec);
System.out.println("S: " + pk.getS());
}
}
@vitolipari
Copy link

I have a public key generated from javascript, i send the (xy) hex rappresentation of that, but i have an error:

curve:    secp256r1

javascript
---------------------------------------
privatekey:    515E72BE296D46472C 
publickey:    b9da7fc09a35f0dece3d9152ac10c032c4fcc26e562f0af1af872f10a81779d7033ce823d464f7529c707c3a36de32f364707a21ecba591e0df4ec6832be7777

java
--------------------------------------
error:    java.security.spec.InvalidKeySpecException: encoded key spec not recognized: failed to construct sequence from byte[]: DER length more than 4 bytes: 90

Why i get this error?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment