none
復号化について RRS feed

  • 質問

  • お世話になります。

    お客様の暗号化したファイルを

    Vb.netで

    復号化しようと思います。

    vb.netの暗号化と復号化では

    KeyとIV(Initialization Vector:初期化ベクター)が必要だと思います。

    実際、vb.netでKeyとIVを使用して、

    暗号化と復号化には成功しました。

    ところが、お客様の暗号化したファイルを

    vb.net

    で復号化しようとすると、IV(Initialization Vector:初期化ベクター)が

    設定されていないのか、復号化できません。

    お客様に聞いてもKeyは教えてもらいましたが、

    IVは、設定しないようでした。

    そのような暗号化ファイルは(IVを設定していないファイル)

    vb.net

    では、復号化できないのでしょうか?

    IVを設定していない暗号化ファイルを

    復号化する方法があれば、教えてくださいませ。

    2018年12月17日 18:29

回答

  • 皆様、ありがとうございました!

    とくに、魔界の仮面弁士さんのサンプルが参考になりました!

    以下のコーディングで暗号化できました。

    ありがとうございました。

    --------------------------------

        ''' <summary>
        ''' パターン5:Shift_JIS テキストを UTF-8 でエンコードし、AES256-ECB-PKCS7 で暗号化してからBASE64 で保存
        ''' </summary>
        Public Sub Encrypt5(plainFileName As String, encFileName As String)
            '①平文ファイルを Shift_JIS テキストとして読み込む
            Dim plaintText As String = File.ReadAllText(plainFileName, Encoding.GetEncoding("Shift_JIS", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback))
            '②平文テキストを UTF-8 でエンコード
            Dim rawBinary As Byte() = Encoding.GetEncoding("UTF-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback).GetBytes(plaintText)
            '③(特に何もしない)
            '
            '④(特に何もしない)
            '
            '⑤暗号化処理
            Dim encBianry As Byte()
            Using encStream As New MemoryStream(), crypt As New CryptoStream(encStream, NewAes().CreateEncryptor(), CryptoStreamMode.Write)
                crypt.Write(rawBinary, 0, rawBinary.Length)
                crypt.Close()
                encBianry = encStream.ToArray()
            End Using
            '⑥暗号化結果をBASE64に変換
            Dim base64Text As String = Convert.ToBase64String(encBianry, Base64FormattingOptions.None)
            '⑦結果をファイルに保存
            File.WriteAllText(encFileName, base64Text, Encoding.ASCII)
        End Sub

    • 回答としてマーク V77777 2018年12月27日 17:34
    2018年12月27日 16:38

すべての返信

  • いろいろと省略されているので念のための確認です。

    「お客様が暗号化している」ということですが、暗号化のアルゴリズムは確認されていますか?

    2018年12月17日 21:18
    モデレータ
  • わかりにくくて、すみません。

    暗号化の方式は、

    AES256-CBC-PKCS7

    です。

    2018年12月18日 2:09
  • CBC モードなのであれば、その方式である以上、VB.NET であろうとなかろうと、初期化ベクトルがなければ復号できません。
    参考:https://ja.wikipedia.org/wiki/暗号利用モード#Cipher_Block_Chaining_(CBC)

    そのお客様に初期化ベクトル(IV)を再確認してください。
    初期化ベクトルを未設定(ランダム初期化)の場合はそのときの初期化ベクトルを保管しておかないと、どうやっても正しく復号できないので、上記の Wikipedia の説明も添えるなどして、再確認してください。

    2018年12月18日 13:14
    モデレータ
  • 暗号化に使用したアプリケーション次第で、利用者にIVが明示的には提示されないこともあるわけで、まず何で暗号化したか、それでは暗号化手順(アルゴリズムとパラメータの組み合わせよりも大きな範囲の話です)がどう定義されていて暗号化済みデータがどんな構造をしているのか、をはっきりさせる必要があるかと思います。
    2018年12月18日 13:30
  • IVを設定していない暗号化ファイルを

    復号化する方法があれば、教えてくださいませ。

    IVを積極的に使用していない場合、IV=0、を暗黙的に使用している場合があります。
    お客様が暗号に詳しくない場合は質問内容自体を理解できずに回答をいただけない場合もありますから
    IVの値をすべて0にして試してみるのも良いかもしれません。

    • 回答の候補に設定 HIDE0707 2018年12月18日 23:38
    • 回答の候補の設定解除 HIDE0707 2018年12月18日 23:39
    2018年12月18日 13:43
  • 了解しました。

    初期化ベクトル(IV)の値を聞いてみます。

    ありがとう、ございました。

    2018年12月19日 1:22
  • 了解しました。

    どのようなアプリケーションで

    暗号化されたか、聞いてみます。

    ありがとうございました。

    2018年12月19日 1:23
  • 以下のロジックで、実行しましたが、

    ’パディングは無効なので、削除できません。’

    というエラーになります。

    IVは、すべて0にしてみました。

    やはり、IVが違うのでしょうか?

    (なお、objRijndaelManaged.Key の値は'*'で公開していません。あしからず。)

    ----------------------------------------

        ''' 秘密鍵を使って文字列を復号化する
        Public Function Decrypt(ByVal encryptoFilePath As String, _
                                       ByVal decryptoFilePath As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")


            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.IV = enc.GetBytes("0000000000000000")
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.CBC
            objRijndaelManaged.Padding = PaddingMode.PKCS7


            Try

                objFileStream = New System.IO.FileStream(encryptoFilePath, IO.FileMode.Open)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateDecryptor(), Security.Cryptography.CryptoStreamMode.Read)

                objStreamReader = New System.IO.StreamReader(objCryptoStream, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter = New System.IO.StreamWriter(decryptoFilePath, False, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd)


                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    2018年12月19日 3:37
  • 以下のロジックで、実行しましたが、

    ’パディングは無効なので、削除できません。’

    というエラーになります。

    PKCS#7 のルールに対して不整合がある、という内容のエラー出力と理解するべきと考えます。
    2つの可能性を提示させていただきます。
    (他の皆様から提示されている通り、お客様から暗号化の方式を正しく入手することが最善であることは重ねて記載させていただきます。以下は適用されている暗号アルゴリズムを推測して試すという内容です。)

    質問&可能性1.
    デコード対象のデータのデータ長はいくつでしょうか。16バイトの倍数でしょうか。
    PKCS#7でパディングされているはずなので、正しく暗号化されている場合は16バイトの倍数になります。
    16バイトの倍数でない場合、対象のデータは上記でご提示いただいた暗号方式とは異なる方式で暗号化されている可能性が高いと考えます。繰り返しになりますが、適用されている正しいアルゴリズムを確認してください。

    質問&可能性2.
    デコード対象のデータが16バイトの倍数であるが ’パディングは無効なので、削除できません。’ というエラーを出力している場合、データの末尾についてデコード後のデータ内容がPKCS#7の内容と不一致、であることが原因で記載のエラーとなっている可能性があります。
    この場合の可能性として、暗号化時のIVの値がデコードデータの末尾に追加されている可能性があります。(よく使用する手法です。)
    IVはAESの場合は16バイトですから、デコード前のデータから末尾16バイトをIVとして扱い、末尾16バイトを削除したデータを暗号の複合対象のデータとして扱ってAES暗号アルゴリズムで複合することで元のデータへ正しく複合できる可能性があります。

    補足1.

    objRijndaelManaged.IV = enc.GetBytes("0000000000000000")

    これだと H'20 を16バイトになりますよね。IV=0 は国際標準では H'00 を16バイト連続したものを意味します。私が意図するところとは異なる実装となります。正しくは以下の通りです。
    objRijndaelManaged.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}

    以上、ご参考まで。

    2018年12月19日 15:19
  • 再度、確認しましたところ

    暗号化の方式が

    AES256-ECB-PKCS7

    でした。

    CBCではなく、ECBでした。すみませんでした。

    ECBの場合ですと、初期化ベクトル(IV)は、いらないようですが、

    objRijndaelManaged.IV =

    には、何をセットするば、よいでしょうか?

    2018年12月19日 16:14
  • 以下のロジックで、IVの指定は無しで

    実行しましたが、やはり、

    ’パディングは無効なので、削除できません。’

    というエラーになります。

    何の原因が考えるでしょうか?

    --------------------------------------------------

        ''' 秘密鍵を使って文字列を復号化する
        Public Function Decrypt(ByVal encryptoFilePath As String, _
                                       ByVal decryptoFilePath As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")


            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.ECB
            objRijndaelManaged.Padding = PaddingMode.PKCS7


            Try

                objFileStream = New System.IO.FileStream(encryptoFilePath, IO.FileMode.Open)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateDecryptor(), Security.Cryptography.CryptoStreamMode.Read)

                objStreamReader = New System.IO.StreamReader(objCryptoStream, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter = New System.IO.StreamWriter(decryptoFilePath, False, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd)


                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    2018年12月19日 17:05
  • HIDE0707 さんが直前で指摘されている点は確認されましたか?
    CBC/ECB といったモードに関係なく、符号化方法の話(PKCS7)に関する指摘・確認点なので、ECB だったからといって読み飛ばして良い話ではありません。

    2018年12月19日 21:15
    モデレータ
  • ECB かつ共通キーという組み合わせを採用するのは脆弱すぎる気もしますが、今回それは横に置いといて…。

    ’パディングは無効なので、削除できません。’

    パディングの問題であるのだとしたら、試しに復号時に PaddingMode.None を指定してみてください。そうすればパディングの自動削除が行われなくなるので、エラーはでなくなると思います。(ただし、復号結果が正しいかどうかは別問題。)

    でもって None を指定した場合、元データが正しいのであれば、復号後のファイルの末尾 16 バイトが、以下のいずれかのパターンになる見込みです。(XX 部は実データの一部です)

    • XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,01
    • XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,02,02
    • XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,03,03,03
    • XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,04,04,04,04
    • XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,05,05,05,05,05
    • XX,XX,XX,XX,XX,XX,XX,XX,XX,XX,06,06,06,06,06,06
    • XX,XX,XX,XX,XX,XX,XX,XX,XX,07,07,07,07,07,07,07
    • XX,XX,XX,XX,XX,XX,XX,XX,08,08,08,08,08,08,08,08
    • XX,XX,XX,XX,XX,XX,XX,09,09,09,09,09,09,09,09,09
    • XX,XX,XX,XX,XX,XX,0A,0A,0A,0A,0A,0A,0A,0A,0A,0A
    • XX,XX,XX,XX,XX,0B,0B,0B,0B,0B,0B,0B,0B,0B,0B,0B
    • XX,XX,XX,XX,0C,0C,0C,0C,0C,0C,0C,0C,0C,0C,0C,0C
    • XX,XX,XX,0D,0D,0D,0D,0D,0D,0D,0D,0D,0D,0D,0D,0D
    • XX,XX,0E,0E,0E,0E,0E,0E,0E,0E,0E,0E,0E,0E,0E,0E
    • XX,0F,0F,0F,0F,0F,0F,0F,0F,0F,0F,0F,0F,0F,0F,0F
    • 10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10


    もしも PaddingMode.None で復号したときに、最終ブロックが上記以外の組み合わせで復号されるようであれば、暗号文自体が破損しているか、キーが誤っている可能性が考えられます。

    というのも暗号化ライブラリによっては、元データが元々 16 の倍数バイトだった場合に、パディングが省略されるケースがあるためです(&H10 を 16 個埋め込まずに暗号化されてしまう)。その場合は復号時に、Pkcs7 パディングではなく None で復号した上で、自前で上記いずれのパターンなのかを判断して、自前で削除することで回避できるかもしれません。


    2018年12月20日 3:43
  • お客様に再確認しましたところ、

    AES256-ECB-PKCS7

    BASE64エンコーディング

    ファイル単位で内容を暗号化したものとわかりました。

    また、PaddingMode.None で復号してみましたが、

    結果、上記以外でしたので、破損している可能性などもあります。

    再度、暗号化のファイルをもらおうと思います。

    また、ファイル単位(ストリーム単位)で

    BASE64デコードする

    サンプルコードがあれば、教えてくださいませ。

    2018年12月20日 4:33
  • 暗号化した後で BASE64 エンコードしているのでしょうか。それとも BASE64 エンコードしたものを暗号化しているのでしょうか。

    恐らく前者だと思いますが、その場合、受領したデータは ASCII テキストになっているはずなので、まずは BASE64 デコードを行ってから、復号処理に渡してみてください。


    2018年12月20日 4:50
  • また、ファイル単位(ストリーム単位)で

    BASE64デコードする

    サンプルコードがあれば、教えてくださいませ。


    これでどうでしょうか。

    Public Function Decrypt(base64Text As String, key32 As Byte()) As Byte()
        Return Decrypt(Convert.FromBase64String(base64Text), key32)
    End Function
    
    Public Function Decrypt(encFile As FileInfo, key32 As Byte()) As Byte()
        Return Decrypt(File.ReadAllBytes(encFile.FullName), key32)
    End Function
    
    Public Function Decrypt(encBinary As Byte(), key32 As Byte()) As Byte()
        Dim aes As New AesManaged() With {
            .KeySize = 256,
            .BlockSize = 128,
            .Mode = CipherMode.ECB,
            .Padding = PaddingMode.PKCS7,
            .Key = key32
        }
        Using decStream As New MemoryStream(), 
            crpyt as New CryptoStream(New MemoryStream(encBinary), aes.CreateDecryptor(), CryptoStreamMode.Read)
            Dim bin(1023) As Byte
            Do
                Dim length As Integer = crpyt.Read(bin, 0, bin.Length)
                If length <= 0 Then Exit do
                decStream.Write(bin, 0, length)
            Loop 
            crpyt.Close()
            Return decStream.ToArray()
        End Using
    End Function

    2018年12月20日 5:15
  • ありがとうございます。

    参考にさせていただきます。

    2018年12月20日 15:58
  • 以下のように、暗号化、復号化を作成しまして、

    AES256-ECB-PKCS7

    BASE64エンコーディングの仕様で

    エラーもでなくなり、作成しました。

    data.csvとdata3.csvは同じ内容になりました。

    -------------

            '暗号化
            Call Encrypt(gstrPath & "\data.tmp", gstrPath & "\base64data.tmp", gstrPath & "\data.csv")

    -------------

            '復号化
            Call Decrypt(gstrPath & "\data2.tmp", gstrPath & "\base64data.tmp", gstrPath & "\data2.csv")

    -------------

        '暗号化する
        Public Function Encrypt(ByVal encryptoFileName As String, ByVal base64FileName As String, _
                                       ByVal FileName As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")

            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.ECB
            objRijndaelManaged.Padding = PaddingMode.PKCS7

            Try

                objFileStream = New System.IO.FileStream(encryptoFileName, System.IO.FileMode.Create)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateEncryptor(), Security.Cryptography.CryptoStreamMode.Write)

                objStreamWriter = New System.IO.StreamWriter(objCryptoStream, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamReader = New System.IO.StreamReader(FileName, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd())


                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

                'Base64で文字列に変換するファイル
                Dim inFileName As String = encryptoFileName
                Dim inFile As System.IO.FileStream
                Dim bs() As Byte

                'ファイルをbyte型配列としてすべて読み込む
                inFile = New System.IO.FileStream(inFileName, _
                    System.IO.FileMode.Open, System.IO.FileAccess.Read)
                ReDim bs(inFile.Length - 1)
                Dim readBytes As Long = inFile.Read(bs, 0, inFile.Length)
                inFile.Close()

                'Base64で文字列に変換
                Dim base64String As String
                base64String = System.Convert.ToBase64String(bs)

                'ファイルに保存する
                '保存するファイル名
                Dim outFileName As String = base64FileName
                'ファイルに書き込む
                Dim sw As IO.StreamWriter = New IO.StreamWriter(outFileName, False, System.Text.Encoding.GetEncoding("Shift_JIS"))
                sw.Write(base64String)
                sw.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    -------------------

        '復号化する
        Public Function Decrypt(ByVal encryptoFileName As String, _
                                       ByVal base64FileName As String, ByVal decryptoFileName As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")

            'テキストファイルを開く
            Dim srFile As New StreamReader(base64FileName, Encoding.GetEncoding("shift-jis"))
            Dim strW As String = ""

            Dim strLine As String = srFile.ReadLine
            While Not strLine Is Nothing
                strW &= strLine
                strLine = srFile.ReadLine
            End While
            srFile.Close()

            'バイト型配列に戻す
            Dim bs() As Byte = System.Convert.FromBase64String(strW)
            'ファイルに保存する
            '保存するファイル名
            Dim outFileName As String = encryptoFileName
            'ファイルに書き込む
            Dim outFile As New System.IO.FileStream(outFileName, _
                System.IO.FileMode.Create, System.IO.FileAccess.Write)
            outFile.Write(bs, 0, bs.Length)
            outFile.Close()

            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.ECB
            objRijndaelManaged.Padding = PaddingMode.PKCS7


            Try

                objFileStream = New System.IO.FileStream(encryptoFileName, IO.FileMode.Open)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateDecryptor(), Security.Cryptography.CryptoStreamMode.Read)

                objStreamReader = New System.IO.StreamReader(objCryptoStream, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter = New System.IO.StreamWriter(decryptoFileName, False, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd)

                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    -----------------

    しかしながら、

    お客様からもいました、

    base64data.tmp

    ファイルをこのロジックで復号しますと、

    数字などは、正常に復号されますが、

    全角文字(日本語)だけが、おかしな漢字に

    文字化けしています。

    この場合、何の原因が考えられるでしょうか?

    2018年12月22日 16:55
  • 文字コードが違うのではないでしょうか。
    お客様に文字コードを確認してください。

    -----

    JIS を ShiftJIS で開いた場合はおかしな漢字ではなく、アルファベット・数字類になるはず。
    EUC-JP を ShiftJIS で開いた場合は漢字や半角カナなど、おかしな文字列になる。

    2018年12月22日 22:38
    モデレータ
  • 文字コードはUTF8でして、以下の復号ロジックの★マークの行

    を修正しましところ復号化に成功しました。ところが、今度は、暗号化で、

    ------------------------

        '復号化する
        Public Function Decrypt(ByVal encryptoFileName As String, _
                                       ByVal base64FileName As String, ByVal decryptoFileName As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")

            'テキストファイルを開く
            Dim srFile As New StreamReader(base64FileName, Encoding.GetEncoding("shift-jis"))
            Dim strW As String = ""

            Dim strLine As String = srFile.ReadLine
            While Not strLine Is Nothing
                strW &= strLine
                strLine = srFile.ReadLine
            End While
            srFile.Close()

            'バイト型配列に戻す
            Dim bs() As Byte = System.Convert.FromBase64String(strW)
            'ファイルに保存する
            '保存するファイル名
            Dim outFileName As String = encryptoFileName
            'ファイルに書き込む
            Dim outFile As New System.IO.FileStream(outFileName, _
                System.IO.FileMode.Create, System.IO.FileAccess.Write)
            outFile.Write(bs, 0, bs.Length)
            outFile.Close()

            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.ECB
            objRijndaelManaged.Padding = PaddingMode.PKCS7


            Try

                objFileStream = New System.IO.FileStream(encryptoFileName, IO.FileMode.Open)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateDecryptor(), Security.Cryptography.CryptoStreamMode.Read)

                objStreamReader = New System.IO.StreamReader(objCryptoStream, System.Text.Encoding.UTF8) '★マーク

                objStreamWriter = New System.IO.StreamWriter(decryptoFileName, False, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd)

                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    --------------------------------------

    次に、暗号化しまして、復号化の第二パラメータのbase64FileName と

    暗号化の第二パラメータのbase64FileName は同じ内容になるはずですが、

    System.Text.Encodingの箇所をいろんなパターンでUTF8に変えて実行してみましたが、

    同じ内容になりません。

    以下の暗号化のロジックの何の原因が考えられるでしょうか?

        '暗号化する
        Public Function Encrypt(ByVal encryptoFileName As String, ByVal base64FileName As String, _
                                       ByVal FileName As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")

            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.ECB
            objRijndaelManaged.Padding = PaddingMode.PKCS7

            Try

                objFileStream = New System.IO.FileStream(encryptoFileName, System.IO.FileMode.Create)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateEncryptor(), Security.Cryptography.CryptoStreamMode.Write)

                objStreamWriter = New System.IO.StreamWriter(objCryptoStream, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamReader = New System.IO.StreamReader(FileName, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd())


                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

                'Base64で文字列に変換するファイル
                Dim inFileName As String = encryptoFileName
                Dim inFile As System.IO.FileStream
                Dim bs() As Byte

                'ファイルをbyte型配列としてすべて読み込む
                inFile = New System.IO.FileStream(inFileName, _
                    System.IO.FileMode.Open, System.IO.FileAccess.Read)
                ReDim bs(inFile.Length - 1)
                Dim readBytes As Long = inFile.Read(bs, 0, inFile.Length)
                inFile.Close()

                'Base64で文字列に変換
                Dim base64String As String
                base64String = System.Convert.ToBase64String(bs)

                'ファイルに保存する
                '保存するファイル名
                Dim outFileName As String = base64FileName
                'ファイルに書き込む
                Dim sw As IO.StreamWriter = New IO.StreamWriter(outFileName, False, System.Text.Encoding.GetEncoding("Shift_JIS"))
                sw.Write(base64String)
                sw.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    2018年12月26日 16:45
  • UTF-8 なんですよね?
    それなのに ShiftJIS で書いているからおかしくなるのでは?
    (入力は ShiftJIS かもしれませんが、Crypto する段階ではお客様の文字コードにしないといけないのが、できていないように見える。最後の BASE64 は ASCII の範囲しかないので ShiftJIS でも構わないはず)

    2018年12月26日 21:11
    モデレータ
  • 以下のように、★マークの箇所をUTF8にしてみましたが、

    状況は変わらず、結果はお客様の行った暗号化ファイルとは、

    違う内容になってしまいます。

    また、復号化の第一パラメータのencryptoFileName と

    暗号化のencryptoFileName は、同じファイルの内容にならないと

    いけないと思いますが、この時点でファイル内容が違っていました。

    何が考えられるでしょうか?

        '暗号化する
        Public Function Encrypt(ByVal encryptoFileName As String, ByVal base64FileName As String, _
                                       ByVal FileName As String) As String
            Dim objCryptoStream As System.Security.Cryptography.CryptoStream

            Dim objRijndaelManaged As New System.Security.Cryptography.AesCryptoServiceProvider()

            Dim objFileStream As System.IO.FileStream

            Dim objStreamReader As System.IO.StreamReader

            Dim objStreamWriter As System.IO.StreamWriter

            Dim strData As String

            Dim enc As System.Text.Encoding = System.Text.Encoding.GetEncoding("shift-jis")

            ' AES暗号化サービスプロバイダ
            objRijndaelManaged.BlockSize = 128
            objRijndaelManaged.KeySize = 256
            objRijndaelManaged.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
            objRijndaelManaged.Key = enc.GetBytes("********************************")
            objRijndaelManaged.Mode = CipherMode.ECB
            objRijndaelManaged.Padding = PaddingMode.PKCS7

            Try

                objFileStream = New System.IO.FileStream(encryptoFileName, System.IO.FileMode.Create)

                objCryptoStream = New System.Security.Cryptography.CryptoStream(objFileStream, objRijndaelManaged.CreateEncryptor(), Security.Cryptography.CryptoStreamMode.Write)

                objStreamWriter = New System.IO.StreamWriter(objCryptoStream, System.Text.Encoding.UTF8) '★マーク

                objStreamReader = New System.IO.StreamReader(FileName, System.Text.Encoding.GetEncoding("shift-jis"))

                objStreamWriter.Write(objStreamReader.ReadToEnd())


                objStreamReader.Close()

                objStreamWriter.Close()

                objFileStream.Close()

                objCryptoStream.Close()

                'Base64で文字列に変換するファイル
                Dim inFileName As String = encryptoFileName
                Dim inFile As System.IO.FileStream
                Dim bs() As Byte

                'ファイルをbyte型配列としてすべて読み込む
                inFile = New System.IO.FileStream(inFileName, _
                    System.IO.FileMode.Open, System.IO.FileAccess.Read)
                ReDim bs(inFile.Length - 1)
                Dim readBytes As Long = inFile.Read(bs, 0, inFile.Length)
                inFile.Close()

                'Base64で文字列に変換
                Dim base64String As String
                base64String = System.Convert.ToBase64String(bs)

                'ファイルに保存する
                '保存するファイル名
                Dim outFileName As String = base64FileName
                'ファイルに書き込む
                Dim sw As IO.StreamWriter = New IO.StreamWriter(outFileName, False, System.Text.Encoding.GetEncoding("Shift_JIS"))
                sw.Write(base64String)
                sw.Close()

            Catch Ex As Exception

                MsgBox(Ex.Message, MsgBoxStyle.Exclamation)

            End Try
        End Function

    2018年12月27日 1:56
  • 先に聞くべきだったかもしれませんが、何をもって OK/NG の判断をされていますか?

    同じ文字列に復号できることで OK と判断すべきだと思いますが、そうならないということですか?

    2018年12月27日 3:39
    モデレータ
  • 返信の階層が深くなりすぎて読みにくくなっているので、最初の投稿に繋ぎなおします。

    「お客様の暗号化方式」の仕様を読み切れていないのですが、とりあえず 4 パターンほど作ってみました。この中に該当するものはありますか?

    ''' <summary>AES256-ECB-PKCS7</summary>
    Private Function NewAes() As SymmetricAlgorithm
        '[.NET 1.0~] マネージ実装のラインダール
        'Dim o As New RijndaelManaged()
    
        '[.NET 2.0~] マネージ実装の AES
        Dim o As New AesManaged()
    
        '[.NET 2.0~] CAPI 実装の AES
        'Dim o As New AesCryptoServiceProvider()
    
        '[.NET 4.6.2~] CNG 実装の AES (Vista 以降向け)
        'Dim o As New AesCng()
    
        o.KeySize = 256
        o.BlockSize = 128
        o.Mode = CipherMode.ECB
        o.Padding = PaddingMode.PKCS7
        o.Key = Encoding.GetEncoding("Shift_JIS").GetBytes("********************************")
        o.IV = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
        Return o
    End Function
    
    
    ''' <summary>
    ''' パターン1:UTF-8 テキストを Shift_JIS で BASE64 化してから AES256-ECB-PKCS7 で暗号化
    ''' </summary>
    Public Sub Encrypt1(plainFileName As String, encFileName As String)
        '①平文ファイルを UTF-8 テキストとしてデコードする
        Dim plaintText As String = File.ReadAllText(plainFileName, Encoding.GetEncoding("UTF-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback))
        '②平文テキストを Shift_JIS でエンコードしなおす
        Dim srcBinary As Byte() = Encoding.GetEncoding("Shift_JIS", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback).GetBytes(plaintText)
        '③変換元データをBASE64テキストに変換
        Dim base64Text As String = Convert.ToBase64String(srcBinary)
        '④BASE64テキストをバイナリ化する
        Dim base64Binary As Byte() = Encoding.ASCII.GetBytes(base64Text)
        '⑤暗号化処理
        Dim encBianry As Byte()
        Using encStream As New MemoryStream(), crypt As New CryptoStream(encStream, NewAes().CreateEncryptor(), CryptoStreamMode.Write)
            crypt.Write(base64Binary, 0, base64Binary.Length)
            crypt.Close()
            encBianry = encStream.ToArray()
        End Using
        '⑥(特に何もしない)
        '
        '⑦結果をファイルに保存
        File.WriteAllBytes(encFileName, encBianry)
    End Sub
    
    ''' <summary>
    ''' パターン2:Shift_JIS テキストを UTF-8 で BASE64 化してから AES256-ECB-PKCS7 で暗号化
    ''' </summary>
    Public Sub Encrypt2(plainFileName As String, encFileName As String)
        '①平文ファイルを Shift_JIS テキストとして読み込む
        Dim plaintText As String = File.ReadAllText(plainFileName, Encoding.GetEncoding("Shift_JIS", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback))
        '②平文テキストを UTF-8 でエンコード
        Dim rawBinary As Byte() = Encoding.GetEncoding("UTF-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback).GetBytes(plaintText)
        '③変換元データをBASE64テキストに変換
        Dim base64Text As String = Convert.ToBase64String(rawBinary)
        '④BASE64テキストをバイナリ化する
        Dim base64Binary As Byte() = Encoding.ASCII.GetBytes(base64Text)
        '⑤暗号化処理
        Dim encBianry As Byte()
        Using encStream As New MemoryStream(), crypt As New CryptoStream(encStream, NewAes().CreateEncryptor(), CryptoStreamMode.Write)
            crypt.Write(base64Binary, 0, base64Binary.Length)
            crypt.Close()
            encBianry = encStream.ToArray()
        End Using
        '⑥(特に何もしない)
        '
        '⑦結果をファイルに保存
        File.WriteAllBytes(encFileName, encBianry)
    End Sub
    
    ''' <summary>
    ''' パターン3:UTF-8 テキスト(あるいはバイナリファイル)をそのまま BASE64 化してから AES256-ECB-PKCS7 で暗号化
    ''' </summary>
    Public Sub Encrypt3(plainFileName As String, encFileName As String)
        '①平文ファイルをバイナリとして読み込む
        Dim rawBinary As Byte() = File.ReadAllBytes(plainFileName)
        '②(特に何もしない)
        '
        '③変換元データをBASE64テキストに変換
        Dim base64Text As String = Convert.ToBase64String(rawBinary)
        '④BASE64テキストをバイナリにする
        Dim base64Binary As Byte() = Encoding.ASCII.GetBytes(base64Text)
        '⑤暗号化処理
        Dim encBianry As Byte()
        Using encStream As New MemoryStream(), crypt As New CryptoStream(encStream, NewAes().CreateEncryptor(), CryptoStreamMode.Write)
            crypt.Write(base64Binary, 0, base64Binary.Length)
            crypt.Close()
            encBianry = encStream.ToArray()
        End Using
        '⑥(特に何もしない)
        '
        '⑦結果をファイルに保存
        File.WriteAllBytes(encFileName, encBianry)
    End Sub
    
    ''' <summary>
    ''' パターン4:UTF-8 テキスト(あるいはバイナリファイル)を AES256-ECB-PKCS7 で暗号化してからBASE64 で保存
    ''' </summary>
    Public Sub Encrypt4(plainFileName As String, encFileName As String)
        '①平文ファイルをバイナリとして読み込む
        Dim rawBinary As Byte() = File.ReadAllBytes(plainFileName)
        '②(特に何もしない)
        '
        '③(特に何もしない)
        '
        '④(特に何もしない)
        '
        '⑤暗号化処理
        Dim encBianry As Byte()
        Using encStream As New MemoryStream(), crypt As New CryptoStream(encStream, NewAes().CreateEncryptor(), CryptoStreamMode.Write)
            crypt.Write(rawBinary, 0, rawBinary.Length)
            crypt.Close()
            encBianry = encStream.ToArray()
        End Using
        '⑥暗号化結果をBASE64に変換
        Dim base64Text As String = Convert.ToBase64String(encBianry, Base64FormattingOptions.InsertLineBreaks)
        '⑦結果をファイルに保存
        File.WriteAllText(encFileName, base64Text, Encoding.ASCII)
    End Sub

    2018年12月27日 7:52
  • すみません、OK、NGの判断ですが、

    data.csvとdata2.csvが同じ内容のテキストファイルとして、

    data.tmpとdata2.tmpの中身が同じで、かつ、

    base64data.tmpとbase64data2.tmpの中身が同じ内容であれば

    OKです。

    -------------

            '暗号化
            Call Encrypt(gstrPath & "\data.tmp", gstrPath & "\base64data.tmp", gstrPath & "\data.csv")

    -------------

            '復号化
            Call Decrypt(gstrPath & "\data2.tmp", gstrPath & "\base64data2.tmp", gstrPath & "\data2.csv")

    -------------

    2018年12月27日 12:41
  • すみません、暗号化の手順ですが、

    AES256-ECB-PKCS7で暗号化してから、

    BASE64 化の順序になります。

    復号化は、うまくいきましたので、

    その逆になりますので、

    Shift_JIS テキストを AES256-ECB-PKCS7 で暗号化し、UTF-8 で BASE64 化して保存になると思います。

    これで、再度、教えていただけますと

    助かります。

    よろしくお願い致します

    2018年12月27日 13:13
  • AES256-ECB-PKCS7で暗号化してから、

    BASE64 化の順序になります。

    だとすれば、先の Encrypt4 が『暗号化』の手順になるでしょう。

    この場合、元ファイルの文字コードは無関係なので、変換元ファイルが Shift_JIS でも UTF-8 でも バイナリファイルでも構いません。

    暗号化した後の最終結果は「Dim base64Text As String」に入りますが、ここに含まれる文字種は、「A~Z」「a~z」「0~9」「+」「/」および「=」と改行だけです。メモ帳で閲覧可能なテキストデータということです。

    なお、ToBase64 メソッドに渡している Base64FormattingOptions オプションは、76桁ごとに改行を含めるかどうかを示しています。改行の有無は復元作業に影響を与えないので、ここは InsertLineBreaks でも None でも構いません。

    そしてこれに対応する復号処理は、このように書けます。

    Public Sub Decrypt4(encFileName As String, plainFileName As String)
        '①復号対象の BASE64 ファイルを ASCII テキストとして読み込む
        Dim base64Text As String = File.ReadAllText(encFileName, Encoding.ASCII)
        '②BASE64 な文字列をバイナリに復元
        Dim encBinary As Byte() = Convert.FromBase64String(base64Text)
        '③復号処理
        Dim plainBinary As Byte()
        Using plainStream As New MemoryStream(), crypt As New CryptoStream(New MemoryStream(encBinary), NewAes().CreateDecryptor(), CryptoStreamMode.Read)
            Dim bin(1023) As Byte
            Do
                Dim length As Integer = crypt.Read(bin, 0, bin.Length)
                If length <= 0 Then Exit Do
                plainStream.Write(bin, 0, length)
            Loop
            plainStream.Close()
            plainBinary = plainStream.ToArray()
        End Using
        '④復号結果をファイルに保存
        File.WriteAllBytes(plainFileName, plainBinary)
    End Sub


    Shift_JIS テキストを AES256-ECB-PKCS7 で暗号化し、UTF-8 で BASE64 化して保存になると思います。

    いや、その理屈はおかしい。

    AES で暗号化した結果はテキストデータではなくバイナリデータになるので、それを「UTF-8 で BASE64 化する」ことは不可能です。

    AES で暗号化した結果を BASE64 変換して得られたテキストを、UTF-8 (ASCII や Shift_JIS でも可) にてファイル(あるいは Byte 配列)化して保存するというのであれば、先の Encrypt4 なコードが相当します。

    2018年12月27日 14:26
  • 皆様、ありがとうございました!

    とくに、魔界の仮面弁士さんのサンプルが参考になりました!

    以下のコーディングで暗号化できました。

    ありがとうございました。

    --------------------------------

        ''' <summary>
        ''' パターン5:Shift_JIS テキストを UTF-8 でエンコードし、AES256-ECB-PKCS7 で暗号化してからBASE64 で保存
        ''' </summary>
        Public Sub Encrypt5(plainFileName As String, encFileName As String)
            '①平文ファイルを Shift_JIS テキストとして読み込む
            Dim plaintText As String = File.ReadAllText(plainFileName, Encoding.GetEncoding("Shift_JIS", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback))
            '②平文テキストを UTF-8 でエンコード
            Dim rawBinary As Byte() = Encoding.GetEncoding("UTF-8", EncoderFallback.ExceptionFallback, DecoderFallback.ExceptionFallback).GetBytes(plaintText)
            '③(特に何もしない)
            '
            '④(特に何もしない)
            '
            '⑤暗号化処理
            Dim encBianry As Byte()
            Using encStream As New MemoryStream(), crypt As New CryptoStream(encStream, NewAes().CreateEncryptor(), CryptoStreamMode.Write)
                crypt.Write(rawBinary, 0, rawBinary.Length)
                crypt.Close()
                encBianry = encStream.ToArray()
            End Using
            '⑥暗号化結果をBASE64に変換
            Dim base64Text As String = Convert.ToBase64String(encBianry, Base64FormattingOptions.None)
            '⑦結果をファイルに保存
            File.WriteAllText(encFileName, base64Text, Encoding.ASCII)
        End Sub

    • 回答としてマーク V77777 2018年12月27日 17:34
    2018年12月27日 16:38