Friday, 2 August 2019

Derive Shared Secret From ECDH with existing foreign public key

Im converting a method from nodeSJ to Java, but im having trouble getting it to work. Im stuck trying to calculate a derived shared secret.

Hoping someone can catch what im doing wrong porting over the nodeJS to Java.

NodeJS code:

 //the public_key param here is from a different device. 
 sign: function(public_key)
    {
        //dummy values 
        var PRE_SALT_VALUE = 'f0f0f0f0f0';
        var POST_SALT_VALUE = '0101010101';

        const crypto = require('crypto');
        var sha512 = crypto.createHash("sha512");

        var EC = require('elliptic').ec;
        var ec = new EC('p256');

        // Generate keys
        var key1 = ec.genKeyPair(); //key1 is gen before pub key
        var key2 = ec.keyFromPublic(public_key, 'hex') //pub key gen from saved cert

        var derived_secret = key1.derive(key2.getPublic()); 
        var derived_secret = Buffer.from(derived_secret.toString(16), 'hex')

        var public_key_client = key1.getPublic('hex') 

        var pre_salt = Buffer.from(PRE_SALT_VALUE, 'hex')
        var post_salt = Buffer.from(POST_SALT_VALUE, 'hex')

        derived_secret = Buffer.from(pre_salt.toString('hex')+derived_secret.toString('hex')+post_salt.toString('hex'), 'hex') // finalyze shared secret 
        // Hash shared secret
        var sha = sha512.update(derived_secret);
        derived_secret = sha.digest();

        return {
            public_key: public_key_client.toString('hex').slice(2), //anyone know why we drop the first byte here?
            secret: derived_secret.toString('hex')  
        }
    }

In progress Java Code:

        //load cert from pem string (passed in from file), foreign cert
        ByteArrayInputStream input = new ByteArrayInputStream(pem);
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        Certificate cert = cf.generateCertificate(input);
        X509Certificate x509Cert = (X509Certificate) cert;

        // get pub key from cert
        PublicKey publicKeyForSignature = x509Cert.getPublicKey();

        // Generate ephemeral ECDH keypair KEY1
        KeyPairGenerator kpg = KeyPairGenerator.getInstance("EC");
        kpg.initialize(256);
        KeyPair kp1 = kpg.generateKeyPair();
        byte[] ourPk = kp1.getPublic().getEncoded(); //use this later

        //load KEY2 from others public key
        KeyFactory kf = KeyFactory.getInstance("EC");
        X509EncodedKeySpec pkSpec = new X509EncodedKeySpec(publicKeyForSignature.getEncoded());
        PublicKey otherPublicKey = kf.generatePublic(pkSpec);

        // Perform key agreement
        KeyAgreement ka = KeyAgreement.getInstance("ECDH");
        ka.init(kp1.getPrivate());
        ka.doPhase(otherPublicKey, true);

        // Read shared secret
        byte[] sharedSecret = ka.generateSecret();

        // Derive a key from the shared secret and both salt keys
        MessageDigest hash = MessageDigest.getInstance("SHA-512");
        hash.update(Util.PRE_SALT_VALUE);
        hash.update(sharedSecret);
        hash.update(Util.POST_SALT_VALUE);

        byte[] derivedKey = hash.digest();

        ... etc, derivedKey = secret returned in JS method, ourPk = public_key returned in JS method. 

One thing i notice is that the public/private keys generated from nodejs vs java are different sizes? 65 bytes in node an 91 bytes in java. No idea why that would happen.

What stands out as wrong here?

Thanx

Edit:

So basically, I just need to know how to do this in Java

 var EC = require('elliptic').ec;
 var ec = new EC('p256');
 // Generate keys
 var key1 = ec.genKeyPair();
 var key2 = ec.keyFromPublic(public_key, 'hex') //pub key from foreign device     
 var derived_secret = key1.derive(key2.getPublic());  



from Derive Shared Secret From ECDH with existing foreign public key

No comments:

Post a Comment