2017-07-05 10 views
4

Ich habe einen PEM-kodierten privaten Schlüssel und ich muss einen String damit signieren. Aber der Code hält mit Ausnahme abstürzt:Zeichenkette mit PEM PrivateKey

java.security.spec.InvalidKeySpecException: java.lang.RuntimeException: error:0c0890ba:ASN.1 encoding routines:asn1_check_tlen:WRONG_TAG 

der Schlüssel string:

-----BEGIN ENCRYPTED PRIVATE KEY----- 
MIICxjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI4P/+9mJV6RwCAggA 
MBQGCCqGSIb3DQMHBAg/ZWGXeLHgeASCAoAhExhFxfcikmIKbFP0rgAlJuj1r999 
... and so on... 
hlgzM2p71FdC6NDVyyxbit/IzbimtJyhkRwOAnZ98yqtXWUEOx2v7CcUqiU8dSLA 
K0PsaxNTUeUcQV+Z7yJk/8HxfE1ya3u2CgPXCZsWWmbxQG/+awE0eEnZ 
-----END ENCRYPTED PRIVATE KEY----- 

ich viele Varianten ausprobiert habe, sah durch viele Antworten, aber die Ergebnisse waren die gleichen

Edit: mit James K Polks Hilfe habe ich es geschafft, private Key-Bytes zu bekommen, aber jetzt bekomme ich java.security.NoSuchAlgorithmException: SecretKeyFactory PBES2 implementation not found. Modifizierter Code:

private String sign(String dataString, String pkString, String privateKeyPass) throws Exception { 
     pkString = pkString.replace("-----BEGIN ENCRYPTED PRIVATE KEY-----", ""); 
     pkString = pkString.replace("-----END ENCRYPTED PRIVATE KEY-----", ""); 
     pkString = pkString.replaceAll("\\s+",""); 
     byte[] privateKeyBytes = decryptPrivateKey(Base64.decode(pkString, Base64.DEFAULT), privateKeyPass); 
     KeyFactory kf = KeyFactory.getInstance("RSA"); 
     PrivateKey privateKey = kf.generatePrivate(new PKCS8EncodedKeySpec(privateKeyBytes)); 

     Signature instance = Signature.getInstance("SHA1withRSA"); 
     instance.initSign(privateKey); 
     instance.update(dataString.getBytes(UTF_8)); 
     return Base64.encodeToString(instance.sign(), Base64.DEFAULT); 
    } 

public static byte[] decryptPrivateKey(byte[] key, String pass) throws Exception { 
     PBEKeySpec passKeySpec = new PBEKeySpec(pass.toCharArray()); 

     EncryptedPrivateKeyInfo encryptedKey = new EncryptedPrivateKeyInfo(key); 
     Timber.w("encryptedKey.getAlgName(): %s", encryptedKey.getAlgName()); 
     SecretKeyFactory keyFac = SecretKeyFactory.getInstance(encryptedKey.getAlgName());//PBES2 
     SecretKey passKey = keyFac.generateSecret(passKeySpec); 

     // Create PBE Cipher 
     Cipher pbeCipher = Cipher.getInstance(encryptedKey.getAlgName()); 
     // Initialize PBE Cipher with key and parameters 
     pbeCipher.init(Cipher.DECRYPT_MODE, passKey, encryptedKey.getAlgParameters()); 

     // Decrypt the private key 
     return pbeCipher.doFinal(encryptedKey.getEncryptedData()); 
    } 

EDIT: Ich landete mit Klasse von http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art050 up:

PrivateKey privateKey = KeyImport.readPrivateKeyFile(pkFileName, privateKeyPass); 

I save in eine Datei keystring und ihn dann

Antwort

1

Ihre privaten Schlüssel verschlüsselt wird nach PKCS # 8, readPrivateKeyFile so Sie verwenden müssen die EncryptedPrivateKeyInfo Klasse unter anderem. This stackoverflow question enthält ein Beispiel, das zeigt, wie es abgerufen wird. Ich habe es in ein vollständigeres Beispiel unten gedreht:

import javax.crypto.Cipher; 
import javax.crypto.EncryptedPrivateKeyInfo; 
import javax.crypto.SecretKey; 
import javax.crypto.SecretKeyFactory; 
import javax.crypto.spec.PBEKeySpec; 
import java.io.IOException; 
import java.nio.charset.StandardCharsets; 
import java.nio.file.Files; 
import java.nio.file.Paths; 
import java.security.KeyFactory; 
import java.security.PrivateKey; 
import java.security.spec.PKCS8EncodedKeySpec; 
import java.util.Base64; 
import java.util.List; 

public class Main { 

    private static byte [] pemFileToBytes(String filename) throws IOException { 
     // read in PEM file, throw away the begin and end lines 
     List<String> pemLines = Files.readAllLines(Paths.get(filename), StandardCharsets.US_ASCII); 
     pemLines.remove(0); 
     pemLines.remove(pemLines.size() - 1); 
     String pem = String.join("", pemLines); 

     // base64 decode and return the result. 

     return Base64.getDecoder().decode(pem); 
    } 

    private static PrivateKey parsePrivateKey (String filename, char [] password) throws Exception{ 
     PBEKeySpec passKeySpec = new PBEKeySpec(password); //my password 

     EncryptedPrivateKeyInfo encryptedKey = new EncryptedPrivateKeyInfo(pemFileToBytes(filename)); 
     SecretKeyFactory keyFac = SecretKeyFactory.getInstance(encryptedKey.getAlgName()); 
     SecretKey passKey = keyFac.generateSecret(passKeySpec); 

     // Create PBE Cipher 
     Cipher pbeCipher = Cipher.getInstance(encryptedKey.getAlgName()); 
     // Initialize PBE Cipher with key and parameters 
     pbeCipher.init(Cipher.DECRYPT_MODE, passKey, encryptedKey.getAlgParameters()); 

     // Decrypt the private key 

     byte [] encodedPrivateKey = pbeCipher.doFinal(encryptedKey.getEncryptedData()); 
     PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedPrivateKey); 
     KeyFactory kf = KeyFactory.getInstance("RSA"); 
     return kf.generatePrivate(privateKeySpec); 

    } 

    public static void main(String[] args) throws Exception { 
     PrivateKey pk = parsePrivateKey("x.pk8", "pass".toCharArray()); 
    } 
} 

Sie letzte Zeile, return new String(instance.sign(), UTF_8); keinen Sinn machen als Signature.sign() ein Array von Bytes zurückgibt, die nicht wahrscheinlich ist, eine gültige Zeichenfolge in jedem Zeichensatz sein. Wenn Sie die Signatur in eine Zeichenfolge konvertieren müssen, ist der Standard Weg zu Base64 es zu kodieren.

+0

Ich bekomme "ASN1Exception: Wrong content length" egal welches Byte [] ich feed zu dieser Funktion: ganze pem string, ohne Header, ohne Header Base64 decodiert. Welches Byte [] soll ich von pem string bekommen? –

+0

@ildarisalin: Ich habe meine Antwort bearbeitet, um ein vollständigeres Beispiel zu zeigen. –

+0

danke, ich werde Ihre Antwort als akzeptiert markieren. aber immer noch, ich bekomme eine NoSuchAlgorithmException bei "SecretKeyFactory.getInstance (encryptedKey.getAlgName())". Ich habe einige Android-unterstützte Algorithmen ausprobiert, aber ohne Glück. Ich denke, ich muss versuchen, openssl zu verwenden –

Verwandte Themen