it-swarm.dev

openssl: recupera chiave e IV tramite passphrase

Una grande quantità di file è stata crittografata da

    openssl enc -aes-256-cbc -pass pass:MYPASSWORD

Openssl dovrebbe derivare chiave + IV dalla passphrase. Mi piacerebbe sapere chiave + IV equivalente di quella MYPASSWORD. È possibile?

Conosco MYPASSWORD. Potrei decifrare e poi ri-crittografare con la nuova chiave nota + IV con:

    openssl enc -d -aes-256-cbc -pass pass:MYPASSWORD
    openssl enc -aes-256-cbc -K MYKEY -IV MYIV

Ma il problema è che la quantità di dati è piuttosto grande.

42

L'uso dell'opzione della riga di comando openssl enc È descritto . Di seguito, risponderò alla tua domanda, ma non dimenticare di dare un'occhiata all'ultima parte del mio testo, dove dare un'occhiata a cosa succede sotto il cofano. È istruttivo.


OpenSSL utilizza un algoritmo di derivazione chiave salato. Il salt è un pezzo di byte casuali generato durante la crittografia, memorizzato nell'intestazione del file; dopo la decrittazione, il salt viene recuperato dall'intestazione e la chiave e IV vengono ricalcolati dalla password fornita e salt.

Alla riga di comando, è possibile utilizzare l'opzione -P (P maiuscola) per stampare il sale, la chiave e il tasto IV, quindi uscire. Puoi anche usare il -p (P minuscola) per stampare il sale, la chiave e IV, quindi procedere con la crittografia. Prima prova questo:

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P

Se esegui questo comando più volte, noterai che ogni invocazione restituisce valori diversi! Questo perché, in assenza del flag -d, openssl enc Fa crittografia e genera un salt casuale ogni volta. Poiché il sale varia, così fanno la chiave e IV. Pertanto, il flag -P Non è molto utile durante la crittografia; il flag -p, tuttavia, può essere utilizzato. Proviamo di nuovo; questa volta, abbiamo il file foo_clear che vogliamo crittografare in foo_enc. Eseguiamo questo:

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -p -in foo_clear -out foo_enc

Questo comando crittograferà il file (creando così foo_enc) e stamperà qualcosa del genere:

salt=A68D6E406A087F05
key=E7C8836AD32C688444E3928F69F046715F8B33AF2E52A6E67A626B586DE8024E
iv=B9F128D827203729BE52A834CC0890B7

Questi valori sono il sale, la chiave e IV effettivamente utilizzati per crittografare il file.

Se voglio riaverli in seguito, posso usare il flag -P Insieme al flag -d:

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -d -P -in foo_enc

che stamperà ogni volta stesso salt, key e IV come sopra. Come mai? Questo perché questa volta siamo decrittografando, quindi viene letta l'intestazione di foo_enc E recuperato il sale. Per un dato valore salt, la derivazione della password in chiave e IV è deterministica.

Inoltre, questo recupero di chiave e IV è veloce, anche se il file è molto lungo, perché il flag -P Impedisce l'effettiva decodifica; legge header, ma si ferma qui.

In alternativa , puoi specificare il valore del sale con il flag -S O disattivare completamente il sale con -nosalt . La crittografia non salata è non consigliabile affatto perché può consentire di accelerare il cracking della password con tabelle pre-calcolate (la stessa password produce sempre la stessa chiave e IV). Se si fornisce il valore del sale, si diventa responsabili della generazione di sali adeguati, ovvero si cerca di renderli il più unici possibile (in pratica, è necessario produrli a caso). È preferibile lasciare che openssl lo gestisca, poiché c'è ampio spazio per guasti silenziosi ("silenzioso" significa "debole e crackabile, ma il codice funziona ancora in modo da non rilevare il problema durante i test").


Il formato di crittografia utilizzato da OpenSSL non è standard: è "ciò che fa OpenSSL" e se tutte le versioni di OpenSSL tendono a concordare tra loro, non esiste ancora alcun documento di riferimento che descriva questo formato tranne il codice sorgente OpenSSL. Il formato dell'intestazione è piuttosto semplice:

magic value (8 bytes): the bytes 53 61 6c 74 65 64 5f 5f
salt value (8 bytes)

Da qui un'intestazione fissa a 16 byte, che inizia con la ASCII della stringa Salted__, Seguita dal salt stesso. Questo è tutto! Nessuna indicazione dell'algoritmo di crittografia; sei dovrei seguirlo da solo.

Il processo mediante il quale la password e salt vengono trasformati nella chiave e IV non è documentato, ma il codice sorgente mostra che chiama lo specifico OpenSSL EVP_BytesToKey() , che utilizza una funzione di derivazione del tasto personalizzata (KDF) con alcuni hashing ripetuti. Questo è un costrutto non standard e non ben controllato (!) Che si basa sulla funzione hash MD5 di dubbia reputazione (!!); quella funzione può essere modificata dalla riga di comando con il flag non documentato-md (!!!); il "conteggio delle iterazioni" è impostato dal comando enc su 1 e non può essere modificato (!!!!). Ciò significa che i primi 16 byte della chiave saranno uguali a MD5 (password || salt), e basta.

Questo è abbastanza debole! Chiunque sappia scrivere codice su un PC può provare a decifrare un tale schema e sarà in grado di "provare" diverse dozzine di milioni di potenziali password al secondo (centinaia di milioni saranno raggiungibili con una GPU). Se usi openssl enc, Assicurati che la tua password abbia un'entropia molto alta! (cioè più alta del solito consigliata; punta a 80 bit, a meno). O, preferibilmente, non usarlo affatto; invece, cerca qualcosa di più robusto ( GnuPG , quando fa una crittografia simmetrica per una password, usa un KDF più forte con molte iterazioni della funzione hash sottostante).

91
Thomas Pornin

Hai provato il -P opzione?

openssl enc -aes-256-cbc -pass pass:MYPASSWORD -P

salt=28C5AD65428E4FD2
key=215202893B8CFEE68E733F69C55AE4C7BED7B2A06533774F3EA0894880E585E6
iv =186DE986FC69F8E47ED692B24D940BED
9
jdigital

Mi piacerebbe conoscere la chiave + IV equivalente di quella MYPASSWORD

Devi solo replicare la funzione di derivazione della chiave in EVP_BytesToKey , che è abbastanza semplice.

Se non si specifica -md (o specifica -md md5) quindi il KDF utilizzato è basato su MD5 ma i primi 16 byte sono derivati ​​utilizzando PKCS # 5 PBKDF1 con un conteggio di iterazioni di 1. Questo viene quindi esteso utilizzando l'algoritmo di derivazione chiave specificato in EVP_BytesToKey per soddisfare i requisiti di dimensione della chiave e IV

Se specifichi la funzione hash sottostante usando -md e scegli una funzione hash diversa da MD5 (ad esempio -md sha256), quindi OpenSSL sarà solo KDF specificato in EVP_BytesToKey (e non PBKDF1).

Implementazione in Python 3 (necessita 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

Esempi (testati con OpenSSL 0.9.8 e 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
5
Null

Nel recente openssl (testato anche con OpenSSL 1.1.0h 27 mar 2018) sembra facile e diretto verificare:

    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  |[email protected]~..d..|
00000020

Se osservi attentamente, il -P output corrisponde all'output hexdump.

Conclusione: non usare enc per altro che studio ed esplorazione, è solo un bel giocattolo (nel caso non lo sapessi già).

1
alexgirao