0

In this post, I answered my own problem about unwrapping a private key which has been wrapped out of a HSM using an EC master key. It implies using a derivation mechanism and a derivation function to issue a AES session key.
The code to implement the unwrapping with Bouncy Castle is:

KeyAgreement recipientAgreement =
  KeyAgreement.getInstance("ECDHWithSHA256KDF", BouncyCastleProvider.PROVIDER_NAME);
recipientAgreement.init(recipientPrivateKey,
                        new UserKeyingMaterialSpec(sharedData));
recipientAgreement.doPhase(transportPublicKey), true);            
final byte[] secret = recipientAgreement.generateSecret();
SecretKeySpec sharedSecret = new SecretKeySpec(secret , "AES");

Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7PADDING");
final InitializationVectorParameters initializationVectorParameters = new InitializationVectorParameters(new byte[16]);
byte[] ivb = initializationVectorParameters.getInitializationVector();
cipher.init(Cipher.DECRYPT_MODE, sharedSecret, new IvParameterSpec(ivb));
byte[] decryptedPrivateKey = cipher.doFinal(privateKeyWrappedBySessionKey);         

PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(decryptedPrivateKey);            
KeyFactory keyFactory = KeyHelper.keyFactory(wrappedPrivateKeyType);
PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

Unfortunately, if this works for almost all derivation functions (you just have to replace ECDHWithSHA256KDF with the appropriate name like ECDHWithSHA1KDF or whatever else), this does not work for CKD_NULL and AES key size shorter than 256 bits.
I used ECDH for the init of the KeyAgreement, generate a secret and got the first 128 or 192 bits of this secret, for example:

KeyAgreement recipientAgreement =
  KeyAgreement.getInstance("ECDH", BouncyCastleProvider.PROVIDER_NAME);
recipientAgreement.init(recipientPrivateKey);
(...)
final byte[] secret = recipientAgreement.generateSecret();
System.arraycopy(secret, 0, shortSecret, 0, 16);
SecretKeySpec sharedSecret = new SecretKeySpec(shortSecret , "AES");
(...)

but it fails at cipher.doFinal(privateKeyWrappedBySessionKey)with:

Cipher initialization exception: Given final block not properly padded. Such issues can arise if a bad key is used during decryption.

It seems obviously that the issued secret is not the expected one

Can anyone help me?

Please note that, with function such as CKD_SHA256_KDF and session key size of 128 or 192 bits, I can succesfully unwrap my key.

3ric-T
  • 31
  • 5

0 Answers0