SecurityUtil

Imports System.IO
Imports System.Security.Cryptography
Public Class SecurityUtils
'------------------------------------------------------------------------
'---AESについて
'------------------------------------------------------------------------
'共通鍵暗号アルゴリズム(対称アルゴリズム)にて暗号化を行う
'Salt、初期化ベクトル、(key生成に使っていればパスフレーズも)を双方で共有することで、暗号化、複合化を行う。
'厳密にはSaltではなくkey。saltを使ってKeyが生成できる。
'Keyの生成にSaltだけではなくパスフレーズも使っている場合は、パスフレーズも共有する必要がある。
'(*)Salt、初期化ベクトルは例えば暗号化データ送信時に、ファイルの頭にセットして送ったりする。
' ・key : 秘匿すべきKey。暗号化元と複合化先でKeyを共有することで複合化を行う。
' ・IV:公開してもよい初期化ベクタ。通常は新規暗号化の都度作成する。
' ・Salt:キーを生成する為の要素。公開してもよい。
' ・Password:Keyを生成する再、パスフレーズとSaltから生成することが可能。
' 同じSalt、パスフレーズから生成されたKeyは、毎回同じ値となる
'
'------------------------------------------------------------------------
'---ITAESSetについて
'------------------------------------------------------------------------
'当クラスは、基本的に以下のITAESSetの設定値を操作し、ITAESSetをやり取りする。
'Public Interface ITAESSet
' Property DecryptedText As String
' Property EncryptedText As String
' Property Key As String
' Property Iv As String
' Property Salt As String
' Property KeyCreatePassPharse As String
'End Interface
'Public Class TAESSet
' Implements ITData, ITAESSet
' <DisplayInfomationAttribute("", "", False, False)>
' Public Property DecryptedText As String Implements ITAESSet.DecryptedText
' <DisplayInfomationAttribute("", "", False, False)>
' Public Property EncryptedText As String Implements ITAESSet.EncryptedText
' <DisplayInfomationAttribute("", "", False, False)>
' Public Property Key As String Implements ITAESSet.Key
' <DisplayInfomationAttribute("", "", False, False)>
' Public Property Iv As String Implements ITAESSet.Iv
' <DisplayInfomationAttribute("", "", False, False)>
' Public Property Salt As String Implements ITAESSet.Salt
' <DisplayInfomationAttribute("", "", False, False)>
' Public Property KeyCreatePassPharse As String Implements ITAESSet.KeyCreatePassPharse
'End Class

'------------------------------------------------------------------------
'---AESについて End
'------------------------------------------------------------------------

''' <summary>
''' esCryptgraphy クラスのインスタンスを初期化します。
''' </summary>
Public Sub New()
Me.BlockSize = 128
Me.KeySize = 256
Me.SaltSize = 25
End Sub

''' <summary>
''' ブロック長を取得または設定
''' ※値は 128bit 固定。
''' </summary>
Public Property BlockSize As Integer

''' <summary>
''' キー長を取得または設定
''' ※値は 128 / 192 / 256 bit から選択
''' </summary>
''' <returns></returns>
Public Property KeySize As Integer

''' <summary>
''' Saltサイズを設定
''' ※8Byte以上
''' </summary>
''' <returns></returns>
Public Property SaltSize As Integer

''' <summary>
''' 共通鍵を派生させるパスワードを指定して共通鍵を生成。
''' </summary>
''' <param name="passPhrase">keyを生成するパスワード</param>
Public Function CreateKey(ByVal passPhrase As String, ByVal salt As String) As String
'--- Key を生成
Dim rfcKey As New Rfc2898DeriveBytes(passPhrase, Convert.FromBase64String(salt), 1000)
Dim arrKey As Byte() = rfcKey.GetBytes(Me.KeySize / 8)
Return Convert.ToBase64String(arrKey)
End Function

''' <summary>
''' 共通鍵を派生させるパスワードを指定してIVを生成。
''' </summary>
''' <param name="passPhrase"></param>
''' <returns></returns>
Public Function CreateIV(ByVal passPhrase As String) As String
'--- IV を生成
Dim rfcBlock As New Rfc2898DeriveBytes(passPhrase + DateTime.Now.Ticks.ToString(), 100, 1000)
Dim arrBlock As Byte() = rfcBlock.GetBytes(Me.BlockSize / 8)
Return Convert.ToBase64String(arrBlock)
End Function

''' <summary>
''' Saltを生成
''' </summary>
''' <returns></returns>
Public Function CreateSalt() As String
Dim Salt As Byte() = New Rfc2898DeriveBytes(DateTime.Now.Ticks.ToString(), Me.SaltSize, 1000).Salt
Return Convert.ToBase64String(Salt)
End Function

