2009-04-17 5 views
2

Y at-il un moyen de décrypter les fichiers qui ont été cryptés en utilisant openssl -des3 enc commande. Comment OpenSl utilise-t-il le mot de passe et le sel pour créer la clé?openssl des3 décryptage en Java

Répondre

5

L'utilitaire enc d'OpenSSL utilise un algorithme de dérivation de clé non standard (et de qualité médiocre) pour les mots de passe. Le code suivant montre comment l'utilitaire enc génère la clé et le vecteur d'initialisation, avec un salt et un mot de passe. Notez que enc stocke la valeur "salt" dans le fichier crypté lorsque l'option -salt est spécifiée (ce qui est essentiel pour la sécurité).

public InputStream decrypt(InputStream is, byte[] password) 
    throws GeneralSecurityException, IOException 
{ 
    /* Parse the "salt" value from the stream. */ 
    byte[] header = new byte[16]; 
    for (int idx = 0; idx < header.length;) { 
    int n = is.read(header, idx, header.length - idx); 
    if (n < 0) 
     throw new EOFException("File header truncated."); 
    idx += n; 
    } 
    String magic = new String(header, 0, 8, "US-ASCII"); 
    if (!"Salted__".equals(magic)) 
    throw new IOException("Expected salt in header."); 

    /* Compute the key and IV with OpenSSL's non-standard method. */ 
    SecretKey secret; 
    IvParameterSpec iv; 
    byte[] digest = new byte[32]; 
    try { 
    MessageDigest md5 = MessageDigest.getInstance("MD5"); 
    md5.update(password); 
    md5.update(header, 8, 8); 
    md5.digest(digest, 0, 16); 
    md5.update(digest, 0, 16); 
    md5.update(password); 
    md5.update(header, 8, 8); 
    md5.digest(digest, 16, 16); 
    iv = new IvParameterSpec(digest, 24, 8); 
    DESedeKeySpec keySpec = new DESedeKeySpec(digest); 
    SecretKeyFactory factory = SecretKeyFactory.getInstance("DESede"); 
    secret = factory.generateSecret(keySpec); 
    } 
    finally { 
    Arrays.fill(digest, (byte) 0); 
    } 

    /* Initialize the cipher. */ 
    Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); 
    cipher.init(Cipher.DECRYPT_MODE, secret, iv); 
    return new CipherInputStream(is, cipher); 
} 

Cette génération de clés et IV sont décrites dans le EVP_BytesToKey(3) documentation. La commande enc utilise 1 comme l'itération count (ce qui est une mauvaise idée, et a noté comme un bug dans la page de manuel pour ma version de enc), et MD5 comme algorithme de digestion — un algorithme "cassé".

Il n'est pas clair comment OpenSSL convertit le mot de passe en octets. Je suppose qu'il utilise l'encodage par défaut de la plateforme. Donc, si vous êtes coincé avec un mot de passe String (pas bon, car il ne peut pas être "zéro-ized"), vous pouvez simplement appeler password.getBytes() pour le convertir en byte[].

Si vous le pouvez, utilisez quelque chose comme le Console de Java 6 ou le JPasswordField de Swing pour obtenir un mot de passe. Ceux-ci retournent un tableau, ainsi vous pouvez "effacer" le mot de passe de la mémoire quand vous avez fini avec lui: Arrays.fill(password, '\0');

1

Merci, Erickson, pour votre publication. Cela m'a aidé énormément à essayer de recréer le mot de passe d'openssl pour la routine clé et IV.

Je me suis retrouvé avec quelque chose de légèrement différent, probablement parce que j'ai besoin de décrypter des données cryptées par blowfish plutôt que DES. Voir ci-dessous.

J'ai également découvert que openssl arrêtera de lire les mots de passe lorsqu'il rencontrera les octets 00, 0a ou 0d. Généralement, je pense que openssl ne lit que les caractères de mot de passe entre les octets 11 et 127. Donc pour l'exemple ci-dessous, j'ai un code qui précède celui qui tronque le mot de passe s'il contient 00, 0a ou 0d.

 /* Compute the key and IV with OpenSSL's non-standard method. */ 
    final byte[] digest = new byte[32]; 
    final MessageDigest md5 = MessageDigest.getInstance("MD5"); 
    md5.update(password, 0); 
    // append the salt 
    md5.update(salt); 
    // run the digest and output 16 bytes to the first 16 bytes to the digest array. Digest is reset 
    md5.digest(digest, 0, 16); 
    // write the first 16 bytes from the digest array back to the buffer 
    md5.update(digest, 0, 16); 
    // append the password 
    md5.update(password, 0); 
    // append the salt 
    md5.update(salt); 
    // run the digest and output 16 bytes to the last 16 bytes of the digest array 
    md5.digest(digest, 16, 16); 
    key = Arrays.copyOfRange(digest, 0, 16); 
    iv = Arrays.copyOfRange(digest, 16, 24); 

Ce code ci-dessus peut être remplacé par 3 lignes à l'aide org.bouncycastle.crypto.generators.OpenSSLPBEParametersGenerator. Il devient

final OpenSSLPBEParametersGenerator generator = new OpenSSLPBEParametersGenerator(); 
generator.init(password, salt); 
final ParametersWithIV ivParam = (ParametersWithIV)generator.generateDerivedParameters(16, 8); 
final KeyParameter keyParameter = (KeyParameter)ivParam.getParameters(); 
Questions connexes