本文へスキップ
ecdsa.com
CryptoJSその他のツール

エラーメッセージ

Malformed UTF-8 data

CryptoJS — thrown by .toString(CryptoJS.enc.Utf8) after decrypt

このエラーの意味

CryptoJS が暗号文を復号した結果、有効な UTF-8 ではないバイト列になり、それを文字列に変換できませんでした。CryptoJS の AES(CBC モード)には完全性のチェックがないため、鍵が間違っていても復号は失敗せず、ランダムなバイト列が生成されるだけです。それに最初に気づくのが UTF-8 デコーダーです。同じ間違った鍵で、このエラーの代わりに空文字列が返ることもあります(パディングのチェックがたまたまきれいに失敗した場合)。そのため、どちらの症状も診断は同じです。

発生する理由

修正方法

  1. 1.

    鍵の扱いを明示的にし、双方でそろえる

    パスフレーズの KDF による曖昧さを避けるため、双方でまったく同じように、本物の鍵を WordArray として渡し、IV も明示的に指定してください。

    js
    const key = CryptoJS.enc.Hex.parse(hexKey);        // 32-byte key, both sides
    const iv  = CryptoJS.enc.Hex.parse(hexIv);         // 16-byte IV, both sides
    const ct  = CryptoJS.AES.encrypt(plaintext, key, { iv });
    const pt  = CryptoJS.AES.decrypt(ct.toString(), key, { iv })
                  .toString(CryptoJS.enc.Utf8);
  2. 2.

    空の出力も同じ失敗として扱う

    結果を確認し、本当のエラーとして表に出してください。何も通知されない空文字列は、間違った鍵によるバグを何か月も隠してしまいます。

    js
    const pt = CryptoJS.AES.decrypt(ct, key, { iv }).toString(CryptoJS.enc.Utf8);
    if (!pt) throw new Error("decryption failed: wrong key/IV or corrupted ciphertext");
  3. 3.

    認証付きの暗号方式を優先する

    WebCrypto の AES-GCM は暗号文を認証します。鍵が間違っていれば、無意味なデータを生成するのではなく、明確かつ確実に失敗するため、この種類のエラーは完全になくなります。

    js
    const pt = await crypto.subtle.decrypt({ name: "AES-GCM", iv }, key, ct);
    // wrong key → OperationError, never silent garbage

関連するエラー

署名エラーデータベースをすべて見る