bouncycastleecdhkdf

How to derive a AES key with ANSI X9.63 in Java?


They are cloud and device team in my company, and sometime cloud side needs to send a sensitive information to the device. For this we are using SHA-512 key derivation function to derive a AES key and encrypt the payload. But device team wants to adopt PKCS#11 for making various operations happen on the device standardize, hence we need to change the way we are deriving a key on the cloud side, from SHA-512 to ECDH X9.63.

In the device side, they are using C language with PKCS#11 library (C_DeriveKey function). In Java, we don't have a straightforward way of using the C_DeriveKey function to derive a key. They are some limitation on top of this, such that we cannot use any third party library that are not approved in the company. Since bouncy castle library is approved, I am looking for a way to use this to derive a key.

I found few way of deriving a key, but none of them output the desire AES key.

  1. Using ECCDHwithSHA256KDF key agreement algorithms and UserKeyingMaterialSpec to perform the key agreement and the KDF in one go (reference: Apple eciesEncryptionCofactorVariableIVX963SHA256AESGCM vs BouncyCastle ECCDHwithSHA256KDF). This generated a different AES key when compared with the device side.

  2. Using ECDHKEKGenerator to derive a key. Same outcome as above, didn't match. Also, this is probably for envelope encryption, which is use to encrypt the key (ECDHKEK - ECDH key encryption key).


Solution

  • I found a function that generated the desire output using KDF2BytesGenerator:

        /**
         * X9.63 key derivation function, derives AES session key from a secret
         */
        public static byte[] deriveKeyWithANSIX963(byte[] sharedSecret) {
            byte[] derivedOOEK = new byte[32];
            SHA256Digest hash = new SHA256Digest();
            KDF2BytesGenerator kdf = new KDF2BytesGenerator(hash);
            // KDF parameters is (arg1 shared secret, arg2 iv)
            kdf.init(new KDFParameters(sharedSecret, null));
            kdf.generateBytes(derivedOOEK, (short) 0, 32);
            return derivedOOEK;
        }