2010-06-02 26 views
9

Ich habe einen Block von Chiffretext, der mit dem JCE-Algorithmus "PBEWithSHA256And256BitAES-CBC-BC" erstellt wurde. Der Anbieter ist BouncyCastle. Was ich tun möchte, entschlüsseln Sie diesen Chiffretext mit der BouncyCastle Lightweight API. Ich möchte JCE nicht verwenden, da dies die Installation der Unzustellbarkeitsrichtlinie-Richtliniendateien erfordert.So verwenden Sie Bouncy Castle Lightweight-API mit AES und PBE

Dokumentation scheint dünn zu sein, wenn es darum geht, BC mit PBE und AES zu verwenden.

Hier ist, was ich bisher habe. Der Entschlüsselungscode läuft ohne Ausnahme, gibt aber Müll zurück.

Der Code-Verschlüsselung,

String password = "qwerty"; 
String plainText = "hello world"; 

byte[] salt = generateSalt(); 
byte[] cipherText = encrypt(plainText, password.toCharArray(), salt); 

private static byte[] generateSalt() throws NoSuchAlgorithmException { 
    byte salt[] = new byte[8]; 
    SecureRandom saltGen = SecureRandom.getInstance("SHA1PRNG"); 
    saltGen.nextBytes(salt); 
    return salt; 
} 

private static byte[] encrypt(String plainText, char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, InvalidAlgorithmParameterException, IllegalBlockSizeException, BadPaddingException { 
    Security.addProvider(new BouncyCastleProvider()); 

    PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 20); 

    PBEKeySpec pbeKeySpec = new PBEKeySpec(password); 
    SecretKeyFactory keyFac = SecretKeyFactory.getInstance("PBEWithSHA256And256BitAES-CBC-BC"); 
    SecretKey pbeKey = keyFac.generateSecret(pbeKeySpec); 

    Cipher encryptionCipher = Cipher.getInstance("PBEWithSHA256And256BitAES-CBC-BC"); 
    encryptionCipher.init(Cipher.ENCRYPT_MODE, pbeKey, pbeParamSpec); 

    return encryptionCipher.doFinal(plainText.getBytes()); 
} 

Der Code Entschlüsselung

byte[] decryptedText = decrypt(cipherText, password.getBytes(), salt); 

private static byte[] decrypt(byte[] cipherText, byte[] password, byte[] salt) throws DataLengthException, IllegalStateException, InvalidCipherTextException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { 
    BlockCipher engine = new AESEngine(); 
    CBCBlockCipher cipher = new CBCBlockCipher(engine); 

    PKCS5S1ParametersGenerator keyGenerator = new PKCS5S1ParametersGenerator(new SHA256Digest()); 
    keyGenerator.init(password, salt, 20); 

    CipherParameters keyParams = keyGenerator.generateDerivedParameters(256); 
    cipher.init(false, keyParams); 

    byte[] decryptedBytes = new byte[cipherText.length]; 
    int numBytesCopied = cipher.processBlock(cipherText, 0, decryptedBytes, 0); 

    return decryptedBytes; 
} 

Antwort

10

Ich versuchte dies und es schien zu funktionieren. stark von der BC-Klasse geborgt org.bouncycastle.jce.provider.test.PBETest

private byte[] decryptWithLWCrypto(byte[] cipher, String password, byte[] salt, final int iterationCount) 
     throws Exception 
{ 
    PKCS12ParametersGenerator pGen = new PKCS12ParametersGenerator(new SHA256Digest()); 
    char[] passwordChars = password.toCharArray(); 
    final byte[] pkcs12PasswordBytes = PBEParametersGenerator 
      .PKCS12PasswordToBytes(passwordChars); 
    pGen.init(pkcs12PasswordBytes, salt, iterationCount); 
    CBCBlockCipher aesCBC = new CBCBlockCipher(new AESEngine()); 
    ParametersWithIV aesCBCParams = (ParametersWithIV) pGen.generateDerivedParameters(256, 128); 
    aesCBC.init(false, aesCBCParams); 
    PaddedBufferedBlockCipher aesCipher = new PaddedBufferedBlockCipher(aesCBC, 
      new PKCS7Padding()); 
    byte[] plainTemp = new byte[aesCipher.getOutputSize(cipher.length)]; 
    int offset = aesCipher.processBytes(cipher, 0, cipher.length, plainTemp, 0); 
    int last = aesCipher.doFinal(plainTemp, offset); 
    final byte[] plain = new byte[offset + last]; 
    System.arraycopy(plainTemp, 0, plain, 0, plain.length); 
    return plain; 
} 
+0

