質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

89.52%

暗号化処理で復号の時に、ファイルから読み込んだ文字列だと複合化に失敗する。UnicodeDecodeError: 'utf-8' codec can't decode

受付中

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,594

Aki1000

score 26

あちこちから写経しつつpycryptodomeのcryptoを使って暗号化複合化処理をするコードを書きました。
(開発が終わってしまったpycryptoがインストール出来ないマシンがありpycryptodomeにアップデートせざるを得なかったので……。Simple-AES-Cipherはpycryptodomeだとうまく動かないのでそれっぽいのを作ろうかと。Simple-AES-Cipher がpycryptodomeで動けば良かったのですが)

#Cipher.py
from Crypto.Cipher import AES
from Crypto import Random
import base64


class Cipher:
    """注意・暗号化するテキストの末尾にスペースがあるとそのスペースは削除される"""
    def __init__(self):
        # iv = "L3f4mlTJtCIPV9af".encode('utf-8')     # 初期化ベクトル(16文字で適当な値を設定)
        n = 16
        self.iv = bytes(Random.get_random_bytes(n))
        self.mode = AES.MODE_CBC  # 暗号化モードを指定

    def mkpad(self, s, size):
        size=48
        s = s.encode("utf-8")  # UTF-8文字列をバイト列に変換する
        pad = b' ' * (size - len(s) % size)  # 特定の長さの倍数にするための空白を生成
        return s + pad

    # 暗号化する
    def encrypt(self, password, data):
        # 特定の長さに調節する
        password = self.mkpad(password, 16)  # 16の倍数にそろえる
        data = self.mkpad(data, 16)  # バイト列に変換し16の倍数に揃える
        password = password[:16]  # ちょうど16文字に揃える

        # 暗号化
        aes = AES.new(password, self.mode, self.iv)
        data_cipher = aes.encrypt(data)
        return base64.b64encode(data_cipher).decode("utf-8")

    # 複合化する

    def decrypt(self, password, encdata):
        # パスワードの文字数を調整
        password = self.mkpad(password, 16)  # 16の倍数に揃える
        password = password[:16]  # ちょうど16文字に揃える

        # 複合化
        aes = AES.new(password, self.mode, self.iv)
        encdata = base64.b64decode(encdata)  # 暗号化データをBASE64でデコードしてバイト列に
        data = aes.decrypt(encdata)  # 複合化
        data = data.strip()
        return data.decode("utf-8")

これを使うために、下のようにすると問題なく動きます。しかしながら、

#ciphertest0
from module import Cipher
Cipher = Cipher()

with open(r"x:\xxxxx\xxx\AEKey.txt", 'r', encoding='utf-8') as file:
    temp0 = file.read()

message = "testtext"
password = temp0
# 暗号化する
enc = Cipher.encrypt(password, message)

# 複合化する
dec = Cipher.decrypt(password, enc)

print(enc)
print(dec)

if message == dec:
    print("一致確認")

このencという暗号化されたテキストをファイルに保存し、同じように下に書いたコードでデコードしようとすると、
Traceback (most recent call last):
File "ciphertest1.py", line 20, in <module>
dec = Cipher.decrypt(password, temp1)
File "Cipher.py", line 49, in decrypt
return data.decode("utf-8")
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xc3 in position 1: invalid continuation byte

言われてしまいます。utf-8で許されない文字列がある?
上のコードでencをtype(enc)とやって調べるとclass 'str'と出るのでただの文字列だと思うんですが、上のコードは問題なく通るのに下のコードは通りません。

エラーが出る復号化コードは以下の通りです。

#ciphertest1
from module import Cipher

Cipher = Cipher()

with open(r"x:\xxxxx\xxx\AEKey.txt", 'r', encoding='utf-8') as file:
    temp0 = file.read()
with open(r"x:\xxx\xxx\messagetext.txt", 'r', encoding='utf-8') as file:
    temp1 = file.read()

message = temp1
password = temp0

# 復号化する
dec = Cipher.decrypt(password, temp1)
print(dec)

試しに、messagetext.txtをファイルからの読み込みではなく、上のプログラム中で
dec = Cipher.decrypt(password, "g4Dj/kZ6z4w4Ia/ApBrw7OeBEHjB7k95XM1eNP6jXSGzcN/IiSITsVndLfvtv2Ks")

とやっても、同じです。
なぜ、上のciphertest0は問題なく動いて、下のciphertest1が動かないのかわかりません。
どうやったら動くようになるでしょう?

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    退会済みユーザー

    2018/12/22 19:49

    Windows環境でutf-8のBOMが関係していないでしょうか?encoding='ISO-8859-1'としてみませんか?

    キャンセル

  • Aki1000

    2018/12/24 01:06

    ISO-8859-1
    プログラム中、全ての'utf-8'を'ISO-8859-1'と置き換えました。
    すると、エラーで止まるのはなくなりました。
    しかし、
    enc = Cipher.encrypt(password, message)
    print(enc)
    で出てきた文字列を
    dec1 = Cipher.decrypt(password, "4wsAr0TO4NIxvXATkgWmLLEYKzwdy2bkpIRaUusGgnQ53MuWt8Ko77kM26xzHIRm")

    として複合化しても、 úåK_àÑÆÐmT4"  という文字列が出てくる。……復号化に失敗してしまいました……

    キャンセル

回答 1

0

とりあえず、ここだけ

utf-8で許されない文字列がある?

0xC3 の次のバイトは、0x80 - 0xBF のバイトのみとなります。
Wikipedia (UTF-8)

その他はまだ見てません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 89.52%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる
  • トップ
  • Pythonに関する質問
  • 暗号化処理で復号の時に、ファイルから読み込んだ文字列だと複合化に失敗する。UnicodeDecodeError: 'utf-8' codec can't decode