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

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

ただいまの
回答率

88.58%

暗号化後のファイルをゲーム内で復号しようとしたらエラーになりました

解決済

回答 1

投稿 編集

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

BinaryNumber

score 13

こんにちは。初心者プログラマです。
どうしても自分で解決できなかったので、質問させてください。

概要

外部にあるcsvファイルを暗号化し、Resources下に置いています。
そして、Unity上で復号化しようとすると、エラーになってしまいます。

詳細

外部にあるcsvファイル(UTF8)を暗号化して、UnityのAssets/Resourcesの中に置きます。
ファイルで書き出すときに、書き出す内容を復号化関数で確認すると、問題なく復号化されます。
Unityで作成しているゲーム内で、最初のSceneでResources下のファイルを読み込みます。ところが、この、読み込むとき、書き出すときに使用した関数とまったく同じコードを使っているのに、エラーが出てしまい、復号ができません。
読み込みが失敗しているのかと内容を確認しましたが、読み込みはできているようでした(以下のコード内の encrypted を確認したらちゃんと読めているようです)。

エラー内容

CryptographicException: Length of the data to decrypt is invalid.
System.Security.Cryptography.RijndaelManagedTransform.TransformFinalBlock (System.Byte[] inputBuffer, System.Int32 inputOffset, System.Int32 inputCount) (at <a8ed250850854b439cedc18931a314fe>:0)
*.Decode () (at Assets/Scripts/*.cs:146)
*.Init () (at Assets/Scripts/*.cs:54)

環境

Unity : 2019.2.0f1 Personal
ただし、2018.2.6f1で作成していたものを移動させた形です(そのためか[PREVIEW PACKAGES IN USE]と表示されています)。
Visual Studio : 2019 Version 16.0.2
これもまた、以前はVisual Studio2017を使っていたので、影響している可能性はあります。

コード

暗号化部分

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Text;
using System.IO;
using System;
using System.Security.Cryptography;

public class * : MonoBehaviour {

    private string guitxt = "";
    private byte[] encrypted;
    private string plain = "";


    // Use this for initialization
    void Start () {
        string filename1 = Application.dataPath + "/../../test.csv";

        if (File.Exists(filename1))
        {
            ReadFile(filename1);

            string filename2 = Application.dataPath + "/Resources/test.csv";

            if (File.Exists(filename2))
            {
                Encrypt();
                File.WriteAllBytes(filename2, encrypted);
                Debug.Log("暗号:" + encrypted);

                Decode();
                Debug.Log("復号:" + plain);
            }
        }
    }

    void ReadFile(string filename)
    {
        FileInfo fi = new FileInfo(filename);

        try
        {
            // 一行毎読み込み
            using (StreamReader sr = new StreamReader(fi.OpenRead(), Encoding.UTF8))
            {
                guitxt = sr.ReadToEnd();
            }
        }
        catch (Exception e)
        {
            // 改行コード
            guitxt += SetDefaultText();
        }

    }

    // 改行コード処理
    string SetDefaultText()
    {
        return "C#あ\n";
    }

    // 暗号化処理
    void Encrypt()
    {
        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.KeySize = 128;
        rijndael.BlockSize = 128;

        // pw, vectorの内容はダミーで、実際には英数字で構成されています
        string pw = "abcdefghijklmnop";
        string vector = "0123456789012345";

        byte[] bSalt = Encoding.UTF8.GetBytes(vector);
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(pw, bSalt);
        deriveBytes.IterationCount = 1000;        // 反復回数

        rijndael.Key = deriveBytes.GetBytes(rijndael.KeySize / 8);
        rijndael.IV = deriveBytes.GetBytes(rijndael.BlockSize / 8);

        // 暗号化
        ICryptoTransform encryptor = rijndael.CreateEncryptor();
        byte[] src = Encoding.UTF8.GetBytes(guitxt);
        encrypted = encryptor.TransformFinalBlock(src, 0, src.Length);

        encryptor.Dispose();
    }

    void Decode()
    {
        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.KeySize = 128;
        rijndael.BlockSize = 128;

        // パスワードから共有キーと初期化ベクターを作成
        string pw = "abcdefghijklmnop";
        string vector = "0123456789012345";

        byte[] bSalt = Encoding.UTF8.GetBytes(vector);
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(pw, bSalt);
        deriveBytes.IterationCount = 1000;        // 反復回数

        rijndael.Key = deriveBytes.GetBytes(rijndael.KeySize / 8);
        rijndael.IV = deriveBytes.GetBytes(rijndael.BlockSize / 8);

        // 復号化
        ICryptoTransform decryptor = rijndael.CreateDecryptor();
        byte[] src = decryptor.TransformFinalBlock(encrypted, 0, encrypted.Length);

        Debug.Log("復号化: " + src);

        plain = Encoding.UTF8.GetString(src);

        decryptor.Dispose();

    }
}

復号化部分

using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using UnityEngine;

public class * : MonoBehaviour
{
    private static byte[] encrypted;
    private static string plain = "";

    // ファイル名
    private const string FILENAME = "test";

    // 問題文のcsvファイル
    private static TextAsset csvFile;

    [RuntimeInitializeOnLoadMethod()]
    static void Init()
    {
        #if UNITY_EDITOR
        if (UnityEditor.EditorApplication.isPlayingOrWillChangePlaymode == false) { return; }
        #endif

        // ファイルを読み込む
        csvFile = Resources.Load(FILENAME) as TextAsset;

        // 復号化
        encrypted = csvFile.bytes;
        Decode();

        // 以後の処理
        // (省略)
    }


static void Decode()
    {
        RijndaelManaged rijndael = new RijndaelManaged();
        rijndael.KeySize = 128;
        rijndael.BlockSize = 128;

        // パスワードから共有キーと初期化ベクターを作成
        string pw = "abcdefghijklmnop";
        string vector = "0123456789012345";

        byte[] bSalt = Encoding.UTF8.GetBytes(vector);
        Rfc2898DeriveBytes deriveBytes = new Rfc2898DeriveBytes(pw, bSalt);
        deriveBytes.IterationCount = 1000;        // 反復回数

        rijndael.Key = deriveBytes.GetBytes(rijndael.KeySize / 8);
        rijndael.IV = deriveBytes.GetBytes(rijndael.BlockSize / 8);

        // 復号化
        ICryptoTransform decryptor = rijndael.CreateDecryptor();
        byte[] src = decryptor.TransformFinalBlock(encrypted, 0, encrypted.Length);
        plain = Encoding.UTF8.GetString(src);

        decryptor.Dispose();
}

いろいろ自分で検索して試しましたが、何かの見落としがあるようで、エラーを取ることができず、お力を貸していただきたく、書き込ませていただきました。
もし、これ以外に、解決のため必要な情報がありましたら、ご指摘いただければ追記いたします。
どうか、よろしくお願いいたします。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • Zuishin

    2019/09/25 15:53

    暗号化部分、書き出し部分、読み込み部分が必要です。

    キャンセル

  • BinaryNumber

    2019/09/25 16:29

    ご指摘ありがとうございます。 暗号化部分のコードと、復号化の際の読み込み部分を追加してみました。
    まだ不足がありましたら、お手数ですが、またご指摘いただけると助かります。

    キャンセル

回答 1

checkベストアンサー

+1

テキストアセット

.txt と .bytes 拡張子によるファイルは、それぞれ、テキストとバイナリファイルとして扱われるので注意してください。これらのファイルからデータを読み込もうとするとき、予想外の動作をしてしまうかもしれないのでバイナリファイルを .txt 拡張子で保存しないでください。

FILENAME を test.bytes にしてみてください。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/09/25 16:45

    早速のお返事、ありがとうございます。
    > FILENAME を test.bytes にしてみてください。
    とのことですが、
    1. FILENAMEの定義を"test"→"test.bytes"にする
    2. Resourceのファイル名を"test.csv"→"test.bytes"にする
    のいずれかでしょうか、それとも別のことをすればよいのでしょうか。
    理解が足りなくて申し訳ありませんが、教えていただけると助かります。
    よろしくお願いします。

    キャンセル

  • 2019/09/25 16:46

    リンク先を一通り読んでみてください。今後も無駄にならないはずです。

    キャンセル

  • 2019/09/25 17:06

    大変失礼いたしました。参照リンクだと思っておりませんでした。完全に勘違いしておりました、申し訳ございません。

    ファイルをtest.csvからtest.bytes、出力先もtest.csvからtest.bytesに変更することで、今回の読み出しに成功しました。

    ご指摘いただき助かりました。ありがとうございました。

    キャンセル

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

  • ただいまの回答率 88.58%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る