Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
282 views
in Technique[技术] by (71.8m points)

java - Using a PEM encoded, encrypted private key to sign a message natively

I'm trying to use a PEM(X.509) certificate (stored in a privateKey.pem file on disk) to sign messages sent via sockets in Java, but am having a lot of trouble finding an example that's close. I'm normally a C++ guy who's just stepping in to help on this project, so it's been a little difficult for me to put it all together into code that works when I'm unfamiliar with the APIs.

Unfortunately, I'm limited to methods that come standard with Java (1.6.0 Update 16), so although I found a similar example using BouncyCastle's PEMReader, it hasn't helped much on this particular project.

My privateKey.pem key is passphrase protected, in the form of:

-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED DEK-Info:
DES-EDE3-CBC,63A862F284B1280B
[...]
tsjQI4H8lhOBuk+NelHu7h2+uqbBQzwkPoA8IqbPXUz+B/MAGhoTGl4AKPjfm9gu
OqEorRU2vGiSaUPgDaRhdPKK0stxMxbByUi8xQ2156d/Ipk2IPLSEZDXONrB/4O5
[...]
-----END RSA PRIVATE KEY-----

They key was generated using OpenSSL:

openssl.exe genrsa -out private_key.pem 4096

I am unable to convert this key to a DER or other format prior to runtime, any conversions necessary will need to be done internally in code, as the key needs to be easily replaceable and the format will remain PEM.

I've heard a mix of things which I'm not entirely sure about, and was hoping the collective minds here at SO could help pull the pieces together.



I've heard it said that the PEM certificate needs Base64 Decoded to convert it into a DER certificate that can be used. I have a Base64 Decoding tool called MiGBase64 but am not entirely sure how/when this decoding needs done.


I've gotten lost in the Java API docs trying to track down the 15 different types of Keys, KeyStores, KeyGenerators, Certificates, etc that exist, but I'm not familiar enough with any of them to properly identify which I need to be using, and how to use them together.


The basic algorithm seems pretty simple, which is why it has been particularly frustrating that I haven't been able to write an equally simple implementation:

1) Read the privateKey.pem from file
2) Load the private Key into XXX class, using the Passphrase to decrypt the key
3) Use the key object with the Signature class to sign the message



Help with this, especially example code, is greatly appreciated. I've been struggling to find useful examples for this problem, as most 'close' examples are generating new keys, using BouncyCastle, or just otherwise using different forms of keys/classes not applicable here.

This seems like a really simple problem but it's driving me crazy, any really simple answers?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you're using BouncyCastle, try the following:

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.security.KeyPair;
import java.security.Security;
import java.security.Signature;
import java.util.Arrays;

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;
import org.bouncycastle.openssl.PasswordFinder;
import org.bouncycastle.util.encoders.Hex;

public class SignatureExample {

    public static void main(String [] args) throws Exception {
        Security.addProvider(new BouncyCastleProvider());

        String message = "hello world";
        File privateKey = new File("private.pem");
        KeyPair keyPair = readKeyPair(privateKey, "password".toCharArray());

        Signature signature = Signature.getInstance("SHA256WithRSAEncryption");
        signature.initSign(keyPair.getPrivate());
        signature.update(message.getBytes());
        byte [] signatureBytes = signature.sign();
        System.out.println(new String(Hex.encode(signatureBytes)));

        Signature verifier = Signature.getInstance("SHA256WithRSAEncryption");
        verifier.initVerify(keyPair.getPublic());
        verifier.update(message.getBytes());
        if (verifier.verify(signatureBytes)) {
            System.out.println("Signature is valid");
        } else {
            System.out.println("Signature is invalid");
        }
    }

    private static KeyPair readKeyPair(File privateKey, char [] keyPassword) throws IOException {
        FileReader fileReader = new FileReader(privateKey);
        PEMReader r = new PEMReader(fileReader, new DefaultPasswordFinder(keyPassword));
        try {
            return (KeyPair) r.readObject();
        } catch (IOException ex) {
            throw new IOException("The private key could not be decrypted", ex);
        } finally {
            r.close();
            fileReader.close();
        }
    }

    private static class DefaultPasswordFinder implements PasswordFinder {

        private final char [] password;

        private DefaultPasswordFinder(char [] password) {
            this.password = password;
        }

        @Override
        public char[] getPassword() {
            return Arrays.copyOf(password, password.length);
        }
    } 
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...