C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[4]: 複合化で「データが正しくありません」のエラー


(過去ログ 25 を表示中)

[トピック内 9 記事 (1 - 9 表示)]  << 0 >>

■11508 / inTopicNo.1)  複合化で「データが正しくありません」のエラー
  
□投稿者/ どみにか (1回)-(2007/12/16(Sun) 22:14:34)

分類:[VB.NET/VB2005] 

どみにかと申します。

VB2005 Express Edition にて、パスワード文字列の暗号化、複合化を行いたいと思っています。
マイクロソフトのサイト(http://www.microsoft.com/japan/msdn/thisweek/10lines/encrypt_vb.aspx)
にあるサンプルモジュールを使って試したところ、何か良く分からないエラーが発生し、困っています。
エラー内容は、
System.Security.Cryptography.CryptographicException :データが正しくありません
です。
他のアルゴリズム(DES, RC2)も同様の現象が発生します。

正しく複合できる場合もあり、暗号化前の文字列と違う文字列に複合される場合もあります。
特定の文字列がそうなるわけでもなく、いろいろな文字列を試している内に、間違った複合がされたり、例外が発生したりします。
ネットで検索しても同様の現象を見つけることができなかったので、私の環境のような気はするのですが、
サンプルそのままですし、現象に法則が見えないもので、いまいち原因が掴めません。
試した文字は半角の英数字のみですし、一度複合に失敗した後にエラーが発生するわけでもなく、
1回目から例外が発生することもあれば、1回目から複合に失敗することもあります。
暗号化サービスプロバイダのクラスに、何か制限があるのかも調べてみたのですが、特に見当たらず。

どなたかお分かりになる方、いらっしゃいませんでしょうか?


環境の詳細は
VB2005 Express Edition Ver 8.0.50727.762 (SP.050727-7600)
.NET Framework Ver 2.0.50727
Windows XP Pro Sp2


-- 現在のソース ---------------------------

Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Public Class Form1

Private TDES As TripleDESCryptoServiceProvider = New TripleDESCryptoServiceProvider
Private DesKey As Byte()
Private DesIV As Byte()


Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
DesKey = TDES.Key
DesIV = TDES.IV
End Sub


Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
TextBox2.Text = GetEncryptString(TextBox1.Text)
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
TextBox3.Text = GetDecryptString(TextBox2.Text)
End Sub


Private Function GetEncryptString(ByVal text As String) As String

' 文字列を byte 配列に変換します
Dim source As Byte() = Encoding.Unicode.GetBytes(text)
Dim ms As MemoryStream = New MemoryStream
Dim cs As CryptoStream = New CryptoStream(ms, TDES.CreateEncryptor(DesKey, DesIV), CryptoStreamMode.Write)

' ストリームに暗号化するデータを書き込みます
cs.Write(source, 0, source.Length)
cs.Close()

' 暗号化されたデータを byte 配列で取得します
Dim destination As Byte() = ms.ToArray()
ms.Close()

' byte 配列を文字列に変換して表示します
Return Encoding.Unicode.GetString(destination)
End Function


Private Function GetDecryptString(ByVal text As String) As String
' 暗号化された文字列を byte 配列に変換します
Dim source As Byte() = Encoding.Unicode.GetBytes(text)
' 入出力用のストリームを生成します
Dim ms As MemoryStream = New MemoryStream
Dim cs As CryptoStream = New CryptoStream(ms, TDES.CreateDecryptor(DesKey, DesIV), CryptoStreamMode.Write)

' ストリームに暗号化されたデータを書き込みます
cs.Write(source, 0, source.Length)
cs.Close()

' 復号化されたデータを byte 配列で取得します
Dim destination As Byte() = ms.ToArray()
ms.Close()

' byte 配列を文字列に変換して表示します
Return Encoding.Unicode.GetString(destination)
End Function


End Class

引用返信 編集キー/
■11509 / inTopicNo.2)  Re[1]: 複合化で「データが正しくありません」のエラー
□投稿者/ オショウ (20回)-(2007/12/16(Sun) 22:40:22)
そのものズバリではありませんが・・・
http://dobon.net/vb/dotnet/string/encryptfile.html
ここの記事・サンプルを参考にして下さい。

