トップ回答者
復号化について

質問
-
お世話になります。
お客様の暗号化したファイルを
Vb.netで
復号化しようと思います。
vb.netの暗号化と復号化では
KeyとIV(Initialization Vector:初期化ベクター)が必要だと思います。
実際、vb.netでKeyとIVを使用して、
暗号化と復号化には成功しました。
ところが、お客様の暗号化したファイルを
vb.net
で復号化しようとすると、IV(Initialization Vector:初期化ベクター)が
設定されていないのか、復号化できません。
お客様に聞いてもKeyは教えてもらいましたが、
IVは、設定しないようでした。
そのような暗号化ファイルは(IVを設定していないファイル)
vb.net
では、復号化できないのでしょうか?
IVを設定していない暗号化ファイルを
復号化する方法があれば、教えてくださいませ。
回答
-
皆様、ありがとうございました!
とくに、魔界の仮面弁士さんのサンプルが参考になりました!
以下のコーディングで暗号化できました。
ありがとうございました。
--------------------------------
''' <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
すべての返信
-
CBC モードなのであれば、その方式である以上、VB.NET であろうとなかろうと、初期化ベクトルがなければ復号できません。
参考:https://ja.wikipedia.org/wiki/暗号利用モード#Cipher_Block_Chaining_(CBC)そのお客様に初期化ベクトル(IV)を再確認してください。
初期化ベクトルを未設定(ランダム初期化)の場合はそのときの初期化ベクトルを保管しておかないと、どうやっても正しく復号できないので、上記の Wikipedia の説明も添えるなどして、再確認してください。 -
以下のロジックで、実行しましたが、
’パディングは無効なので、削除できません。’
というエラーになります。
IVは、すべて0にしてみました。
やはり、IVが違うのでしょうか?
(なお、objRijndaelManaged.Key の値は'*'で公開していません。あしからず。)
----------------------------------------
''' 秘密鍵を使って文字列を復号化する
Public Function Decrypt(ByVal encryptoFilePath As String, _
ByVal decryptoFilePath As String) As String
Dim objCryptoStream As System.Security.Cryptography.CryptoStreamDim 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
TryobjFileStream = 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 -
以下のロジックで、実行しましたが、
’パディングは無効なので、削除できません。’
というエラーになります。
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}以上、ご参考まで。
-
以下のロジックで、IVの指定は無しで
実行しましたが、やはり、
’パディングは無効なので、削除できません。’
というエラーになります。
何の原因が考えるでしょうか?
--------------------------------------------------
''' 秘密鍵を使って文字列を復号化する
Public Function Decrypt(ByVal encryptoFilePath As String, _
ByVal decryptoFilePath As String) As String
Dim objCryptoStream As System.Security.Cryptography.CryptoStreamDim 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
TryobjFileStream = 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 -
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 で復号した上で、自前で上記いずれのパターンなのかを判断して、自前で削除することで回避できるかもしれません。
- 編集済み 魔界の仮面弁士MVP 2018年12月20日 4:14
-
暗号化した後で BASE64 エンコードしているのでしょうか。それとも BASE64 エンコードしたものを暗号化しているのでしょうか。
恐らく前者だと思いますが、その場合、受領したデータは ASCII テキストになっているはずなので、まずは BASE64 デコードを行ってから、復号処理に渡してみてください。
- 編集済み 魔界の仮面弁士MVP 2018年12月20日 4:51
-
また、ファイル単位(ストリーム単位)で
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
-
以下のように、暗号化、復号化を作成しまして、
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.CryptoStreamDim 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.PKCS7Try
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.CryptoStreamDim 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
TryobjFileStream = 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
ファイルをこのロジックで復号しますと、
数字などは、正常に復号されますが、
全角文字(日本語)だけが、おかしな漢字に
文字化けしています。
この場合、何の原因が考えられるでしょうか?
-
文字コードはUTF8でして、以下の復号ロジックの★マークの行
を修正しましところ復号化に成功しました。ところが、今度は、暗号化で、
------------------------
'復号化する
Public Function Decrypt(ByVal encryptoFileName As String, _
ByVal base64FileName As String, ByVal decryptoFileName As String) As String
Dim objCryptoStream As System.Security.Cryptography.CryptoStreamDim 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
TryobjFileStream = 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.CryptoStreamDim 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.PKCS7Try
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 -
UTF-8 なんですよね?
それなのに ShiftJIS で書いているからおかしくなるのでは?
(入力は ShiftJIS かもしれませんが、Crypto する段階ではお客様の文字コードにしないといけないのが、できていないように見える。最後の BASE64 は ASCII の範囲しかないので ShiftJIS でも構わないはず)
- 編集済み AzuleanMVP, Moderator 2018年12月26日 21:16
-
以下のように、★マークの箇所を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.CryptoStreamDim 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.PKCS7Try
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 -
先に聞くべきだったかもしれませんが、何をもって OK/NG の判断をされていますか?
同じ文字列に復号できることで OK と判断すべきだと思いますが、そうならないということですか?
- 編集済み AzuleanMVP, Moderator 2018年12月27日 3:58
-
返信の階層が深くなりすぎて読みにくくなっているので、最初の投稿に繋ぎなおします。
「お客様の暗号化方式」の仕様を読み切れていないのですが、とりあえず 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
-
すみません、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")-------------
-
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 なコードが相当します。
- 編集済み 魔界の仮面弁士MVP 2018年12月27日 14:52
-
皆様、ありがとうございました!
とくに、魔界の仮面弁士さんのサンプルが参考になりました!
以下のコーディングで暗号化できました。
ありがとうございました。
--------------------------------
''' <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