''' <summary>
''' IV、キーを指定して暗号化された文字列の複合を行う。
''' </summary>
''' <param name="cipherText">暗号化された文字列</param>
''' <param name="iv">IV</param>
''' <param name="key">キー</param>
''' <returns>復号された文字列</returns>
Public Function Decrypt(ByVal cipherText As String, ByVal iv As String, ByVal key As String) As String
Dim plainText As String = String.Empty
Dim csp As New AesCryptoServiceProvider With {
.BlockSize = Me.BlockSize,
.KeySize = Me.KeySize,
.Mode = CipherMode.CBC,
.Padding = PaddingMode.PKCS7,
.IV = Convert.FromBase64String(iv),
.Key = Convert.FromBase64String(key)
}
Using inms As New MemoryStream(Convert.FromBase64String(cipherText))
Using decryptor As ICryptoTransform = csp.CreateDecryptor()
Using cs = New CryptoStream(inms, decryptor, CryptoStreamMode.Read)
Using reader As New StreamReader(cs)
plainText = reader.ReadToEnd()
End Using
Return plainText
End Using
End Using
End Using
End Function

''' <summary>
''' ITAESSetのEncryptedTextの内容を復号し、DecryptedTextにセットする。
''' </summary>
''' <param name="Taes"></param>
''' <returns></returns>
Public Function Decrypt(ByVal tAes As ITAESSet) As ITAESSet
If tAes Is Nothing Then Return Nothing
If String.IsNullOrWhiteSpace(tAes.EncryptedText) Then Return tAes
Dim csp As New AesCryptoServiceProvider With {
.BlockSize = Me.BlockSize,
.KeySize = Me.KeySize,
.Mode = CipherMode.CBC,
.Padding = PaddingMode.PKCS7,
.IV = Convert.FromBase64String(tAes.Iv),
.Key = Convert.FromBase64String(Me.CreateKey(tAes.KeyCreatePassPharse, tAes.Salt))
}
Using inms As New MemoryStream(Convert.FromBase64String(tAes.EncryptedText))
Using decryptor As ICryptoTransform = csp.CreateDecryptor()
Using cs = New CryptoStream(inms, decryptor, CryptoStreamMode.Read)
Using reader As New StreamReader(cs)
tAes.DecryptedText = reader.ReadToEnd()
End Using
Return tAes
End Using
End Using
End Using
End Function

''' <summary>
''' IV、キーを指定して文字列の暗号化を行う。
''' </summary>
''' <param name="plainText">暗号化する文字列</param>
''' <param name="iv">IV</param>
''' <param name="key">キー</param>
''' <returns>暗号化された文字列</returns>
Public Function Encrypt(ByVal plainText As String, ByVal iv As String, ByVal key As String) As String
Dim cipherText As String = String.Empty
Dim csp As New AesCryptoServiceProvider With {
.BlockSize = Me.BlockSize,
.KeySize = Me.KeySize,
.Mode = CipherMode.CBC,
.Padding = PaddingMode.PKCS7,
.IV = Convert.FromBase64String(iv),
.Key = Convert.FromBase64String(key)
}
Using outms As New MemoryStream()
Using encryptor As ICryptoTransform = csp.CreateEncryptor()
Using cs As New CryptoStream(outms, encryptor, CryptoStreamMode.Write)
Using writer As New StreamWriter(cs)
writer.Write(plainText)
End Using
cipherText = Convert.ToBase64String(outms.ToArray())
End Using
Return cipherText
End Using
End Using
End Function

''' <summary>
''' ITAESSetのDecryptedTextの内容を暗号化し、EncryptedTextにセットする。
''' IV、Saltが未指定の場合は当メソッド内で生成する。
''' </summary>
''' <param name="tAes"></param>
''' <returns></returns>
Public Function Encrypt(ByVal tAes As ITAESSet) As ITAESSet
If tAes Is Nothing Then Return Nothing
If String.IsNullOrWhiteSpace(tAes.DecryptedText) Then Return Nothing
If String.IsNullOrWhiteSpace(tAes.Salt) Then tAes.Salt = Me.CreateSalt()
tAes.Key = Me.CreateKey(AppConstants.SEC_SQL_PASS_PHARSE, tAes.Salt)
If String.IsNullOrWhiteSpace(tAes.Iv) Then tAes.Iv = Me.CreateIV(AppConstants.SEC_SQL_PASS_PHARSE)
Dim csp As New AesCryptoServiceProvider With {
.BlockSize = Me.BlockSize,
.KeySize = Me.KeySize,
.Mode = CipherMode.CBC,
.Padding = PaddingMode.PKCS7,
.IV = Convert.FromBase64String(tAes.Iv),
.Key = Convert.FromBase64String(tAes.Key)
}
Using outms As New MemoryStream()
Using encryptor As ICryptoTransform = csp.CreateEncryptor()
Using cs As New CryptoStream(outms, encryptor, CryptoStreamMode.Write)
Using writer As New StreamWriter(cs)
writer.Write(tAes.DecryptedText)
End Using
tAes.EncryptedText = Convert.ToBase64String(outms.ToArray())
End Using
Return tAes
End Using
End Using
End Function
End Class