※ 多分、文字列長が影響しているのでは・・・と思います。

以上。
引用返信 編集キー/
■11510 / inTopicNo.3)  Re[1]: 複合化で「データが正しくありません」のエラー
□投稿者/ Hongliang (217回)-(2007/12/16(Sun) 22:40:46)
Hongliang さんの Web サイト
暗号化済みバイト配列の文字列へのデコード/エンコードを、Encoding.GetString/GetBytes ではなく Convert.ToBase64String/FromBase64String を使ってみたらどうでしょう。
引用返信 編集キー/
■11511 / inTopicNo.4)  Re[1]: 複合化で「データが正しくありません」のエラー
□投稿者/ なちゃ (84回)-(2007/12/16(Sun) 22:42:09)
ぱっとみた限りでは、

>' byte 配列を文字列に変換して表示します
>Return Encoding.Unicode.GetString(destination)

こういうやり方がそもそも間違いですね。
これでは元の(暗号化された)バイト列に戻せるとは限りません。
※なんでこんなやり方をするんでしょうね…

例えば、代わりにConvert.ToBase64StringとFromBase64Stringメソッド辺りを使用してみてください。

引用返信 編集キー/
■11512 / inTopicNo.5)  Re[2]: 複合化で「データが正しくありません」のエラー
□投稿者/ なちゃ (85回)-(2007/12/16(Sun) 22:57:20)
よく見ると.NET1.1のころのサンプルですね。
UnicodeEncodingの不正バイトに対する扱いが変わった感じもあるので、
以前のバージョンでは問題が発生しなかったのかもしれません(未確認)。
とはいえ、どちらにしてもとてもほめられたやり方ではありませんが。

引用返信 編集キー/
■11513 / inTopicNo.6)  Re[1]: 複合化で「データが正しくありません」のエラー
□投稿者/ IIJIMAS (61回)-(2007/12/16(Sun) 23:01:57)
No11508 (どみにか さん) に返信
> VB2005 Express Edition にて、パスワード文字列の暗号化、複合化を行いたいと思っています。
> マイクロソフトのサイト(http://www.microsoft.com/japan/msdn/thisweek/10lines/encrypt_vb.aspx)
> にあるサンプルモジュールを使って試したところ、何か良く分からないエラーが発生し、困っています。

そのサンプルは.NET1.1用のものですね。
こちら
http://forums.microsoft.com/MSDN-JA/ShowPost.aspx?PostID=1287620&SiteID=7
の質問者の方と同じ現象だと思います。

Hongliangさんとなちゃさんのおっしゃる方法で解決できると思います。
引用返信 編集キー/
■11514 / inTopicNo.7)  Re[2]: 複合化で「データが正しくありません」のエラー
□投稿者/ どみにか (3回)-(2007/12/17(Mon) 00:13:40)
皆様、早速のお返事有難うございます。
色々と勉強させていただきました。

なちゃ様、Hongliang様から提示頂いた方法で解決致しました。
ただ、Base64だと文字列長が4の倍数である必要があるようなので、
何らか補完して暗号化し、複合後は補完文字を除外しなければいけないのですね。
NullCharも使えませんし、どうしたものか。
オショウ様が貼ってくれたリンクなども参考にしつつ、もう少し勉強してから機能を実装することにします。
しかしま、勉強しても勉強しても追いつきませんねぇ・・・いつまで経っても未熟者。
がんばろう。

皆さま本当に有難う御座いました。
解決済み
引用返信 編集キー/
■11517 / inTopicNo.8)  Re[3]: 複合化で「データが正しくありません」のエラー
□投稿者/ なちゃ (86回)-(2007/12/17(Mon) 00:29:41)
> ただ、Base64だと文字列長が4の倍数である必要があるようなので、
> 何らか補完して暗号化し、複合後は補完文字を除外しなければいけないのですね。
> NullCharも使えませんし、どうしたものか。
> オショウ様が貼ってくれたリンクなども参考にしつつ、もう少し勉強してから機能を実装することにします。

