【问题标题】:Java: write and read password based encrypted private keyJava:写入和读取基于密码的加密私钥
【发布时间】:2016-03-27 00:13:23
【问题描述】:

我正在尝试从文件中读取基于密码的加密私钥,但出现以下异常:

java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:561)
at sun.security.util.DerValue.init(DerValue.java:365)
at sun.security.util.DerValue.<init>(DerValue.java:294)
at javax.crypto.EncryptedPrivateKeyInfo.<init>(EncryptedPrivateKeyInfo.java:84) ...

这就是我加密和写入私钥文件的方式:

public static void savePrivateKeyToDisk(PrivateKey privateKey, String passord){

    try {
        // unencrypted PKCS#8 private key
        byte[] encodedPrivateKey = privateKey.getEncoded();

        String MYPBEALG = "PBEWithSHA1AndDESede";

        int count = 20;
        SecureRandom random = new SecureRandom();
        byte[] salt = new byte[8];
        random.nextBytes(salt);

        // Create PBE parameter set
        PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, count);
        PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray());
        SecretKeyFactory keyFac = SecretKeyFactory.getInstance(MYPBEALG);
        SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec);

        Cipher pbeCipher = Cipher.getInstance(MYPBEALG);

        // Initialize PBE Cipher with key and parameters
        pbeCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec);

        // Encrypt the encoded Private Key with the PBE key
        byte[] cipherText = pbeCipher.doFinal(encodedPrivateKey);

        // Now construct  PKCS #8 EncryptedPrivateKeyInfo object
        AlgorithmParameters algparms = AlgorithmParameters.getInstance(MYPBEALG);
        algparms.init(pbeParamSpec);
        EncryptedPrivateKeyInfo encinfo = new EncryptedPrivateKeyInfo(algparms, cipherText);

        // DER encoded PKCS#8 encrypted key
        byte[] encryptedPkcs8 = encinfo.getEncoded();


        File encryptedPrivate = new File(PRIVATE_KEY_FILE);

        if (encryptedPrivate.getParentFile() != null) {
            encryptedPrivate.getParentFile().mkdirs();
        }
        encryptedPrivate.createNewFile();

        ObjectOutputStream publicKeyOS = new ObjectOutputStream(
                new FileOutputStream(encryptedPrivate));
        publicKeyOS.writeObject(encryptedPkcs8);
        publicKeyOS.close();

    }
    catch (Exception e){
        e.printStackTrace();
    }
}

...这就是我尝试读取加密私钥的方式:

public static PrivateKey getPrivateKey(String passwd){
    try {

        byte[] encodedPrivateKey = getFileBytes(PRIVATE_KEY_FILE);

        // exception thrown from here
        EncryptedPrivateKeyInfo encryptPKInfo = new EncryptedPrivateKeyInfo(encodedPrivateKey);

        Cipher cipher = Cipher.getInstance(encryptPKInfo.getAlgName());
        PBEKeySpec pbeKeySpec = new PBEKeySpec(passwd.toCharArray());
        SecretKeyFactory secFac = SecretKeyFactory.getInstance(encryptPKInfo.getAlgName());
        Key pbeKey = secFac.generateSecret(pbeKeySpec);
        AlgorithmParameters algParams = encryptPKInfo.getAlgParameters();
        cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams);
        KeySpec pkcs8KeySpec = encryptPKInfo.getKeySpec(cipher);
        KeyFactory kf = KeyFactory.getInstance(ALGORITHM);
        return kf.generatePrivate(pkcs8KeySpec);
    }
    catch (Exception e){
        e.printStackTrace();
        return null;
    }
}

...getFileBytes 方法:

 private static byte[] getFileBytes(String infile){
    File f = new File(infile) ;
    int sizecontent = ((int) f.length());
    byte[] data = new byte[sizecontent];
    try
    {
        FileInputStream freader = new FileInputStream(f);
        freader.read(data, 0, sizecontent) ;
        freader.close();
        return data;
    }
    catch(IOException ioe)
    {
        System.out.println(ioe.toString());
        return null;
    }
}

似乎加密的私钥格式不正确,但我将其保存为 DER PKCS#8 格式。 那么问题来了:这段代码有什么错误?

【问题讨论】:

  • 非对称加密不适用于加密大于其密钥大小的数据。

标签: java encryption private-key


【解决方案1】:

我想问题是你写了一个Object,但是你读到了byte[](不是Object) 我建议您要么读取整个对象,然后获取所需的字节,甚至更好地直接写入byte[](不要使用ObjectOutputStream)然后加载这些字节,例如:

FileOutputStream fos = new FileOutputStream(PRIVATE_KEY_FILE);
fos.write(myByteArray);
fos.close();

然后去检索它:

byte[] bytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILE));

【讨论】:

  • 构造函数EncryptedPrivateKeyInfo 仍然会抛出异常,即java.io.IOException: DerValue.getOctetString, not an Octet String: 3。现在我正在写 FileOutputStream fos = new FileOutputStream(PRIVATE_KEY_FILE); fos.write(encryptedPkcs8); fos.close(); 和阅读 byte[] bytes = Files.readAllBytes(Paths.get(PRIVATE_KEY_FILE)); EncryptedPrivateKeyInfo encryptPKInfo = new EncryptedPrivateKeyInfo(bytes);
  • 方法DerValue.getOctetString 需要一个八位组字符串标记,但它得到一个位字符串标记。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-18
  • 2020-05-01
  • 2021-09-22
  • 2011-07-24
  • 1970-01-01
相关资源
最近更新 更多