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.
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);
}
}
}
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,
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.
-
Biblioteka OAuth ma do tego funkcję. Spójrz na kod tutaj,
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