Danke Greg. Funktioniert super. – Adrian

+0

die Zeile pGen.generateDerivedParameters (256, 128); setzt das die Schlüssellänge? –

+1

@george_h: 256 ist die Schlüssellänge; 128 ist die IV-Länge. –

1

Es ist nicht trivial ist der Schlüssel genau wie die JCE Pendants zu erzeugen. Ich habe nur kurz Ihren Code durchsucht. Gefunden mindestens eine Diskrepanz. JCE verwendet den PKCS12-Generator, aber Sie verwenden PKCS5S1.

Ich bin nicht überrascht, wenn es andere Unterschiede gibt. Sie müssen Ihren Code mit der BC-Quelle vergleichen.

+0

Danke für das ZZ. Ich habe auch versucht, PKCS12 zu verwenden, aber das machte keinen Unterschied. – Adrian

8

Es gibt ein paar Probleme mit Ihrer decrypt-Methode waren:

private static byte[] decrypt(final byte[] bytes, final char[] password, final byte[] salt) throws DataLengthException, IllegalStateException, InvalidCipherTextException, InvalidKeyException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException { 

    final PBEParametersGenerator keyGenerator = new PKCS12ParametersGenerator(new SHA256Digest()); 
    keyGenerator.init(PKCS12ParametersGenerator.PKCS12PasswordToBytes(password), salt, 20); 
    final CipherParameters keyParams = keyGenerator.generateDerivedParameters(256, 128); 

    final BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), new PKCS7Padding()); 
    cipher.init(false, keyParams); 

    final byte[] processed = new byte[cipher.getOutputSize(bytes.length)]; 
    int outputLength = cipher.processBytes(bytes, 0, bytes.length, processed, 0); 
    outputLength += cipher.doFinal(processed, outputLength); 

    final byte[] results = new byte[outputLength]; 
    System.arraycopy(processed, 0, results, 0, outputLength); 
    return results; 
} 

Die Hauptprobleme waren so, wie Sie die Entschlüsselung durchgeführt wurden, ohne Verwendung eine Blockchiffre und die fehlende IV-Größe zur generateDerivedParameters Methode. Ich sah das erste Problem ziemlich schnell, das zweite war viel weniger offensichtlich. Ich habe das nur durch einen Blick auf einen Hüpfburg-Test namens PBETest entdeckt.

+0

Danke laz. Ihre Lösung funktioniert perfekt, aber da Greg zuerst antwortete, ist es nur fair, dass ich seine Antwort akzeptiere. – Adrian

+0

Danke für die Rückmeldung. Ich habe irgendwie vermisst, dass GregS eine Antwort gab, als er es tat. Ich bin daran interessiert, herauszufinden, warum die Größe für diesen Initialisierungsvektor 128 sein muss und wie jemand wissen soll, dass dies erforderlich ist. Das war der Teil, der mich aufgelegt hat. – laz

+1

Großartige Köpfe denken gleich :) Ich wusste, dass AES eine 128-Bit Blockchiffre ist, also wird die IV für AES immer 128 Bit sein. Ich hätte BlockCipher.getBlockSize() * 8 verwenden können, um allgemeiner zu sein. –

0

Ich habe festgestellt, dass Ihre Verschlüsselungsmethode ein Passwort als Char-Array akzeptiert, aber die Entschlüsselung akzeptiert das Passwort als Byte. In Java sind Zeichen 16-Bit, während Bytes 8-Bit sind. Dies könnte zu unterschiedlichen Schlüsseln zum Verschlüsseln/Entschlüsseln führen und möglicherweise die Probleme mit entschlüsselten Ergebnissen erklären.

Verwandte Themen