DOBON.NET DOBON.NETプログラミング掲示板過去ログ

DESで暗号化・復号化

環境/言語:[VB2008]
分類:[.NET]

サンプルプログラムを拝借して、データとキーをバイト配列で受け取り
結果をバイト配列で返す関数を作成しようとしています。

暗号化がうまくいったので、同じやり方で復号化もできるのかと思いましたが
うまく動きませんでした。復号化の場合は、同じように単純なやり方では
できないものでしょうか?



''' 文字列を暗号化する
Public Shared Function EncryptString(ByVal bytIn() As Byte, ByVal bytKey() As Byte) As Byte()
Dim bytTmpIV() As Byte = {&H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0}

'DESCryptoServiceProviderオブジェクトの作成
Dim des As New System.Security.Cryptography.DESCryptoServiceProvider

'共有キーと初期化ベクタを設定
des.Key = bytKey
des.IV = bytTmpIV

'暗号化されたデータを書き出すためのMemoryStream
Dim msOut As New System.IO.MemoryStream
'DES暗号化オブジェクトの作成
Dim desencrypt As System.Security.Cryptography.ICryptoTransform = des.CreateEncryptor()
'書き込むためのCryptoStreamの作成
Dim cryptStreem As New System.Security.Cryptography.CryptoStream(msOut, desencrypt, System.Security.Cryptography.CryptoStreamMode.Write)
'書き込む
cryptStreem.Write(bytIn, 0, bytIn.Length)
'暗号化されたデータを取得
Dim bytesOut As Byte() = msOut.ToArray

'閉じる
cryptStreem.Close()
msOut.Close()

'結果を返す
Return bytesOut
End Function

''' 文字列を復号化する
Public Shared Function DecryptString(ByVal bytIn() As Byte, ByVal bytKey() As Byte) As Byte()
Dim bytTmpIV() As Byte = {&H0, &H0, &H0, &H0, &H0, &H0, &H0, &H0}

'DESCryptoServiceProviderオブジェクトの作成
Dim des As New System.Security.Cryptography.DESCryptoServiceProvider

'共有キーと初期化ベクタを設定
des.Key = bytKey
des.IV = bytTmpIV

'復号化されたデータを読み込むためのMemoryStream
Dim msOut As New System.IO.MemoryStream
'DES復号化オブジェクトの作成
Dim desdecrypt As System.Security.Cryptography.ICryptoTransform = des.CreateDecryptor()
'書き込むためのCryptoStreamの作成
Dim cryptStreem As New System.Security.Cryptography.CryptoStream(msOut, desdecrypt, System.Security.Cryptography.CryptoStreamMode.Write)
''書き込む
cryptStreem.Write(bytIn, 0, bytIn.Length)
''復号化されたデータを取得
Dim bytesOut As Byte() = msOut.ToArray

'閉じる
cryptStreem.Close()
msOut.Close()

Return bytesOut
End Function
> '書き込む
> cryptStreem.Write(bytIn, 0, bytIn.Length)
> '暗号化されたデータを取得
> Dim bytesOut As Byte() = msOut.ToArray
>
> '閉じる
> cryptStreem.Close()
> msOut.Close()
これはいけません。
CryptoStream は FlushFinalBlock または Close を呼び出して初めてきちんとした暗号化済みバイナリが完成します。Close() する前に ToArray() してしまっては正しい暗号化済みバイト配列を取得できません。
復号の方も同様です。
Hongliangさん

ありがとうございます。
FlushFinalBlock か Closeしてからじゃないと
だめなんですね。8バイトで処理して、8バイト返ってきてるから
うまくいってるのかと思ってました。

で、closeしてみたんですけど
今度は16バイトで返ってきました。
後ろの8バイトはなににあたいするものなのでしょうか?
パディングです。
DES などはブロック暗号という暗号化手法を使って暗号化を行います。これはもともとのデータを一定のサイズ(BlockSize)ごとに取り出し(これがブロックです)、その単位で暗号化を施すというやりかたです。
一番最後のブロックは往々にして BlockSize に足りません。例えば、BlockSize が 64bits(8 バイト)で、10 バイトのデータを暗号化しようとした場合、暗号化対象は 2 ブロックですが、2 ブロック目は 6 バイト不足します。このままではブロックが用意できないので、Padding プロパティで指定された手法でもって残りの 6 バイトを用意し、8 バイトにします。
ちょうどバイト数がブロックにぴったりだった場合はどうするかも Padding プロパティ次第です。DES のデフォルトは PKCS7 であり、これは BlockSize 分のパディングを埋め込みます。
Hongliangさん

ありがとうござます。
PKCS7でBlockSizeが64した。
なるほど。埋め込まれるわけですね。

ただ今回暗号用として渡してるデータが
8バイトなんで、埋め込みがない気がするのですが16バイトで
返ってくる。。。余計なバイトを付加して渡しちゃっているという事でしょうか。。。

埋め込まれる数値も、埋め込んだ数が入りそうなのに
ランダム値みたいなのが入っている。。。

とりあえず暗号化は最初の8バイトを有効にして
復号化は対象の8バイト+穴埋め8バイトで16バイトで処理したら
ちゃんと復号化できました。
> ただ今回暗号用として渡してるデータが
> 8バイトなんで、埋め込みがない気がするのですが16バイトで
> 返ってくる。。。余計なバイトを付加して渡しちゃっているという事でしょうか。。。
余計ではありません。元データがブロックサイズちょうどに収まる場合はブロックサイズ分のパディングを追加するよう PKCS#7 で定義されているからそうしているのです。

> 埋め込まれる数値も、埋め込んだ数が入りそうなのに
> ランダム値みたいなのが入っている。。。
埋め込んだ後でそのブロックを暗号化しているので、一見ランダムっぽい値になっています。
Hongliangさん

ありがとうござます。
なるほど!!そういう事だったんですね。
やっと意味が分かりました!

最後にひとつだけ分からない事がありまして
復号化する時にFlushFinalBlockやcloseを記述すると
「データが正しくありません。」とエラーとなってしまいます。
FlushFinalBlockやcloseをコメントアウトすると正常に値が返ってきます。
記述位置の問題でしょうか?
パディングによって追加されたデータも必要なデータの一部です。勝手に切り捨ててはいけませんよ。

DOBON.NET | プログラミング道 | プログラミング掲示板