Une grande quantité de fichiers ont été chiffrés par
openssl enc -aes-256-cbc -pass pass:MYPASSWORD
Openssl doit dériver la clé + IV de la phrase secrète. J'aimerais connaître la clé + l'équivalent IV de ce MYPASSWORD. Est-ce possible?
Je connais MYPASSWORD. Je pourrais décrypter puis rechiffrer avec une nouvelle clé connue + IV avec:
openssl enc -d -aes-256-cbc -pass pass:MYPASSWORD
openssl enc -aes-256-cbc -K MYKEY -IV MYIV
Mais le problème est que la quantité de données est assez importante.
L'utilisation de l'option de ligne de commande openssl enc
Est décrite là . Ci-dessous, je répondrai à votre question, mais n'oubliez pas de jeter un œil à la dernière partie de mon texte, où je regarde ce qui se passe sous le capot. C'est instructif.
OpenSSL utilise un algorithme de dérivation de clé salé. Le sel est un morceau d'octets aléatoires générés lors du cryptage, stocké dans l'en-tête du fichier; lors du déchiffrement, le sel est récupéré de l'en-tête, et la clé et IV sont recalculés à partir du mot de passe fourni et salt.
Sur la ligne de commande, vous pouvez utiliser l'option -P
(Majuscule P) pour imprimer le sel, la clé et l'IV, puis quitter. Vous pouvez également utiliser le -p
(P minuscule) pour imprimer le sel, la clé et l'IV, puis procéder au chiffrement. Essayez d'abord ceci:
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P
Si vous exécutez cette commande plusieurs fois, vous remarquerez que chaque invocation renvoie des valeurs différentes! En effet, en l'absence du drapeau -d
, openssl enc
Fait chiffrement et génère un sel aléatoire à chaque fois. Comme le sel varie, il en va de même pour la clé et l'IV. Ainsi, l'indicateur -P
N'est pas très utile lors du cryptage; le drapeau -p
, cependant, peut être utilisé. Essayons encore; cette fois, nous avons le fichier foo_clear
que nous voulons chiffrer dans foo_enc
. Lançons ceci:
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -p -in foo_clear -out foo_enc
Cette commande va crypter le fichier (créant ainsi foo_enc
) et imprimer quelque chose comme ceci:
salt=A68D6E406A087F05
key=E7C8836AD32C688444E3928F69F046715F8B33AF2E52A6E67A626B586DE8024E
iv=B9F128D827203729BE52A834CC0890B7
Ces valeurs sont le sel, la clé et l'IV réellement utilisés pour crypter le fichier.
Si je veux les récupérer par la suite, je peux utiliser le drapeau -P
En conjonction avec le drapeau -d
:
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -d -P -in foo_enc
qui affichera le même sel, clé et IV comme ci-dessus, à chaque fois. Comment? C'est parce que cette fois, nous sommes décryptage, donc l'en-tête de foo_enc
Est lu et le sel récupéré. Pour une valeur de sel donnée, la dérivation du mot de passe en clé et IV est déterministe.
De plus, cette récupération de clé et IV est rapide, même si le fichier est très long, car l'indicateur -P
Empêche le décryptage réel; il lit le en-tête, mais s'arrête là.
Alternativement , vous pouvez spécifier la valeur de sel avec le drapeau -S
, Ou désactiver complètement le sel avec -nosalt
. Le chiffrement non salé est déconseillé du tout car il peut permettre d'accélérer le craquage de mot de passe avec des tables pré-calculées (le même mot de passe donne toujours la même clé et IV). Si vous fournissez la valeur du sel, vous devenez alors responsable de la génération de sels appropriés, c'est-à-dire que vous essayez de les rendre aussi uniques que possible (dans la pratique, vous devez les produire au hasard). Il est préférable de laisser openssl
gérer cela, car il y a amplement de place pour les échecs silencieux ("silent" signifiant "faible et fissurable, mais le code fonctionne toujours afin que vous ne détectiez pas le problème pendant vos tests").
Le format de chiffrement utilisé par OpenSSL n'est pas standard: c'est "ce que fait OpenSSL", et si toutes les versions d'OpenSSL ont tendance à s'accorder entre elles, il n'y a toujours pas de document de référence qui décrit ce format à l'exception du code source OpenSSL. Le format d'en-tête est assez simple:
magic value (8 bytes): the bytes 53 61 6c 74 65 64 5f 5f
salt value (8 bytes)
D'où un en-tête de 16 octets fixe, commençant par le ASCII encodage de la chaîne Salted__
, Suivi du sel lui-même. C'est tout! Aucune indication de l'algorithme de cryptage; vous êtes censé le suivre vous-même.
Le processus par lequel le mot de passe et le sel sont transformés en clé et IV n'est pas documenté, mais le code source montre qu'il appelle la fonction spécifique à OpenSSL EVP_BytesToKey()
, qui utilise une fonction personnalisée fonction de dérivation de clé (KDF) avec un hachage répété. Il s'agit d'une construction non standard et mal vérifiée (!) Qui repose sur la fonction de hachage MD5 de réputation douteuse (!!); cette fonction peut être modifiée sur la ligne de commande avec l'indicateur non documenté-md
(!!!); le "nombre d'itérations" est défini par la commande enc
sur 1 et ne peut pas être modifié (!!!!). Cela signifie que les 16 premiers octets de la clé seront égaux à MD5 (mot de passe || sel), et c'est tout.
C'est assez faible! Quiconque sait écrire du code sur un PC peut essayer de casser un tel schéma et pourra "essayer" plusieurs dizaines de millions de mots de passe potentiels par seconde (des centaines de millions seront réalisables avec un GPU). Si vous utilisez openssl enc
, Assurez-vous que votre mot de passe a une entropie très élevée! (c'est-à-dire plus élevé que d'habitude recommandé; visez 80 bits, à moins). Ou, de préférence, ne l'utilisez pas du tout; au lieu de cela, optez pour quelque chose de plus robuste ( GnuPG , lorsque vous effectuez un cryptage symétrique pour un mot de passe, utilise un KDF plus fort avec de nombreuses itérations de la fonction de hachage sous-jacente).
Avez-vous essayé le -P
option?
openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P
salt=28C5AD65428E4FD2
key=215202893B8CFEE68E733F69C55AE4C7BED7B2A06533774F3EA0894880E585E6
iv =186DE986FC69F8E47ED692B24D940BED
Je voudrais connaître l'équivalent clé + IV de ce MYPASSWORD
Il vous suffit de répliquer la fonction de dérivation de clé dans EVP_BytesToKey
, ce qui est assez simple.
Si vous ne spécifiez pas -md
(ou spécifiez -md md5
) alors le KDF utilisé est basé sur MD5 mais les 16 premiers octets sont dérivés en utilisant PKCS # 5 PBKDF1 avec un nombre d'itérations de 1
. Ceci est ensuite étendu en utilisant l'algorithme de dérivation de clé spécifié dans EVP_BytesToKey
pour répondre aux exigences de taille de la clé et IV
Si vous spécifiez la fonction de hachage sous-jacente à l'aide de -md
et choisissez une fonction de hachage autre que MD5 (par exemple -md sha256
), puis OpenSSL uniquement KDF spécifié dans EVP_BytesToKey
(et non PBKDF1).
Implémentation en Python 3 (nécessite passlib ):
import hashlib, binascii
from passlib.utils.pbkdf2 import pbkdf1
def hasher(algo, data):
hashes = {'md5': hashlib.md5, 'sha256': hashlib.sha256,
'sha512': hashlib.sha512}
h = hashes[algo]()
h.update(data)
return h.digest()
# pwd and salt must be bytes objects
def openssl_kdf(algo, pwd, salt, key_size, iv_size):
if algo == 'md5':
temp = pbkdf1(pwd, salt, 1, 16, 'md5')
else:
temp = b''
fd = temp
while len(fd) < key_size + iv_size:
temp = hasher(algo, temp + pwd + salt)
fd += temp
key = fd[0:key_size]
iv = fd[key_size:key_size+iv_size]
print('salt=' + binascii.hexlify(salt).decode('ascii').upper())
print('key=' + binascii.hexlify(key).decode('ascii').upper())
print('iv=' + binascii.hexlify(iv).decode('ascii').upper())
return key, iv
Exemples (testés avec OpenSSL 0.9.8 et 1.0.1):
openssl_kdf('md5', b'test', b'\xF6\x81\x8C\xAE\x13\x18\x72\xBD', 32, 16)
# generates the same output as:
openssl enc -aes-256-cbc -P -pass pass:test -S F6818CAE131872BD
openssl_kdf('sha256', b'test', b'\xF6\x81\x8C\xAE\x13\x18\x72\xBD', 32, 16)
# generates the same output as:
openssl enc -aes-256-cbc -P -pass pass:test -S F6818CAE131872BD -md SHA256
Dans openssl récent (également testé avec OpenSSL 1.1.0h 27 mars 2018), il semble facile et direct de vérifier:
openssl version
OpenSSL 1.0.2k-fips 26 Jan 2017
echo -n salt1234 | od -A n -t x1 | Perl -lpe's,\s+,,g'
73616c7431323334
openssl enc -e -aes-128-cbc -pass pass:123 -S 73616c7431323334 -P -md sha256
salt=73616C7431323334
key=5A7C52236BAEAE1A92A6B2D1E50C43ED
iv =9F629A34588A4006FE1C7E8FC664B5EC
echo -n 123salt1234 | openssl dgst -sha256 -binary | hexdump -Cv
00000000 5a 7c 52 23 6b ae ae 1a 92 a6 b2 d1 e5 0c 43 ed |Z|R#k.........C.|
00000010 9f 62 9a 34 58 8a 40 06 fe 1c 7e 8f c6 64 b5 ec |.b.4X.@...~..d..|
00000020
Si vous regardez attentivement, le -P
la sortie correspond à la sortie hexdump.
Conclusion: n'utilisez pas enc
pour autre chose que l'étude et l'exploration, c'est juste un joli jouet (au cas où vous ne le saviez pas déjà).