web-dev-qa-db-ja.com

OpenSSLでAESを復号化できません

私はctfゲームに取り組んでいます:

ECBモードのAESで暗号化されます。すべての値はbase64でエンコードされています

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

私は自分の端末でそれを復号化しようとしましたが、base64に暗号文を残し、-base64フラグ、運がない。次に、 http://extranet.cryptomathic.com/aescalc に移動しました。ここで、値を16進数に変換した後、復号化できました。

key: DEAD45C4686E6797D061B8F30F1810DF 
text: F0B0545597C37C8EB09E0806D6E518B90B11A06774F291B01C237EF91E6B69B316F4F26658759C4AB8F2E537DF7E3E8B
out: 7B796F755F73686F756C645F6E6F745F706F73745F7468655F61637475616C5F6374665F76616C75657D5F5F5F5F5F5F

次に、次のことを試みてターミナルに戻りました。

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

しかし、私は同じエラーを受け取りました:

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

これをUbuntu17.04で試しましたが、MacOSXでOpenSSL1.0.2lを使用して試しました。自分の端末で復号化できないのはなぜですか?

3
robert

opensslはデフォルトでPKCS#7パディングを使用し、プレーンテキストにはPKCS#7パディングが含まれていないためです。平文が埋め込まれている場合は、値5Fのバイトが埋め込まれています。代わりに、オプション-nopadを使用してください。値5Fでパディングすることは、私が知っているパディングスキームではありません。削除する必要がある場合は、自分で削除する必要があります。

現在、入力は16進数で表示されています。 16進数はバイトの表現であり、バイト値自体ではありません。ファイルの<を使用してファイルからソースマテリアルを直接入力するか、入力を16進デコードする必要があります。

出力もバイナリになります。読み取り可能な平文を表すものではありません。したがって、質問の値と比較する前に、出力を16進数に変換する必要がある場合があります。

5
Maarten Bodewes

まあ、あなたはpythonまたは他のスクリプト/プログラミング言語を使用してそのようなことをすることを検討したいかもしれません。

プログラムで行うことの利点は次のとおりです。

  • 同様のことをやり直す必要があるときはいつでも、コードを準備できます。
  • 何が起こっているのかを説明するコメントを書くことができるので、以前に行ったことを理解する必要がある場合、できればコードとコメントでそれが可能になることを望みます。
  • エンコーディング、バイト処理などの多くのことは、コンソールよりも簡単です
  • ほとんどの言語はクロスプラットフォームであるため、一度デバイスを切り替えると、Windows、Linux、Androidで簡単に動作します。

手元の問題に関しては、pythonを使用してすべてを実行することで解決できます:

# 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))

さて、あなたがPythonまたは他の言語を学びたくない場合、および/またはあなたが本当にしたい場合端末ですべてを行うには、それも可能です:次に、 pipes を使用してすべてを直接実行し、あるコマンドから別のコマンドにデータを渡し、 コマンド置換 をフィードすることができますopensslの右キー、およびコマンド base64 base64 plusを処理するには xxdでバイナリデータを16進数に変換 (opensslのキーの場合)最後にsedを使用して5fパディング:

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'

理由はわかりませんが、個人的にはpythonアプローチの方がクリーンだと思います。


また、Maarten Bodewesが示した方法を使用してガベージを取得したとおっしゃいましたが、これは、OpenSSLに16進値をフィードしているという事実に起因していますが、バイナリデータを直接提供する必要があります (16進値ではなく)メッセージの場合、16進でキーを指定する必要があります。

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

PS:CTFで遭遇する実際の値を投稿することはおそらく避けるべきです。なぜなら、最初の反射が値をグーグルすることである人々にとってゲームを台無しにする可能性があるからです。

3
Lery

base64をデコードする

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

-DはMacOSの癖です。Linuxは代わりに-dまたは--decodeを使用する傾向があります)。

同様に:

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

ただし、opensslはパラメータに16進値を期待します(ただし、暗号ファイルではバイナリ)。

xxd -p < aeskey.datdead45c4686e6797d061b8f30f1810dfを返します。または、混乱を避けたい場合は、前のコマンドからパイプします。

最後に:

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

それを解読します。 -nopadは、非標準のパディングが使用されるため、復号化エラーを回避します。

hd plainで結果を確認します。これは、まさにあなたが探していたものです。

2
Henno