2010-06-02 4 views
9

J'ai un bloc de texte chiffré qui a été créé en utilisant l'algorithme JCE "PBEWithSHA256And256BitAES-CBC-BC". Le fournisseur est BouncyCastle. Ce que j'aimerais faire, c'est décrypter ce texte chiffré en utilisant l'API légère de BouncyCastle. Je ne veux pas utiliser JCE, car cela nécessite l'installation des fichiers de règles de compétence de force illimitée.Comment utiliser Bouncy Castle API léger avec AES et PBE

La documentation semble être mince sur le terrain quand il s'agit d'utiliser BC avec PBE et AES.

Voici ce que j'ai jusqu'ici. Le code de déchiffrement s'exécute sans exception mais renvoie des détritus.

Le code de cryptage,

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

Le code de décryptage,

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

Répondre

10

J'ai essayé ceci et cela a semblé fonctionner. Lourdement endettées de la classe BC 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

Merci Greg. Fonctionne très bien. – Adrian

+0

la ligne pGen.generateDerivedParameters (256, 128); est-ce la définition de la longueur de la clé? –

+1

@george_h: 256 est la longueur de la clé; 128 est la longueur IV. –

1

Ce n'est pas trivial pour générer la clé exactement comme les homologues JCE. Je viens de parcourir brièvement votre code. Trouvé au moins un écart. JCE utilise le générateur PKCS12 mais vous utilisez PKCS5S1.

Je ne suis pas surpris s'il y a d'autres différences. Vous devez comparer votre code avec la source BC.

+0

Merci pour ce ZZ. J'ai aussi essayé d'utiliser PKCS12, mais cela ne faisait aucune différence. – Adrian

8

Il y avait quelques problèmes avec votre méthode de Décrypter:

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

Les principaux problèmes sont la façon dont vous meniez le décryptage sans utiliser un chiffrement par bloc et la Taille IV manquante à la méthode generateDerivedParameters. J'ai vu le premier problème assez rapidement, le second était beaucoup moins évident. J'ai seulement découvert celui-là en regardant un test Bouncy Castle appelé PBETest.

+0

Merci laz. Votre solution fonctionne parfaitement, mais comme Greg a répondu en premier, c'est juste que j'accepte sa réponse. – Adrian

+0

Merci pour les commentaires. J'ai manqué d'une façon ou d'une autre que GregS ait fourni une réponse quand il l'a fait. Je suis intéressé à découvrir pourquoi la taille de ce vecteur d'initialisation doit être de 128 et comment quelqu'un est censé savoir ce qui est requis. C'est la partie qui m'a fait raccrocher. – laz

+1

Les grands esprits se ressemblent :) Je savais que AES est un chiffrement de bloc de 128 bits, donc l'IV pour AES sera toujours de 128 bits. J'aurais pu utiliser BlockCipher.getBlockSize() * 8 pour être plus générique. –

0

J'ai remarqué que votre méthode de cryptage accepte un mot de passe en tant que tableau de caractères, mais le décryptage accepte le mot de passe en octets. En Java, les caractères sont en 16 bits tandis que les octets sont en 8 bits. Cela pourrait entraîner des clés différentes pour crypter/décrypter et peut-être expliquer les problèmes avec des résultats décryptés charabia?

Questions connexes