簡體   English   中英

使用PEM編碼的加密私鑰本地簽名消息

[英]Using a PEM encoded, encrypted private key to sign a message natively

我正在嘗試使用PEM(X.509)證書(存儲在磁盤上的privateKey.pem文件中)來簽署通過Java中的套接字發送的消息,但是在找到一個接近的示例時遇到了很多麻煩。 我通常是一個C ++人,他只是在幫助這個項目,所以我把它放在代碼中有點困難,因為我不熟悉API。

不幸的是,我只限於Java(1.6.0 Update 16)標准的方法,所以雖然我發現了一個使用BouncyCastlePEMReader的類似例子,但它對這個特定的項目沒有多大幫助。

我的privateKey.pem密鑰是passphrase protected,格式為:

-----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-----

它們是使用OpenSSL生成的:

openssl.exe genrsa -out private_key.pem 4096

我無法在運行之前將此密鑰轉換為DER或其他格式,任何必要的轉換都需要在代碼內部完成,因為密鑰需要易於更換且格式仍為PEM。

我聽過各種各樣的事情,我並不完全確定,並且希望這里的集體思想可以幫助將各個部分拉到一起。



我聽說它說PEM證書需要Base64解碼才能將其轉換為可以使用的DER證書。 我有一個名為MiGBase64的Base64解碼工具,但我不完全確定如何/何時需要解碼。


我已經迷失在Java API文檔中,試圖追蹤存在的15種不同類型的Keys,KeyStores,KeyGenerators,Certificates等,但我對它們中的任何一種都不熟悉,無法正確識別我需要的使用,以及如何一起使用它們。


基本算法看起來很簡單,這就是為什么我無法編寫同樣簡單的實現特別令人沮喪的原因:

1)從文件中讀取privateKey.pem
2)使用密碼短語將私鑰加載到XXX類中以解密密鑰
3)使用帶有Signature類的密鑰對象對消息進行簽名



非常感謝幫助,特別是示例代碼。 我一直在努力尋找這個問題的有用示例,因為大多數“關閉”示例都是使用BouncyCastle生成新密鑰,或者只是使用不適用於此處的不同形式的密鑰/類。

這似乎是一個非常簡單的問題,但它讓我發瘋,任何非常簡單的答案?

如果您使用的是BouncyCastle,請嘗試以下操作:

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

OpenSSL命令生成密鑰對並以PKCS#1格式對其進行編碼。 如果您不使用加密(沒有為命令提供密碼),則PEM只是用於PKCS#1 RSAPrivateKey的Base64編碼的DER。

不幸的是,Sun的JCE沒有提供公共接口來讀取這種格式的密鑰。 你有2個選擇,

  1. 將密鑰導入密鑰庫,您可以從那里讀取密鑰。 Keytool不允許導入私鑰。 您可以找到其他工具來執行此操作。

  2. OAuth庫具有處理此功能的功能。 看看這里的代碼,

http://oauth.googlecode.com/svn/code/java/core/commons/src/main/java/net/oauth/signature/pem/PKCS1EncodedKeySpec.java

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM