要转换为PrivateKey对象的字节

时间:2015-07-08 11:54:45

标签: java cryptography

我的JKS(Java密钥库)文件中有一个对称密钥,我想用对称密钥包装我的私钥。

我再次将wrappedBytes用于PrivateKey对象。最后我想要KeyPair对象。

以下代码给出以下错误消息:

  

java.security.spec.InvalidKeySpecException:java.security.InvalidKeyException:IOException:DerInputStream.getLength():lengthTag = 125,太大了。**

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);;
}

我该如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

在您的示例中,wrappedBytes不是PKCS #8格式。它只是一些AES加密块 - 基本上是随机数据 - 没有编码结构。

如果你想创建一个加密的 PKCS#8(正式地,EncryptedPrivateKeyInfo),你需要一个处理它的库。您尝试使用的内置API仅处理其明文有效负载PrivateKeyInfo(如its documentation中所述)。

包装器没什么用,您可以自己编写必要的DER编码,或使用像BouncyCastle.这样的库

这是代码,使用BouncyCastle对EncryptyedPrivateKeyInfo结构进行编码和解码。由于密钥加密算法标识符及其参数的处理不当,JCE提供的无用类不起作用。

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);
  }

}