Sign string with PEM PrivateKey

后端 未结 1 593
不知归路
不知归路 2021-02-10 22:24

I have a PEM-encoded private key and I need to sign a string with it. But the code keeps crashing with exception:

java.security.spec.InvalidKeySpecException: jav         


        
1条回答
  •  天涯浪人
    2021-02-10 22:50

    Your private key is encrypted according PKCS#8, so you need to use the EncryptedPrivateKeyInfo class among others. This stackoverflow question contains an example showing how to retrieve it. I have turned it into a more complete example below:

    import javax.crypto.Cipher;
    import javax.crypto.EncryptedPrivateKeyInfo;
    import javax.crypto.SecretKey;
    import javax.crypto.SecretKeyFactory;
    import javax.crypto.spec.PBEKeySpec;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    import java.nio.file.Files;
    import java.nio.file.Paths;
    import java.security.KeyFactory;
    import java.security.PrivateKey;
    import java.security.spec.PKCS8EncodedKeySpec;
    import java.util.Base64;
    import java.util.List;
    
    public class Main {
    
        private static byte [] pemFileToBytes(String filename) throws IOException {
            // read in PEM file, throw away the begin and end lines
            List pemLines = Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII);
            pemLines.remove(0);
            pemLines.remove(pemLines.size() - 1);
            String pem = String.join("", pemLines);
    
            // base64 decode and return the result.
    
            return Base64.getDecoder().decode(pem);
        }
    
        private static PrivateKey parsePrivateKey (String filename, char [] password) throws Exception{
            PBEKeySpec passKeySpec = new PBEKeySpec(password); //my password
    
            EncryptedPrivateKeyInfo encryptedKey = new EncryptedPrivateKeyInfo(pemFileToBytes(filename));
            SecretKeyFactory keyFac = SecretKeyFactory.getInstance(encryptedKey.getAlgName());
            SecretKey passKey = keyFac.generateSecret(passKeySpec);
    
            // Create PBE Cipher
            Cipher pbeCipher = Cipher.getInstance(encryptedKey.getAlgName());
            // Initialize PBE Cipher with key and parameters
            pbeCipher.init(Cipher.DECRYPT_MODE, passKey, encryptedKey.getAlgParameters());
    
            // Decrypt the private key
    
            byte [] encodedPrivateKey = pbeCipher.doFinal(encryptedKey.getEncryptedData());
            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey);
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(privateKeySpec);
    
        }
    
        public static void main(String[] args) throws Exception {
            PrivateKey pk = parsePrivateKey("x.pk8", "pass".toCharArray());
        }
    }
    

    You last line, return new String(instance.sign(), UTF_8); doesn't make any sense as Signature.sign() returns an array of bytes that is not likely to be a valid string in any character set. If you must convert the signature to a string then the standard way is to base64 encode it.

    0 讨论(0)
提交回复
热议问题