Come decrittografare manualmente un messaggio SOAP usando openssl?

3

Quindi ho un messaggio SOAP come questo (dati chiave e dati crittografati sono stati troncati):



<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" xmlns:a="http://www.w3.org/2005/08/addressing" xmlns:u="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
  <s:Header>
    <o:Security xmlns:o="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" s:mustUnderstand="1">
      <e:EncryptedKey xmlns:e="http://www.w3.org/2001/04/xmlenc#" Id="_0">
        <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5"/>
        <KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
          <o:SecurityTokenReference>
            <X509Data>
              <X509IssuerSerial>
                <X509IssuerName>CN=blah, O=blah, L=blah, S=blah, C=blah</X509IssuerName>
                <X509SerialNumber>1</X509SerialNumber>
              </X509IssuerSerial>
            </X509Data>
          </o:SecurityTokenReference>
        </KeyInfo>
        <e:CipherData>
          <e:CipherValue>TiMPCLfQgfw==</e:CipherValue>
        </e:CipherData>
        <e:ReferenceList>
          <e:DataReference URI="#_2"/>
        </e:ReferenceList>
      </e:EncryptedKey>
    </o:Security>
  </s:Header>
  <s:Body xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" u:Id="_1">
    <e:EncryptedData xmlns:e="http://www.w3.org/2001/04/xmlenc#" Id="_2" Type="http://www.w3.org/2001/04/xmlenc#Content">
      <e:EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#aes256-cbc"/>
      <e:CipherData>
        <e:CipherValue>1qsIPulqkVQ3==</e:CipherValue>
      </e:CipherData>
    </e:EncryptedData>
  </s:Body>
</s:Envelope>

Quindi il corpo è stato codificato in aes-256-cbc e quindi la chiave di sessione che ha fatto questa codifica è stata codificata con la mia chiave pubblica.

La mia domanda è: come posso decodificarlo manualmente?

Stavo cercando quanto segue:

  1. Copia la chiave di sessione crittografata su un file

    echo "TiMPCLfQgfw==" > sessionkey.enc

  2. Formatta la chiave in 64 caratteri max per riga:

    sed -e "s/.{64}/&\n/g" < sessionkey.enc > sessionkey.hex

  3. Converti la chiave di sessione in formato binario per openssl (dato che il comando rsautl funziona solo con binario):

    openssl enc -in sessionkey.hex -out sessionkey.bin -d -a

  4. Decrittografa la chiave di sessione usando openssl e privatekey:

    openssl rsautl -decrypt -in sessionkey.bin -out sessionkey.dec -inkey myprivatekey.key

  5. Copia il corpo del messaggio crittografato in un file

    echo "1qsIPulqkVQ3==" > messagebody.enc

  6. Formatta il corpo del messaggio crittografato a 64 caratteri per riga (formato esadecimale):

    sed -e "s/.{64}/&\n/g" < messagebody.enc > messagebody.hex

  7. Converti la chiave del corpo del messaggio nel formato binario per openssl:

    openssl enc -in messagebody.hex -out messagebody.bin -d -a

  8. Decifra il corpo del messaggio usando openssl e chiave di sessione:

    openssl enc -aes-256-cbc -d -in messagebody.bin -out messagebody.dec -kfile sessionkey.dec

Ma ottengo "numero magico magico" su questo ultimo passaggio quando provo questo. Qualche idea, perché?

    
posta Barry Pollard 17.04.2013 - 14:38
fonte

2 risposte

1

OK, finalmente l'ho capito da solo dopo molte prove ed errori.

I passaggi sono:

  1. Copia la chiave di sessione crittografata in un file e base64 la decodifica allo stesso tempo

echo "TiMPCLfQgfw==" | base64 -d -i > sessionkey.enc

  1. Decrittografa la chiave di sessione usando openssl e privatekey:

openssl rsautl -decrypt -in sessionkey.enc -out sessionkey.dec -inkey myprivatekey.key

  1. Copia la chiave di sessione crittografata in un file e base64 la decodifica allo stesso tempo

