microsoft-visualbasic-runtime/Extensions/Security/SHA.vb

324 lines
13 KiB
VB.net

#Region "Microsoft.VisualBasic::aea2365815cc6204399888e7186c27d2, Microsoft.VisualBasic.Core\Extensions\Security\SHA.vb"
' Author:
'
' asuka (amethyst.asuka@gcmodeller.org)
' xie (genetics@smrucc.org)
' xieguigang (xie.guigang@live.com)
'
' Copyright (c) 2018 GPL3 Licensed
'
'
' GNU GENERAL PUBLIC LICENSE (GPL3)
'
'
' This program is free software: you can redistribute it and/or modify
' it under the terms of the GNU General Public License as published by
' the Free Software Foundation, either version 3 of the License, or
' (at your option) any later version.
'
' This program is distributed in the hope that it will be useful,
' but WITHOUT ANY WARRANTY; without even the implied warranty of
' MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
' GNU General Public License for more details.
'
' You should have received a copy of the GNU General Public License
' along with this program. If not, see <http://www.gnu.org/licenses/>.
' /********************************************************************************/
' Summaries:
' Class SHA256
'
' Properties: CertificateSigned, Passphrase
'
' Constructor: (+1 Overloads) Sub New
' Function: Decrypt, DecryptString, Deserialization, Encrypt, EncryptData
' (+2 Overloads) GetDynamicsCertification, Serialization, ToString
'
'
' /********************************************************************************/
#End Region
Imports System.IO
Imports System.Security.Cryptography
Imports System.Text
Imports Microsoft.VisualBasic.Linq.Extensions
Namespace SecurityString
''' <summary>
''' Derives a SHA256 key from a password using an extension of the PBKDF1 algorithm.
''' </summary>
''' <remarks></remarks>
Public Class SHA256 : Inherits SecurityStringModel
Const hashAlgorithm As String = "SHA1"
Const keySize As Integer = 256
Const passwordIterations As Integer = 2
' Convert strings defining encryption key characteristics into byte
' arrays. Let us assume that strings only contain ASCII codes.
' If strings include Unicode characters, use Unicode, UTF7, or UTF8
' encoding.
Dim initVectorBytes As Byte()
Dim saltValueBytes As Byte()
''' <summary>
'''
''' </summary>
''' <param name="password"></param>
''' <param name="saltValue">8 Bytes</param>
Sub New(password As String, saltValue As String)
Const initVector = "@1B2c3D4e5F6g7H8"
Me.strPassphrase = password
Me.initVectorBytes = Encoding.ASCII.GetBytes(initVector)
Me.saltValueBytes = Encoding.ASCII.GetBytes(saltValue)
End Sub
Public Overrides Function ToString() As String
Return MyBase.ToString() & $"// {NameOf(saltValueBytes)}:={String.Join(", ", saltValueBytes.Select(Of String)(Function(b) CStr(b)).ToArray)}"
End Function
Public ReadOnly Property Passphrase As String
Get
Return Me.strPassphrase
End Get
End Property
Public Overloads Overrides Function Decrypt(cipherTextBytes As Byte()) As Byte()
' First, we must create a password, from which the key will be
' derived. This password will be generated from the specified
' passphrase and salt value. The password will be created using
' the specified hash algorithm. Password creation can be done in
' several iterations.
Dim password As New PasswordDeriveBytes(strPassphrase, saltValueBytes, hashAlgorithm, passwordIterations)
' Use the password to generate pseudo-random bytes for the encryption
' key. Specify the size of the key in bytes (instead of bits).
#Disable Warning
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
#Enable Warning
' Create uninitialized Rijndael encryption object.
Dim symmetricKey As New RijndaelManaged()
' It is reasonable to set encryption mode to Cipher Block Chaining
' (CBC). Use default options for other symmetric key parameters.
symmetricKey.Mode = CipherMode.CBC
' Generate decryptor from the existing key bytes and initialization
' vector. Key size will be defined based on the number of the key
' bytes.
Dim decryptor As ICryptoTransform = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)
' Define memory stream which will be used to hold encrypted data.
Dim memoryStream As New MemoryStream(cipherTextBytes)
' Define cryptographic stream (always use Read mode for encryption).
Dim cryptoStream As New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)
' Since at this point we don't know what the size of decrypted data
' will be, allocate the buffer long enough to hold ciphertext;
' plaintext is never longer than ciphertext.
Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}
' Start decrypting.
Dim decryptedByteCount As Integer = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
' Close both streams.
memoryStream.Close()
cryptoStream.Close()
' Convert decrypted data into a string.
' Let us assume that the original plaintext string was UTF8-encoded.
Return plainTextBytes
End Function
''' <summary>
''' 字符串的解密方法
''' </summary>
''' <param name="cipherText"></param>
''' <returns></returns>
''' <remarks></remarks>
Public Overrides Function DecryptString(cipherText As String) As String
' Convert our ciphertext into a byte array.
Dim cipherTextBytes As Byte() = Convert.FromBase64String(cipherText)
' First, we must create a password, from which the key will be
' derived. This password will be generated from the specified
' passphrase and salt value. The password will be created using
' the specified hash algorithm. Password creation can be done in
' several iterations.
Dim password As New PasswordDeriveBytes(strPassphrase, saltValueBytes, hashAlgorithm, passwordIterations)
' Use the password to generate pseudo-random bytes for the encryption
' key. Specify the size of the key in bytes (instead of bits).
#Disable Warning
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
#Enable Warning
' Create uninitialized Rijndael encryption object.
Dim symmetricKey As New RijndaelManaged()
' It is reasonable to set encryption mode to Cipher Block Chaining
' (CBC). Use default options for other symmetric key parameters.
symmetricKey.Mode = CipherMode.CBC
' Generate decryptor from the existing key bytes and initialization
' vector. Key size will be defined based on the number of the key
' bytes.
Dim decryptor As ICryptoTransform = symmetricKey.CreateDecryptor(keyBytes, initVectorBytes)
' Define memory stream which will be used to hold encrypted data.
Dim memoryStream As New MemoryStream(cipherTextBytes)
' Define cryptographic stream (always use Read mode for encryption).
Dim cryptoStream As New CryptoStream(memoryStream, decryptor, CryptoStreamMode.Read)
' Since at this point we don't know what the size of decrypted data
' will be, allocate the buffer long enough to hold ciphertext;
' plaintext is never longer than ciphertext.
Dim plainTextBytes As Byte() = New Byte(cipherTextBytes.Length - 1) {}
' Start decrypting.
Dim decryptedByteCount As Integer = cryptoStream.Read(plainTextBytes, 0, plainTextBytes.Length)
' Close both streams.
memoryStream.Close()
cryptoStream.Close()
' Convert decrypted data into a string.
' Let us assume that the original plaintext string was UTF8-encoded.
Dim plainText As String = Encoding.UTF8.GetString(plainTextBytes, 0, decryptedByteCount)
Return plainText
End Function
Public Overloads Overrides Function Encrypt(plainTextBytes() As Byte) As Byte()
Dim password As New PasswordDeriveBytes(strPassphrase, saltValueBytes, hashAlgorithm, passwordIterations)
#Disable Warning
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
#Enable Warning
Dim symmetricKey As New RijndaelManaged()
symmetricKey.Mode = CipherMode.CBC
Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)
Dim memoryStream As New MemoryStream()
Dim cryptoStream As New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
cryptoStream.FlushFinalBlock()
Dim cipherTextBytes As Byte() = memoryStream.ToArray()
memoryStream.Close()
cryptoStream.Close()
Return cipherTextBytes
End Function
Public Function Serialization(data As Byte()) As String
data = Encrypt(data)
Return System.Text.Encoding.Unicode.GetString(data)
End Function
Public Function Deserialization(data As String) As Byte()
Dim Buffer As Byte() = System.Text.Encoding.Unicode.GetBytes(data)
Return Decrypt(Buffer)
End Function
''' <summary>
''' Encrypt the plain text string.
''' </summary>
''' <param name="plainText"></param>
''' <returns></returns>
Public Overrides Function EncryptData(plainText As String) As String
Dim plainTextBytes As Byte() = Encoding.UTF8.GetBytes(plainText)
Dim password As New PasswordDeriveBytes(strPassphrase, saltValueBytes, hashAlgorithm, passwordIterations)
#Disable Warning
Dim keyBytes As Byte() = password.GetBytes(keySize \ 8)
#Enable Warning
Dim symmetricKey As New RijndaelManaged()
symmetricKey.Mode = CipherMode.CBC
Dim encryptor As ICryptoTransform = symmetricKey.CreateEncryptor(keyBytes, initVectorBytes)
Dim memoryStream As New MemoryStream()
Dim cryptoStream As New CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write)
cryptoStream.Write(plainTextBytes, 0, plainTextBytes.Length)
cryptoStream.FlushFinalBlock()
Dim cipherTextBytes As Byte() = memoryStream.ToArray()
memoryStream.Close()
cryptoStream.Close()
Dim cipherText As String = Convert.ToBase64String(cipherTextBytes)
Return cipherText
End Function
''' <summary>
''' The previous key of the sha256 encryption will be expired after the rebuild of this module,
''' so that this method is not working on the statics data storage job.
''' (在本模块进行重新编译之后,原有的密匙将会失效,故这个属性不适合于静态存储加密使用)
''' </summary>
''' <value></value>
''' <returns></returns>
''' <remarks></remarks>
Public Shared ReadOnly Property CertificateSigned As SHA256 =
New SHA256(password:=Microsoft.VisualBasic.SecurityString.GetFileMd5(GetType(SHA256).Assembly.Location), saltValue:="ATCGCGAT")
''' <summary>
''' 双重动态数据签名
''' </summary>
''' <typeparam name="T"></typeparam>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetDynamicsCertification(Of T)() As SHA256
Return GetDynamicsCertification(GetType(T))
End Function
''' <summary>
''' 双重动态数据签名
''' </summary>
''' <returns></returns>
''' <remarks></remarks>
Public Shared Function GetDynamicsCertification(TypeInfo As Type) As SHA256
Dim Password As String = Microsoft.VisualBasic.SecurityString.GetFileMd5(TypeInfo.Assembly.Location)
Dim saltValue As String = Microsoft.VisualBasic.SecurityString.GetFileMd5(GetType(SHA256).Assembly.Location)
saltValue = Mid(saltValue, 3, 8)
Return New SHA256(Password, saltValue)
End Function
End Class
End Namespace