Background: Sto scrivendo un GPL Python OpenPGP su parser JSON che sto testando su file generati con GPG 1.4.16.
Se viene fornita una passphrase, il parser genererà le chiavi utilizzando i metodi stringa-chiave e alla fine decodificherà i messaggi.
Sto iniziando con i messaggi di crittografia simmetrica:
echo "hello" | gpg --s2k-mode=0 --symmetric > symmetric.simples2k.gpg
... e usando "foo" come passphrase.
Questo genera un pacchetto con un SymmetricKeyEncryptedSessionKeyPacket
e un SymmetricEncryptedandIntegrityProtectedDataPacket
pacchetto, come previsto.
I parametri S2K creati da GPG sono: S2K semplice ( link ) con hash SHA1 e AES256 cifra simmetrica.
Problema: quando ricavo la chiave dalla passphrase foo
utilizzando SimpleS2K, quindi tento di decodificare con AES256, non decodifica correttamente. Quindi la prima parte della mia indagine sta verificando che sto facendo correttamente il S2K.
Ecco le mie conoscenze su come generare la chiave dalla passphrase foo
utilizzando SimpleS2K
- Crea due hash SHA1 (poiché AES256 richiede una chiave da 32 byte, SHA1 produce hash da 20 byte)
- Non precaricare le rondelle [0]
- Aggiorna
hashers[1]
con 0x00 - Aggiorna
hashers[0]
con UTF-8 codificatofoo
- Aggiorna
hashers[0]
con UTF-8 codificatofoo
- Concatena
hashers[0].digest
piùhashers[1].digest
- Prendi i primi 32 byte di risultato (ovvero elimina gli ultimi 8 byte)
Ecco un'implementazione dimostrativa in Python 3:
import hashlib
from Crypto.Cipher import AES # using pycrypto==2.6.1
def format_octets(octets):
return ' '.join(['{:02x}'.format(x) for x in octets])
hasher_0 = hashlib.sha1()
hasher_1 = hashlib.sha1()
hasher_1.update(bytes([0x0]))
hasher_0.update('foo'.encode('utf-8'))
hasher_1.update('foo'.encode('utf-8'))
key = (hasher_0.digest() + hasher_1.digest())[0:32]
print('s2k key: {}'.format(format_octets(key)))
encrypted_data = bytes([
0x0b, 0x1e, 0xcf, 0x86, 0x33, 0x08, 0xfd, 0x66, 0x9a, 0xf0, 0xbe, 0x48,
0x62, 0xa4, 0xa5, 0x42, 0x4f, 0xd8, 0x20, 0xfe, 0x16, 0xe4, 0x4c, 0xdb,
0x80, 0x89, 0xee, 0x34, 0x72, 0xef, 0x52, 0x36, 0x70, 0x15, 0x01, 0x82,
0xd5, 0x0e, 0xeb, 0x61, 0xba, 0xe7, 0x71, 0x4a, 0x8c, 0x22, 0x6a, 0x9c,
0x79, 0x8f, 0xe3, 0xda, 0x31, 0xfc, 0xad, 0x14, 0xeb, 0x8a])
block_size = 16 # AES
iv = bytes([0x0] * block_size) # all-zero initialisation vector
obj = AES.new(key, AES.MODE_CFB, iv)
decrypted = obj.decrypt(encrypted_data)
random_octets = decrypted[0: block_size]
repeated_octets = decrypted[block_size: block_size + 2]
plaintext_packets = decrypted[block_size + 2:-20]
sha1 = decrypted[-20:]
print('random octets: {}'.format(format_octets(random_octets)))
print('repeated octets: {}'.format(format_octets(repeated_octets)))
print('plaintext_packets: {}'.format(format_octets(plaintext_packets)))
print('sha1: {}'.format(format_octets(sha1)))
Quali output
s2k key: 0b ee c7 b5 ea 3f 0f db c9 5d 0d d4 7f 3c 5b c2 75 da 8a 33 5a 8c aa 40 39 fd bc 02 c0 1a 64 9c
random octets: 48 9b 65 84 01 f7 33 23 0a 6e e4 32 9d c4 ef 99
repeated octets: 56 a8
plaintext_packets: b9 fd 5a 05 6e d2 83 22 22 fe e5 d7 77 dd 93 49 4f 03 fe 13
sha1: ce 7d 93 34 59 f6 71 70 c3 bd 06 94 ad 97 f3 0a 59 72 1d 93
L'output JSON completo è qui: link
Speriamo di poter escludere la parte S2K e passare alla parte AES:)
Grazie!