1
votes

I have a symmetric Key in my JKS (Java Key Store) file, I want to wrap my private key with a symmetric key.

Again I am using wrappedBytes to PrivateKey Object. And finally I want the KeyPair Object.

The below code gives the following error message:

java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: IOException : DerInputStream.getLength(): lengthTag=125, too big.**

public KeyPair wrapPrivateKeyWithSymmetricKey(KeyPair keyPair) {

    try {
        PrivateKey priv = keyPair.getPrivate();
        SecretKey symmetricKey = "bjksabfkasdbgvkasbvkkj";//symmetricKey from jks file

        //wrapping Private Key
        Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
        cipher.init(Cipher.WRAP_MODE, symmetricKey);
        byte[] wrappedKey = cipher.wrap(priv);

        //wrappedKey bytes to PrivateKey Object
        KeyFactory keyFactory = KeyFactory.getInstance(priv.getAlgorithm());
        EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(wrappedKey);
        PrivateKey privateKey2 = keyFactory.generatePrivate(privateKeySpec); //above Error Throwing in this line

        return new KeyPair(keyPair.getPublic(), privateKey2);;
}

How can I solve this?

1
Welcome to Information Security Stack Exchange! I think this question is better fit for Stack Overflow. You can flag your post for moderator attention and ask for migration. You may want to show what's in your catch statement, for the sake of clarity. Also, it helps to show on what line the error occurs - you can find this in the stack trace that comes with the Exception. Good luck!S.L. Barth

1 Answers

2
votes

In your example, wrappedBytes isn't in a PKCS #8 format. It's simply some AES encrypted blocks—essentially random data—with no encoded structure.

If you want to create an encrypted PKCS #8 (formally, EncryptedPrivateKeyInfo) you'll need a library that handles that. The built-in API you are trying to use only handles its clear-text payload, PrivateKeyInfo (as described in its documentation).

There isn't much to the wrapper, and you could write the necessary DER coding yourself, or use a library like BouncyCastle.


Here's code, using BouncyCastle to encoded and decode the EncryptyedPrivateKeyInfo structure. The useless class provided by the JCE doesn't work, because of poor handling of the key encryption algorithm identifier and its parameters.

import java.security.GeneralSecurityException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateCrtKey;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.RSAPublicKeySpec;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;

import org.bouncycastle.asn1.ASN1Encodable;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.ASN1OctetString;
import org.bouncycastle.asn1.DEROctetString;
import org.bouncycastle.asn1.nist.NISTObjectIdentifiers;
import org.bouncycastle.asn1.pkcs.EncryptedPrivateKeyInfo;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo;

final class PKCS8
{

  private static final ASN1ObjectIdentifier AES = ASN1ObjectIdentifier.getInstance(NISTObjectIdentifiers.id_aes128_CBC);

  static RSAPublicKey toPublic(RSAPrivateCrtKey pvt)
    throws GeneralSecurityException
  {
    RSAPublicKeySpec pub = new RSAPublicKeySpec(pvt.getModulus(), pvt.getPublicExponent());
    KeyFactory f = KeyFactory.getInstance("RSA");
    return (RSAPublicKey) f.generatePublic(pub);
  }

  static byte[] encrypt(SecretKey secret, PrivateKey pvt)
    throws Exception
  {
    Cipher enc = Cipher.getInstance("AES/CBC/PKCS5Padding");
    enc.init(Cipher.WRAP_MODE, secret);
    ASN1Encodable params = new DEROctetString(enc.getIV());
    AlgorithmIdentifier algId = new AlgorithmIdentifier(AES, params);
    byte[] ciphertext = enc.wrap(pvt);
    return new EncryptedPrivateKeyInfo(algId, ciphertext).getEncoded();
  }

  static PrivateKey decrypt(SecretKey secret, byte[] pkcs8)
    throws Exception
  {
    EncryptedPrivateKeyInfo info = new PKCS8EncryptedPrivateKeyInfo(pkcs8).toASN1Structure();
    AlgorithmIdentifier id = info.getEncryptionAlgorithm();
    byte[] iv = ((ASN1OctetString) id.getParameters()).getOctets();
    Cipher dec = Cipher.getInstance("AES/CBC/PKCS5Padding");
    dec.init(Cipher.UNWRAP_MODE, secret, new IvParameterSpec(iv));
    return (PrivateKey) dec.unwrap(info.getEncryptedData(), "RSA", Cipher.PRIVATE_KEY);
  }

}