it-swarm-eu.dev

Jak používat klíče generované OpenSSL v Javě?

Mám svůj pár veřejných a soukromých klíčů a můj certifikát. Ty, kde byly vytvořeny v OpenSSL (proč? Protože jsem byl požádán, abych to udělal v OpenSSL). Nyní chci tyto věci použít k vytvoření aplikace Java), která používá digitální podpisy. Jak mohu použít své soukromé a veřejné klíče k šifrování/dešifrování informací (a pomocí certifikátu zjistím, zda jsou data platné? Jaké jsou třídy v Java), které mi to umožňují?

Moje klíče jsou ve formě prostého textu:

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

AKTUALIZACE

Vytvořil jsem tento kód, ale stále nemůžu použít soukromý klíč k podpisu řetězce.

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

výjimkou je, že dostanu

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

Pokud máte v této podobě veřejný klíč (a nikoli v certifikátu), doporučuji použít BouncyCastle 's PEMReader. Její metoda readObject() umí číst hodně pro formáty: veřejné klíče, certifikáty, soukromé klíče (i když možná budete muset metodu použít s heslem) ...

Pokud nechcete používat BouncyCastle, můžete si přečíst certifikáty pomocí CertificateFactory (viz příklady). S certifikátem ve formátu PEM ve InputStream:

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

U soukromých klíčů, pokud je váš soukromý klíč strukturou PKCS # 8 ve formátu DER, si ji můžete přečíst přímo pomocí PKCS8EncodedKeySpec . Například:

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

Můžete převést svůj soukromý klíč na PKCS # 8 pomocí openssl pkcs8 -topk8 (Pamatujte -outform DER, Možná budete také chtít zkontrolovat sady šifry, protože ne všechny mohou být běžně podporovány oběma Java a OpenSSL).

  • Z pohledu využití úložiště klíčů:

Pokud nechcete dělat mnoho programování pro práci s klíči, jít mezi Java a OpenSSL), je vhodné použít formát PKCS # 12.

Pokud klíče a certs, které jste vytvořili pomocí OpenSSL, již nejsou v kontejneru p12:

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

Obecně můžete přímo použít typ úložiště klíčů "PKCS12" Java (ve výchozím nastavení namísto "JKS").

V případě potřeby můžete tento klíčový sklad PKCS12 převést do jiného formátu (např. JKS) pomocí keytool (Java 6+):

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

(V podstatě opačná operace, jako je operace popsaná v tato otázka .)

V každém případě, ať už z použití PEMReader nebo načtením klíče/cert z KeyStore, měli byste být schopni získat instance PrivateKey a Certificate (nebo PublicKey přímo).

Můžete ověřit, že podpis Certificate byl proveden soukromým klíčem odpovídajícím veřejnému klíči pomocí metody verify(PublicKey).

S nimi můžete také použít API pro digitální podpis . Je to obecnější API pro jakýkoli podpis dokumentu a já bych s tím nutně neověřoval podpis certifikátu (raději bych pro to použil API pro certifikační cestu, protože to také vytvoří řetěz).

10
Bruno