14 Stimmen

PrivateKey und PublicKey aus einem String base64-codiert mit DER-Format erstellen

Ich habe meine privaten und öffentlichen Schlüssel in einem String in base64, die mit ANS1 DER kodiert wurden. Ich habe versucht, die Instanz eines Java PrivateKey y PublicKey :

byte [] llave2 = DatatypeConverter.parseBase64Binary(key);
PKCS8Key pkcs8 = new PKCS8Key( llave2, password.toCharArray()); //line 2
llave2 = pkcs8.getDecryptedBytes();                             //line 3
certificado = DatatypeConverter.parseBase64Binary(cer);

KeyFactory kf = KeyFactory.getInstance("RSA");  
PKCS8EncodedKeySpec ks = new PKCS8EncodedKeySpec(llave2);
PrivateKey privateKey = kf.generatePrivate(ks);
X509EncodedKeySpec x = new X509EncodedKeySpec(certificado);
PublicKey publicKey = kf.generatePublic(x);

Ich erhalte den folgenden Fehler in PublicKey publicKey = kf.generatePublic(x) .

    java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException:     IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
    at sun.security.rsa.RSAKeyFactory.engineGeneratePublic(Unknown Source)
    at java.security.KeyFactory.generatePublic(Unknown Source)
    at vital.cancelaciones.GeneraXMLCancelacion.main(GeneraXMLCancelacion.java:118)
Caused by: java.security.InvalidKeyException: IOException: ObjectIdentifier() -- data isn't an object ID (tag = -96)
    at sun.security.x509.X509Key.decode(Unknown Source)
    at sun.security.x509.X509Key.decode(Unknown Source)
    at sun.security.rsa.RSAPublicKeyImpl.<init>(Unknown Source)
    at sun.security.rsa.RSAKeyFactory.generatePublic(Unknown Source)
    ... 3 more

Ich denke, ich sollte mit dem öffentlichen Schlüssel etwas Ähnliches machen wie mit dem privaten Schlüssel in Zeile 2 und 3. Denn auch das Zertifikat ist verschlüsselt. Irgendwelche Vorschläge?

37voto

Kohányi Róbert Punkte 9261

Um Ihr Szenario zu testen, habe ich einen privaten RSA-Schlüssel mit openssl .

openssl genrsa -out private.pem 1024

Dann habe ich diesen Schlüssel in das PKCS#8 DER-Format konvertiert.

openssl pkcs8 -topk8 -inform PEM -in private.pem -outform DER -out private.der -nocrypt

Das Handbuch der openssl bezieht sich auf PKCS#8 und DER sowohl als Formate Das heißt, für mich geschieht Folgendes:

  • pkcs8 sagt openssl dass ich mit privaten Schlüsseln im PKCS#8-Format arbeiten möchte.
  • -topk8 sagt ihm, dass der private Schlüssel, den ich mit -in est no in PKCS#8 (andernfalls wird davon ausgegangen, dass sie es ist).
  • -inform y -in angeben, dass ich den (PEM) privaten Schlüssel in PKCS#8 konvertieren möchte (ohne -topk8 wird versucht, einen Schlüssel, der bereits im PKCS#8-Format vorliegt, in ein Standard Schlüsselformat).
  • -outform y -out sagt ihm, dass ich einen DER-formatierten Schlüssel als Ausgabe haben möchte.
  • -nocrypt sagt ihm, dass ich den Schlüssel nicht verschlüsseln will.

Dann habe ich mit meinem RSA-Schlüssel (im Standardformat) ein Zertifikat erstellt.

openssl req -new -x509 -keyform PEM -key private.pem -outform DER -out public.der

Das Zertifikat enthält den öffentlichen Schlüssel, der meinem privaten Schlüssel entspricht.

Danach habe ich sowohl den privaten Schlüssel als auch das Zertifikat mit Base64 verschlüsselt.

base64 private.der > private.der.b64
base64 public.der > public.der.b64

Die folgenden Dateien wurden erstellt.

private.pem      # standard
private.der      # pkcs8/DER
private.der.b64 
public.der       # x509/DER
public.der.b64   

public static void main(String[] args) throws IOException, GeneralSecurityException {
  // get a handle on the base64 encoded key and certificate
  File privateKeyFile = new File("private.der.b64");
  File publicKeyFile = new File("public.der.b64");

  // pull them into arrays
  byte[] privateKeyBytes = toByteArray(privateKeyFile);
  byte[] publicKeyBytes = toByteArray(publicKeyFile);

  // decode them
  privateKeyBytes = toDecodedBase64ByteArray(privateKeyBytes);
  publicKeyBytes = toDecodedBase64ByteArray(publicKeyBytes);

  // get the private key
  KeyFactory keyFactory = KeyFactory.getInstance("RSA");
  KeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
  PrivateKey privateKey = keyFactory.generatePrivate(privateKeySpec);

  // get the public key
  CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
  Certificate certificate = certificateFactory.generateCertificate(new ByteArrayInputStream(publicKeyBytes));
  PublicKey publicKey = certificate.getPublicKey();
}

private static byte[] toByteArray(File file) throws IOException {
  // java 7's try-with-resources statement
  try (FileInputStream in = new FileInputStream(file);
      FileChannel channel = in.getChannel()) {
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    channel.transferTo(0, channel.size(), Channels.newChannel(out));
    return out.toByteArray();
  }
}

private static byte[] toDecodedBase64ByteArray(byte[] base64EncodedByteArray) {
  return DatatypeConverter.parseBase64Binary(
      new String(base64EncodedByteArray, Charset.forName("UTF-8")));
}

Das Hauptproblem war, dass man ein Zertifikat statt eines öffentlichen Schlüssels hatte. Das Zertifikat enthält den öffentlichen Schlüssel, aber es kann nicht mit X509EncodedKeySpec(...) Deshalb ist die CertificateFactory muss stattdessen verwendet werden.

(Nebenbei bemerkt aquí ist ein großartiger Artikel/Tutorial über openssl und die Verwendung von Java-Kryptographie. Ich habe meine Informationen teilweise von dort).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X