📝

PythonのCryptoでの暗号化時のエラー、cannot be passed to C codeを解決する方法

2022/01/04に公開

結論

・原因
 AES.new()に渡す引数が文字列だったこと
・解決策
 AES.new()に引数を渡す際に、encode()でバイト型に変換する

動画

https://youtu.be/UqWfnIkT2wo

環境

・Python 3.9
・PyCryptodome 3.12.0
・VSCode 1.63.2

発生した問題

PyCryptodomeモジュールを使用して暗号化しようとしたら、AES.new()の時点で以下のエラーが発生しました。

Object type <class 'str'> cannot be passed to C code

エラーが発生したコードは以下の通りです。

sample.py

import string
import random

from Crypto.Cipher import AES

key = ''.join(
    random.choice(string.ascii_letters) for _ in range(AES.block_size)
)

iv = ''.join(
    random.choice(string.ascii_letters) for _ in range(AES.block_size)
)

plaintext = "Hello World"
cipher = AES.new(key, AES.MODE_CBC, iv) #ここでエラー
padding_length = AES.block_size - len(plaintext) % AES.block_size
plaintext += chr(padding_length) * padding_length
cipher_text = cipher.encrypt(plaintext.encode())
print(cipher_text)

解決策

AES.new(key, AES.MODE_CBC, iv)keyivencode()でバイト型に変換します。

sample.py
import string
import random

from Crypto.Cipher import AES

key = ''.join(
    random.choice(string.ascii_letters) for _ in range(AES.block_size)
)
key = key.encode() #ここで変換

iv = ''.join(
    random.choice(string.ascii_letters) for _ in range(AES.block_size)
)
iv = iv.encode() #ここで変換

plaintext = "Hello World"
cipher = AES.new(key, AES.MODE_CBC, iv)
padding_length = AES.block_size - len(plaintext) % AES.block_size
plaintext += chr(padding_length) * padding_length
cipher_text = cipher.encrypt(plaintext.encode())
print(cipher_text)

実行結果

b'l\x99ZU~"\xeb\x05\x945\xee\x9a9\xd2\xce\xc1

エラーについてちょっと調べたみた

どうやら以前までのPyCryptoモジュールでは文字列でもよかったようなのですが、現在は非推奨となっているようです。
現在はPyCryptodomeモジュールが推奨されており、こちらでは文字列ではエラーになるため、バイト型への変換が必要なようです。
pycryptoを使ったデータの暗号化に失敗する
以下はpycrypto 2.6.1のドキュメントに記載されているサンプルですが、AES.new()に文字列を渡しています。

>>> from Crypto.Cipher import AES
>>> obj = AES.new('This is a key123', AES.MODE_CBC, 'This is an IV456')
>>> message = "The answer is no"
>>> ciphertext = obj.encrypt(message)
>>> ciphertext
'\xd6\x83\x8dd!VT\x92\xaa`A\x05\xe0\x9b\x8b\xf1'

一方、PyCryptodomeモジュールの公式ドキュメントには、以下のように、keyivbytes型と記載があります。

Parameters:
key (bytes) – the cryptographic key
mode – the constant Crypto.Cipher.<algorithm>.MODE_CBC
iv (bytes) – the Initialization Vector. A piece of data unpredictable to adversaries. It is as long as the block size (e.g. 16 bytes for AES). If not present, the library creates a random IV value.

推奨モジュールが変わったことで、引数の型も変わっていたことが原因でした。

まとめ

今回は、PythonのCryptoでの暗号化時のエラー、cannot be passed to C codeを解決する方法を紹介しました。
AES.new()に渡す引数の型が、文字列だったことが原因だったため、バイト型に変換することで解決しました。
どなたかの参考になれば幸いです。

Discussion