要转换为 PrivateKey 对象的字节

Posted

技术标签:

【中文标题】要转换为 PrivateKey 对象的字节【英文标题】:bytes to be converted into PrivateKey Object 【发布时间】:2015-07-08 11:54:45 【问题描述】:

我的 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);;

我该如何解决这个问题?

【问题讨论】:

欢迎来到信息安全堆栈交换!我认为这个问题更适合Stack Overflow。您可以标记您的帖子以引起版主的注意并要求迁移。为了清楚起见,您可能希望显示 catch 语句中的内容。此外,它有助于显示错误发生在哪一行 - 您可以在异常附带的堆栈跟踪中找到它。祝你好运! 【参考方案1】:

在您的示例中,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);
  


【讨论】:

感谢您的回复,我在 BouncyCastle 中找不到同等课程。我怎样才能将wrappedBytes 放入PKCS #8。你能建议吗? 您是否使用基于密码的加密?还是您使用随机生成的SecretKey 进行加密? 我们的 jks 文件中有一个固定的密钥。我们正在使用 Secret Key 加密私钥。在我的示例程序中,我将 KeyPair 对象传递给 wrapPrivateKeyWithSymmetricKey 方法,并用 Secret Key 包装私钥,最后将 KeyPair 对象返回给该方法。如何从 WrappedBytes 获取私钥对象?你能建议吗? @user3240160 你真的需要编码为EncryptedPrivateKeyInfo 的密钥吗?例如,您是否需要与其他一些需要 PKCS #8 密钥的软件进行互操作?您正在使用受密码保护的密钥对私钥进行加密,因此您的私钥并不比该密码更安全;您为什么不按预期将私钥直接存储在KeyStore 中?我不想为你不需要的东西提供代码。你应该解释你想要完成的什么,而不是如何你认为你应该这样做。 我有 KeyPair 对象,我正在用密钥加密私钥并再次需要 KeyPair 对象。我将序列化的 KeyPair 对象保存到数据库中。你能建议吗?

以上是关于要转换为 PrivateKey 对象的字节的主要内容,如果未能解决你的问题,请参考以下文章

EC 将字符串转换为 PublicKey / PrivateKey

我尝试获取PrivateKey.getEncode时出错

如何将 Byte 数组转换为 PrivateKey 或 PublicKey 类型?

将 JSON 公钥/私钥对转换为 rsa.PrivateKey 和 rsa.PublicKey

python使用rsa非对称加密

C#将对象转换为字节数组