echo "1qsIPulqkVQ3==" | base64 -d -i > body.enc

  1. Leggi la tua chiave di sessione in esadecimale (sono sicuro che c'è un modo più semplice per farlo, ma ecco un modo usando il comando hexdump unix):

hexdump -C sessionkey.dec

E diciamo che assomiglia a questo (questa chiave troppo breve per aes256 ma è solo a scopo dimostrativo):

00000000  8a bc f2 86 25 4c 76 c4                           |....%Lv.|
00000008
  1. Leggi il tuo corpo in esadecimale (ancora una volta devi scrivere questo script):

hexdump -C body.enc

e diciamo che assomiglia a questo:

00000000  80 33 28 0f 7a fa 73 f3  7e 4a 93 e6 a7 5f fe 2d  |.3(.z.s.~J..._.-|
00000010  29 88 84 4e e5 23 33 b8  0e 1a 43 fb 43 b1 83 ce  |)..N.#3...C.C...|
00000020

Il primo blocco (80 - f3) è la crittografia iv

  1. Decifra il messaggio utilizzando la versione esadecimale della chiave e la versione esadecimale di iv:

openssl enc -d -aes-256-cbc -in body.enc -K 8abcf286254c76c4 -iv 8033280f7afa73f3 -out body.dec

Si noti che all'inizio si otterrà un po 'di spazzatura, in quanto dovresti rimuovere la iv dall'inizio del corpo prima di decifrare.

Non bello, e può essere notevolmente migliorato con alcuni script, ma questo ti dà il succo di cosa fare.

    
risposta data 19.04.2013 - 18:55
fonte
4

(Non è "hex", ma Base64 . Non è un punto critico qui, ma se si ottiene la terminologia proprio allora diventa più facile cercare soluzioni sul Web.)

Quando si esegue la crittografia simmetrica, openssl enc , lo strumento della riga di comando, utilizza il proprio formato non standard, OpenSSL specifico, che non corrisponde a quello utilizzato da SOAP. OpenSSL aggiunge un'intestazione specifica (che è il "numero magico" di cui si lamenta) e un po 'di casualità (un "sale" - i sali hanno molto senso quando le chiavi sono password, ma non è questo il caso). In base alla specifica , crittografia con AES-256 -CBC in SOAP aggiunge semplicemente IV come i primi 16 byte e non ci sono intestazione e non sale. Ciò significa che il seguente dovrebbe funzionare (non l'ho provato):

  1. Estrai il IV:

    dd if=messagebody.bin of=iv.bin bs=16 count=1

  2. Converti l'IV in esadecimale (vero esadecimale questa volta, non Base64):

    ivhex=$(od -t x1 -w iv.bin | sed 's/^[0-9A-Fa-f]*//' | sed 's/ //g')

  3. Estrai i dati crittografati attuali:

    dd if=messagebody.in of=edata.bin bs=16 skip=1

  4. Applicare la decrittografia con IV esplicita e istruire OpenSSL non a riprodurre i propri giochi non standard con sali:

    openssl enc -aes-256-cbc -iv $ivhex -kfile sessionkey.dec -nosalt -in edata.bin -out cdata.bin

L'ultimo problema spinoso è il riempimento . OpenSSL, apparentemente, utilizza il padding PKCS # 7, il che significa che n byte vengono aggiunti ai dati al momento della crittografia, in modo che:

  • n è compreso tra 1 e 16 (almeno uno, al massimo sedici byte aggiunti);
  • la lunghezza imbottita totale è un multiplo di 16;
  • i n byte aggiunti hanno tutti il valore n .

SOAP, d'altro canto, richiede qualcosa di simile, tranne che richiede solo che l'ultimo byte aggiunto abbia valore n ; gli n-1 altri byte possono avere qualsiasi valore. Pertanto, quando OpenSSL decodifica i dati, potrebbe trovare un riempimento che non è esattamente quello che si aspetterebbe (dipende dal fatto che OpenSSL insista o meno su tutti i byte di riempimento aventi valore n , e su quali valori di byte di padding sono stati utilizzati da chi ha prodotto i dati crittografati in primo luogo.

Se il padding sembra essere un problema, prova ad aggiungere l'opzione -nopad al comando openssl enc ; quindi dovrai esaminare i dati binari ottenuti (ad es. con od ) e rimuovere tu stesso i byte di riempimento (di nuovo, con dd ).

(Tutto quanto sopra è stato scritto assumendo un sistema simile a Unix, ad esempio Linux o FreeBSD.)

    
risposta data 19.04.2013 - 18:57
fonte

Leggi altre domande sui tag