Nie można odszyfrować AES za pomocą OpenSSL

3

Pracuję nad grą CTF:

Szyfrowane za pomocą AES w trybie EBC. Wszystkie wartości zakodowane w base64

ciphertext = 8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L
key = 3q1FxGhuZ5fQYbjzDxgQ35==

Próbowałem odszyfrować go w moim terminalu, pozostawiając tekst szyfrowany w base64 i używając -base64flagi, bez powodzenia. Potem poszedłem na http://extranet.cryptomathic.com/aescalc , gdzie po przekonwertowaniu wartości na hex mogłem odszyfrować:

key: DEAD45C4686E6797D061B8F30F1810DF 
text: F0B0545597C37C8EB09E0806D6E518B90B11A06774F291B01C237EF91E6B69B316F4F26658759C4AB8F2E537DF7E3E8B
out: 7B796F755F73686F756C645F6E6F745F706F73745F7468655F61637475616C5F6374665F76616C75657D5F5F5F5F5F5F

Potem wróciłem do terminala, próbując:

echo -n F0B0545597C37C8EB09E0806D6E518B90B11A06774F291B01C237EF91E6B69B316F4F26658759C4AB8F2E537DF7E3E8B | openssl enc -d -K DEAD45C4686E6797D061B8F30F1810DF -aes-128-ecb -nosalt

ale dostałem ten sam błąd:

bad decrypt
140735124906848:error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt:evp_enc.c:531:

Próbowałem tego na Ubuntu 17.04, a teraz na MacOSX przy użyciu OpenSSL 1.0.2l. Dlaczego nie mogę odszyfrować we własnym terminalu?

Robert
źródło
Ponieważ dotyczy to CTF, zastąpiłem rzeczywiste wartości roboczymi symbolami zastępczymi. ;)
Lery

Odpowiedzi:

5

Ponieważ openssldomyślnie używa dopełniania PKCS # 7, a tekst jawny nie zawiera dopełniania PKCS # 7. Jeśli twój tekst jawny został uzupełniony, to został uzupełniony bajtami wartości 5F. -nopadZamiast tego użyj opcji: wypełnienie z wartością 5Fnie jest żadnym znanym mi schematem wypełniania; jeśli trzeba go usunąć, musisz go usunąć samodzielnie.

Obecnie wyświetlasz dane wejściowe w postaci szesnastkowej. Szesnastkowy to reprezentacja bajtów, a nie same wartości bajtów. Musisz albo bezpośrednio wprowadzić materiał źródłowy z pliku, używając <pliku, albo dekodować dane wejściowe w trybie szesnastkowym.

Dane wyjściowe będą również binarne; nie będzie reprezentował żadnego czytelnego tekstu jawnego. Może więc być konieczne przekonwertowanie wyniku na szesnastkowe przed porównaniem go z wartościami w pytaniu.

Maarten Bodewes
źródło
1
Googlowałem i dostałem jedną z moich odpowiedzi :)
Maarten Bodewes
1
5F pojawia się w odszyfrowanej wiadomości.
Robert
1
Tak, wypełnianie jest wykonywane przed szyfrowaniem za pomocą szyfru blokowego / trybu działania, a zatem po deszyfrowaniu.
Maarten Bodewes
1
OK, teraz rozumiem. Za pomocą -nopadnie ma już komunikatów o błędach, ale dane wyjściowe są nieprawidłowe, niektóre śmieci.
Robert
1
AES to 128-bitowy / 16-bajtowy szyfr blokowy, dlatego nie jest możliwe stosowanie wypełniania zgodnego z PKCS # 5, ponieważ jest zdefiniowany tylko dla 64-bitowych / 8-bajtowych szyfrów blokowych . Jeśli dane wyjściowe wyglądają jak śmieci, to prawdopodobnie dlatego, że dane wyjściowe są interpretowane jako US-ASCII / UTF-8 (lub dowolny inny zestaw znaków w systemie). Skieruj dane wyjściowe do pliku za pomocą, >a następnie otwórz je w edytorze szesnastkowym, a następnie porównaj wyniki, nie wcześniej.
Maarten Bodewes
3

Cóż, możesz rozważyć użycie Pythona lub innego języka skryptowego / programowania do takich rzeczy.

