Ruby DES-EDE3-CBC 暗号化データを Python で復号化する

概要

次のコードによってRubyで暗号化された大量のデータがあります

text = '12345678'
key = '6b4f0a29d4bba86add88be9d'
cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').encrypt
cipher.key = key
s = cipher.update(text) + cipher.final
encrypted_text = s.unpack('H*')[0].upcase
# => 3B223AA60F1921F34CBBBAC209ACDCE4

Rubyで復号化できる

cipher = OpenSSL::Cipher.new('DES-EDE3-CBC').decrypt
cipher.key = key
s = [encrypted_text].pack("H*").unpack("C*").pack("c*")
cipher.update(s) + cipher.final
# => 12345678

次に、Python でデータを復号化する必要があります。 以下のように暗号化コードを書きました。

from Crypto.Cipher import DES3
from Crypto import Random
from base64 import b64encode, b64decode
from Crypto.Util.Padding import pad, unpad

key = '6b4f0a29d4bba86add88be9d'
iv = Random.new().read(DES3.block_size)
cipher = DES3.new(key, DES3.MODE_CBC, iv)
text = '12345678'.encode()
encrypted = cipher.encrypt(text)
encrypted_text = encrypted.hex()
print(encrypted_text)
# => f84f555b02e3ee24

ご覧のとおり、暗号化されたデータは、少なくとも長さがまったく異なります。したがって、復号化部分は機能しません。 Ruby と互換性を持たせるために Python コードを変更するにはどうすればよいですか? 残念ながら、データは Ruby アプリケーションで入手できたので、Python のみを変更できました。

解決策

Ruby コードとの互換性を保つために、Python コードには次のものが欠けています。

これにより、Python コードを次のように修正する必要があります。

from Crypto.Cipher import DES3
from Crypto.Util.Padding import pad, unpad

key = '6b4f0a29d4bba86add88be9d'
iv = b'\0' *  DES3.block_size                       # apply a zero IV
cipher = DES3.new(key, DES3.MODE_CBC, iv)
text = pad('12345678'.encode(), DES3.block_size)    # pad
encrypted = cipher.encrypt(text)
encrypted_text = encrypted.hex()
print(encrypted_text.upper()) # => 3B223AA60F1921F34CBBBAC209ACDCE4

この変更により、Python コードは Ruby コードの結果を提供するようになりました。 対応する復号化は次のとおりです。

...
key = '6b4f0a29d4bba86add88be9d'
iv = b'\0' *  DES3.block_size     
cipher = DES3.new(key.encode(), DES3.MODE_CBC, iv)
ciphertext = bytes.fromhex('3B223AA60F1921F34CBBBAC209ACDCE4')
decrypted = cipher.decrypt(ciphertext)
decryptedUnpadded = unpad(decrypted, DES3.block_size)
print(decryptedUnpadded.decode('utf8')) # => 12345678

ただし、コードには脆弱性があることに注意してください。