it-swarm-vi.com

Làm cách nào để sử dụng các khóa được tạo OpenSSL trong Java?

Tôi có cặp khóa Công khai và Riêng tư và chứng chỉ của mình. Những nơi được tạo trong OpenSSL (tại sao? Bởi vì tôi được yêu cầu làm điều đó trong OpenSSL). Bây giờ tôi muốn sử dụng những thứ đó để tạo một ứng dụng Java sử dụng chữ ký điện tử. Làm cách nào tôi có thể sử dụng khóa riêng và khóa chung để mã hóa/giải mã thông tin (và sử dụng chứng chỉ để xem liệu có phải dữ liệu không hợp lệ? Các lớp trong Java cho phép tôi làm điều đó là gì?

Các phím của tôi ở dạng văn bản đơn giản như thế này:

-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDDuyg3h0VbP9iZ6RCxSU6x4WX4
anAwedMVUTqF0WHlvHl1Kiqa6N6TiUk23uXAVUX8RwLFjXWHlG0xwW7mGByA2mX9
5oPQpQFu8C70aMuUotGv87iiLi0UKCZV+9wS9rMdg5LHu1mMPilwgOO6MlyTxKem
-----END PUBLIC KEY-----

CẬP NHẬT

Tôi đã tạo mã này nhưng vẫn không thể sử dụng khóa riêng để ký chuỗi.

public void encryptHash(String hashToEncrypt, String pathOfKey, String Algorithm) {
    FileInputStream fis = null;
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    int len;

        File f = new File(pathOfKey);

        fis = new FileInputStream(pathOfKey);
        len = 0;
        while((len = fis.read()) != -1){
            baos.write(len);
        }

        KeyFactory kf = KeyFactory.getInstance(Algorithm); //Algorithm = "RSA"
        KeySpec keySpec = new PKCS8EncodedKeySpec(baos.toByteArray());
        baos.close();
        PrivateKey privateKey = kf.generatePrivate(keySpec);  //Here's the exception thrown

        Signature rsaSigner = Signature.getInstance("SHA1withRSA");
        rsaSigner.initSign(privateKey);

        fis = new FileInputStream(hashToEncrypt);
        BufferedInputStream bis = new BufferedInputStream(fis);
        byte[] buffer = new byte[1024];
        len = 0;
        while((len = bis.read(buffer)) >= 0){
            try {
                rsaSigner.update(buffer, 0, len);
            } catch (SignatureException ex) {
                Logger.getLogger(DataEncryptor.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        bis.close();

        byte[] signature = rsaSigner.sign();

        System.out.println(new String(signature));
}

ngoại lệ tôi nhận được là

dic 09, 2011 12:49:02 PM firmaelectronica.DataEncryptor encryptHash
Grave: null
Java.security.spec.InvalidKeySpecException: Java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at Sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.Java:217)
    at Java.security.KeyFactory.generatePrivate(KeyFactory.Java:372)
    at firmaelectronica.DataEncryptor.encryptHash(DataEncryptor.Java:40)
    at firmaelectronica.FirmaElectronica.main(FirmaElectronica.Java:39)
Caused by: Java.security.InvalidKeyException: IOException : DER input, Integer tag error
    at Sun.security.pkcs.PKCS8Key.decode(PKCS8Key.Java:361)
    at Sun.security.pkcs.PKCS8Key.decode(PKCS8Key.Java:367)
    at Sun.security.rsa.RSAPrivateCrtKeyImpl.<init>(RSAPrivateCrtKeyImpl.Java:91)
    at Sun.security.rsa.RSAPrivateCrtKeyImpl.newKey(RSAPrivateCrtKeyImpl.Java:75)
    at Sun.security.rsa.RSAKeyFactory.generatePrivate(RSAKeyFactory.Java:316)
    at Sun.security.rsa.RSAKeyFactory.engineGeneratePrivate(RSAKeyFactory.Java:213)
    ... 3 more
11
BRabbit27

Nếu bạn có khóa công khai ở dạng này (và không có trong chứng chỉ), tôi khuyên bạn nên sử dụng BouncyCastle 's PEMReader. Phương thức readObject() của nó có thể đọc rất nhiều định dạng: khóa chung, chứng chỉ, khóa riêng (mặc dù bạn có thể cần sử dụng phương thức với mật khẩu) ...

Nếu bạn không muốn sử dụng BouncyCastle, bạn có thể đọc chứng chỉ bằng cách sử dụng Chứng nhậnFactory (xem ví dụ). Với chứng chỉ ở định dạng PEM trong InputStream:

CertificateFactory cf = CertificateFactory.getInstance("X.509");
Certificate cert = cf.generateCertificate(inputStream);

Đối với khóa riêng, nếu khóa riêng của bạn là cấu trúc PKCS # 8 ở định dạng DER, bạn có thể đọc trực tiếp bằng PKCS8EncodingKeySpec . Ví dụ:

KeyFactory kf = KeyFactory.getInstance("RSA");
// Read privateKeyDerByteArray from DER file.
KeySpec keySpec = new PKCS8EncodedKeySpec(privateKeyDerByteArray);
PrivateKey key = kf.generatePrivate(keySpec);

Bạn có thể chuyển đổi khóa riêng của mình thành PKCS # 8 bằng cách sử dụng openssl pkcs8 -topk8 (Hãy nhớ -outform DER, Bạn cũng có thể muốn kiểm tra các bộ mật mã vì không phải tất cả đều được hỗ trợ bởi cả Java và OpenSSL).

  • Từ quan điểm sử dụng kho khóa:

Nếu bạn không muốn lập trình nhiều để xử lý các khóa, hãy chuyển giữa Java và OpenSSL, thật tiện lợi khi sử dụng định dạng PKCS # 12.

Nếu các khóa và certs bạn đã tạo bằng OpenSSL chưa có trong bộ chứa p12:

openssl pkcs12 -export -in cert.pem -inkey key.pem -out store.p12

Nói chung, bạn có thể sử dụng trực tiếp loại sử dụng loại kho khóa "PKCS12" Của Java (thay vì "JKS" theo mặc định).

Nếu cần, bạn có thể chuyển đổi kho khóa PKCS12 này sang định dạng khác (ví dụ: JKS) bằng cách sử dụng keytool (Java 6+):

keytool -importkeystore -srckeystore store.p12 -srcstoretype PKCS12 \
     -destkeystore store.jks -deststoretype JKS

(Về cơ bản, thao tác ngược lại như hoạt động được mô tả trong câu hỏi này .)

Dù bằng cách nào, dù sử dụng PEMReader hay bằng cách tải khóa/cert của bạn từ KeyStore, bạn sẽ có thể nhận được các phiên bản của PrivateKeyCertificate (hoặc PublicKey trực tiếp).

Bạn có thể xác minh chữ ký của một Certificate đã được thực hiện bằng khóa riêng khớp với khóa chung đã cho bằng cách sử dụng phương thức verify(PublicKey) của nó.

Với họ, bạn cũng có thể sử dụng API chữ ký số . Đó là API chung hơn cho bất kỳ chữ ký tài liệu nào và tôi không nhất thiết phải xác minh chữ ký chứng chỉ với nó (Tôi muốn sử dụng API đường dẫn chứng nhận cho điều này, vì nó cũng sẽ xây dựng chuỗi).

10
Bruno