OpenPGP (RFC4880) - sei d'accordo con la mia implementazione SimpleS2K (stringa-chiave)?

2

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

  1. Crea due hash SHA1 (poiché AES256 richiede una chiave da 32 byte, SHA1 produce hash da 20 byte)
  2. Non precaricare le rondelle [0]
  3. Aggiorna hashers[1] con 0x00
  4. Aggiorna hashers[0] con UTF-8 codificato foo
  5. Aggiorna hashers[0] con UTF-8 codificato foo
  6. Concatena hashers[0].digest più hashers[1].digest
  7. 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!

    
posta Paul M Furley 27.03.2015 - 15:35
fonte

0 risposte

Leggi altre domande sui tag