なにか勘違いしてると思います。
Convertのメソッドは何も考えなくても正しく動作するようになっていますし。
もしくはそもそもこのメソッドを使う場所(処理の箇所)を間違えていませんか?

暗号化した結果のバイト列を、TextBox表示用の文字列に変換するためと、
復号する際に、TextBoxの(暗合化後、Base64表現にした)文字列を、暗号化済みのバイト列に戻すために、
使用するのですよ。

引用返信 編集キー/
■11519 / inTopicNo.9)  Re[4]: 複合化で「データが正しくありません」のエラー
□投稿者/ どみにか (4回)-(2007/12/17(Mon) 04:32:35)
なちゃ様

ご指摘有難うございます。
仰るとおり、大いに勘違いしておりました。
恥ずかしながら単純にメソッドを置き換えてしまっていたもので。
Base64のメソッドを使う意味など含めて色々調べていった結果、現在は末尾のコードとなり目的機能を満足しました。
感謝申し上げます。

-----------------------------------------
Public Class Form1

Private Const cCryptoKey As String = "CryptoKey"
Private mCryptoProvider As TripleDESCryptoServiceProvider
Private mEncryptor As ICryptoTransform
Private mDecryptor As ICryptoTransform


Private Function CryptoProvider() As TripleDESCryptoServiceProvider
If mCryptoProvider IsNot Nothing Then Return mCryptoProvider

mCryptoProvider = New TripleDESCryptoServiceProvider

'暗号キーをバイト配列にする
Dim bytKey As Byte() = Encoding.UTF8.GetBytes(cCryptoKey)

'共有キーと初期化ベクタを設定
mCryptoProvider.Key = ResizeBytesArray(bytKey, mCryptoProvider.Key.Length)
mCryptoProvider.IV = ResizeBytesArray(bytKey, mCryptoProvider.IV.Length)

Return mCryptoProvider
End Function


Private Function Encryptor() As ICryptoTransform
If mEncryptor Is Nothing Then mEncryptor = Me.CryptoProvider.CreateEncryptor()
Return mEncryptor
End Function


Private Function Decryptor() As ICryptoTransform
If mDecryptor Is Nothing Then mDecryptor = Me.CryptoProvider.CreateDecryptor()
Return mDecryptor
End Function


Private Function ResizeBytesArray(ByVal data() As Byte, ByVal newSize As Integer) As Byte()
If data.Length = newSize Then Return data

Dim newBytes(newSize - 1) As Byte
Dim offset As Integer = 0

If data.Length <= newSize Then
For index As Integer = 0 To data.Length - 1 Step 1
newBytes(index) = data(index)
Next
Else
For index As Integer = 0 To data.Length - 1 Step 1
newBytes(offset) = newBytes(offset) Xor data(index)
offset += 1
If offset >= newBytes.Length Then offset = 0
Next
End If
Return newBytes
End Function


Public Function GetEncryptString(ByVal text As String) As String
Dim bytData As Byte() = Encoding.UTF8.GetBytes(text)
Dim objMemoryStream As MemoryStream = New MemoryStream
Dim objCryptoStream As CryptoStream = New CryptoStream(objMemoryStream, Me.Encryptor, CryptoStreamMode.Write)
Dim strReturn As String

objCryptoStream.Write(bytData, 0, bytData.Length)
objCryptoStream.FlushFinalBlock()

'暗号化されたデータをBase64で取得
strReturn = System.Convert.ToBase64String(objMemoryStream.ToArray())

objCryptoStream.Close()
objMemoryStream.Close()

Return strReturn
End Function


Public Function GetDecryptString(ByVal text As String) As String
Dim bytData As Byte() = System.Convert.FromBase64String(text)
Dim objMemoryStream As MemoryStream = New MemoryStream(bytData)
Dim objCryptoStream As CryptoStream = New CryptoStream(objMemoryStream, Me.Decryptor, CryptoStreamMode.Read)
Dim objStreamReader As StreamReader = New StreamReader(objCryptoStream, Encoding.UTF8)
Dim strReturn As String = objStreamReader.ReadToEnd()

objStreamReader.Close()
objCryptoStream.Close()
objMemoryStream.Close()

Return strReturn
End Function

End Class


引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -