2010-06-02 20 views
9

Ho un blocco di testo cifrato che è stato creato utilizzando l'algoritmo JCE "PBEWithSHA256And256BitAES-CBC-BC". Il fornitore è BouncyCastle. Quello che mi piacerebbe fare è decriptare questo testo cifrato usando l'API leggera di BouncyCastle. Non desidero utilizzare JCE perché è necessario installare i file dei criteri di giurisdizione illimitata.Come utilizzare l'API leggera di Bouncy Castle con AES e PBE

La documentazione sembra essere sottile sul terreno quando si tratta di utilizzare BC con PBE e AES.

Ecco quello che ho finora. Il codice di decrittazione funziona senza eccezioni ma restituisce spazzatura.

Il codice di crittografia,

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()); 
} 

Il codice di decrittazione,

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; 
} 

risposta

10

Ho provato questo e sembrava funzionare. Preso in prestito pesantemente dalla classe aC 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

Grazie Greg. Funziona alla grande. – Adrian

+0

la riga pGen.generateDerivedParameters (256, 128); è quella impostazione della lunghezza della chiave? –

+1

@george_h: 256 è la lunghezza della chiave; 128 è la lunghezza IV. –

1

Non è banale per generare la chiave esattamente come le controparti JCE. Ho solo sfogliato brevemente il tuo codice. Trovato almeno una discrepanza. JCE utilizza il generatore PKCS12 ma si utilizza PKCS5S1.

Non sono sorpreso se ci sono altre differenze. Devi confrontare il tuo codice con la fonte BC.

+0

Grazie per quella ZZ. Ho provato a usare anche PKCS12 ma non ha fatto alcuna differenza. – Adrian

8

Ci sono stati alcuni problemi con il metodo di decrypt:

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; 
} 

I problemi principali erano il modo in cui si stava effettuando la decrittazione senza utilizzare un cifrario a blocchi e la manca la dimensione IV al metodo generateDerivedParameters. Ho visto il primo problema abbastanza rapidamente, il secondo era molto meno ovvio. L'ho scoperto solo guardando un test di Bouncy Castle chiamato PBETest.

+0

Grazie laz. La tua soluzione funziona perfettamente, ma poiché Greg ha risposto per primo, è giusto che io accetti la sua risposta. – Adrian

+0

Grazie per il feedback. In qualche modo mi sono perso perché GregS ha fornito una risposta quando l'ha fatto. Sono interessato a scoprire perché la dimensione per quel vettore di inizializzazione deve essere 128 e come qualcuno dovrebbe sapere che è richiesto. Questa è stata la parte che mi ha fatto riattaccare. – laz

+1

Le grandi menti pensano allo stesso modo :) Sapevo che AES è un codice a 128 bit, quindi l'IV per AES sarà sempre a 128 bit. Avrei potuto usare BlockCipher.getBlockSize() * 8 per essere più generico. –

0

Ho notato che il metodo di crittografia accetta una password come array di caratteri ma il decrypt accetta password come byte. Nei caratteri Java sono 16 bit mentre i byte sono 8 bit. Ciò potrebbe comportare chiavi diverse per crittografare/decifrare e forse spiegare i problemi con risultati decifrati senza senso?

Problemi correlati