Używanie zakodowanego PEM, zaszyfrowanego klucza prywatnego do podpisywania wiadomości natywnie

Próbuję użyć certyfikatu PEM (X. 509) (przechowywanego w privateKey.plik pem na dysku) do podpisywania wiadomości wysyłanych za pośrednictwem gniazd w Javie, ale mam duży problem ze znalezieniem przykładu, który jest bliski. Zwykle jestem facetem z C++, który właśnie wkracza, aby pomóc w tym projekcie, więc trochę trudno było mi połączyć to wszystko w kod, który działa, gdy nie znam API.

Niestety, jestem ograniczony do metod, które są standardowo z Java( 1.6.0 Update 16), więc chociaż Podobny przykład znalazłem przy użyciu BouncyCastle's PEMReader, nie pomógł zbyt wiele w tym konkretnym projekcie.

Mój szeregowy.klucz pem jest zabezpieczony hasłem w postaci:
-----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-----

Klucz został wygenerowany przy użyciu OpenSSL:

openssl.exe genrsa -out private_key.pem 4096

Nie jestem w stanie przekonwertować tego klucza do DER lub innego formatu przed uruchomieniem, wszelkie niezbędne konwersje będą musiały być wykonane wewnętrznie w kodzie, ponieważ klucz musi być łatwo wymienny, a format pozostanie PEM.

Słyszałem mieszankę rzeczy, których nie jestem do końca pewien, i miałem nadzieję, że zbiorowe umysły tutaj w SO mogą pomóc zebrać kawałki razem.



słyszałem, że certyfikat PEM wymaga dekodowania Base64, aby przekształcić go w certyfikat DER, który może być używany. Mam narzędzie do dekodowania Base64 o nazwie MiGBase64, ale nie jestem do końca pewien, jak/kiedy to dekodowanie wymaga wykonania.


zgubiłem się w dokumentach Java API próbując śledzić w dół 15 różne rodzaje kluczy, Keystore, Keygeneratory, certyfikaty, itp, które istnieją, ale nie jestem wystarczająco zaznajomiony z żadnym z nich prawidłowo zidentyfikować, które trzeba używać, i jak używać ich razem.


podstawowy algorytm wydaje się dość prosty, dlatego szczególnie frustrujące było to, że nie byłem w stanie napisać równie prostej implementacji: {]}

1) przeczytaj privateKey.pem z pliku
2) Załaduj klucz prywatny do klasy XXX, używając Hasło do odszyfrowania klucza
3) Użyj obiektu key Z klasą Signature, aby podpisać wiadomość



Pomoc w tym, szczególnie przykładowy kod, jest bardzo doceniana. Starałem się znaleźć przydatne przykłady tego problemu, ponieważ większość przykładów "bliskich" generuje nowe klucze, używając BouncyCastle lub po prostu w inny sposób używając różnych form kluczy / klas nie mających tu zastosowania.

To wygląda na bardzo prosty problem, ale doprowadza mnie to do szału. proste odpowiedzi?
Author: Community, 2009-10-16

2 answers

Jeśli używasz BouncyCastle, spróbuj wykonać następujące czynności:

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);
        }
    } 
}
 20
Author: Kevin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-16 20:05:41

Polecenie OpenSSL generuje parę kluczy i koduje ją w formacie PKCS#1. Jeśli nie używasz szyfrowania (nie podałeś hasła do polecenia), PEM jest po prostu zakodowany Base64 DER dla PKCS#1 RSAPrivateKey.

Niestety, JCE Sun nie zapewnia publicznego interfejsu do odczytu klucza w tym formacie. Masz 2 opcje,

  1. Zaimportuj klucz do keystore i możesz go stamtąd odczytać. Keytool nie pozwala na importowanie kluczy prywatnych. Możesz znaleźć inne narzędzia do tego.

  2. Biblioteka OAuth ma do tego funkcję. Spójrz na kod tutaj,

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

 4
Author: ZZ Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-16 20:15:29