Zalety robienia tego programowo to:

  • Ilekroć będziesz musiał powtórzyć coś podobnego, będziesz mieć gotowy kod.
  • Możesz pisać komentarze, aby wyjaśnić, co się dzieje, więc jeśli kiedyś będziesz musiał zrozumieć, co zrobiłeś wcześniej, mam nadzieję, że kod i komentarze pozwolą ci to zrobić.
  • Wiele rzeczy, takich jak kodowanie, obsługa bajtów itp., Jest łatwiejszych niż w konsoli
  • Większość języków jest wieloplatformowa, więc łatwo będzie działać na systemach Windows, Linux i Android, jeśli raz przełączysz urządzenie.

Jeśli chodzi o twój problem, można go rozwiązać za pomocą Pythona, aby zrobić wszystko:

# we import the function we need from common librairies
from base64 import b64decode
from Crypto.Cipher import AES
from binascii import hexlify, unhexlify


# First we decode the message and the key from base64 into bytes:
msg = b64decode("8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L")
key = b64decode("3q1FxGhuZ5fQYbjzDxgQ35==")

# We then instantiate a cipher_suite using AES with the provided key, in ECB mode
cipher_suite = AES.new(key, AES.MODE_ECB)

# We can decrypt the message using our cipher_suite:
recovered = cipher_suite.decrypt(msg)

# We can print it:
print ("plaintext: ", recovered)

# There is some garbage at the end, but if we display it in hexadecimal form:
print ("in hex:", hexlify(recovered))
# We can see it's just padding using '5f', so let's create a function to remove such padding:
def unpad(padded):
  # we declare the value of our padding:
  paddingByte = unhexlify('5f')
  # we do a loop, while the last byte is padding
  while padded[-1:]==paddingByte:
    # we remove the last byte
    padded = padded[:-1]
  # once it's done, we return
  return padded

# We can now use our function to remove padding:
print ("unpadded: ", unpad(recovered))

Teraz, jeśli nie chcesz nauczyć się języka Python lub innego języka i / lub naprawdę chcesz to wszystko zrobić w swoim terminalu, jest to również możliwe: wtedy możesz zrobić wszystko bezpośrednio za pomocą potoków, aby przesłać dane z jednego polecenie do drugiej, podstawienie polecenia , aby podać odpowiedni klucz do openssl, i polecenia base64do obsługi base64 plus xxddo konwersji danych binarnych na hex (dla klucza w openssl), a na koniec użyj seddo usunięcia 5fdopełnienia:

echo "8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L" | base64 --decode | openssl enc -d -K $(echo "3q1FxGhuZ5fQYbjzDxgQ35==" | base64 --decode | xxd  -c 16 -ps) -aes-128-ecb -nosalt -nopad | sed 's/_*$//g'

Nie wiem dlaczego, ale osobiście uważam, że podejście do Pythona jest czystsze.


Wspomniałeś również, że uzyskałeś śmieci w sposób wskazany przez Maarten Bodewes, wynika to z faktu, że podajesz wartości szesnastkowe do OpenSSL, podczas gdy powinieneś podać bezpośrednio dane binarne (nie wartość szesnastkową) dla wiadomości, podczas gdy ty powinien podać klucz w systemie szesnastkowym:

echo -n f0b0545597c37c8eb09e0806d6e518b90b11a06774f291b01c237ef91e6b69b316f4f26658759c4ab8f2e537df7e3e8b | xxd -r -p | openssl ...

PS: prawdopodobnie powinieneś unikać publikowania rzeczywistych wartości, które napotykasz w CTF, ponieważ może to zepsuć grę dla osób, których pierwszym odruchem jest wyszukanie wartości w Google.

Lery
źródło
2

dekodować base64 przez

echo 8LBUVZfDfI6wnggG1uUYuQsRoGd08pGwHCN++R5rabMW9PJmWHWcSrjy5Tfffj6L | base64 -D > aesdata.dat

( -Dto dziwactwo Mac OS. Linux zwykle używa -dlub --decodezamiast tego).

Podobnie:

echo 3q1FxGhuZ5fQYbjzDxgQ35== | base64 -D > aeskey.dat

ale openssl oczekuje wartości szesnastkowych w parametrach (ale binarnych w plikach szyfrów):

xxd -p < aeskey.datdaje dead45c4686e6797d061b8f30f1810df. Lub potok z poprzedniego polecenia, jeśli chcesz uniknąć bałaganu.

Wreszcie:

openssl enc -d -nopad -aes-128-ecb -K dead45c4686e6797d061b8f30f1810df -in aesdata.dat -out plain

odszyfruje to. Opcja -nopad pozwala uniknąć błędu odszyfrowywania, ponieważ zastosowano niestandardowe wypełnienie.

Teraz hd plainsprawdź wynik, którego rzeczywiście szukałeś.

Henno
źródło