2014年11月7日 星期五

NET上的對稱、非對稱、雜湊式加解密

引用

'『對稱式』加密,
'''此方法可將加密過的密碼做逆向的解密工作,
'''套用範圍較廣,但目前架構僅限於伺服器端的內容加密儲存方式,
'''此目的是為了不讓具有資料庫管理權限的管理者直接看到一些
'''屬於公司內部的機密資料或是重要資料,而造成資料外洩的情況發生。
'
'-----------------------------------------------------------------------------------------------------------------
'
'此架構必須設計三個儲存『對稱演算法的秘密金鑰SecretKey』、『對稱演算法的起始向量SecretIV』及
'『加密後Base64內容字串EncryptedString』欄位
'以機密內容加密為例:
'加密時:由外部輸入欲加密字串內容後,程式會自動產生『對稱演算法的秘密金鑰』、『對稱演算法的起始向量』,
'        上述兩個資料是為瞭解密之用,因此你在前端程式必須將之儲存於資料庫欄位中,以利解密時取出之用。
'        隨後產生加密後的內容字串,此字串我們再使用Base64來做一次處理,加強加密內容的複雜度,
'        當然加密的欄位也必須儲存起來。
'       
'解密時:我們可以從資料庫取出先前加密時產生的『對稱演算法的秘密金鑰』、『對稱演算法的起始向量』,
'        另外取出加密後的字串來做解密工作。       
'
'-----------------------------------------------------------------------------------------------------------------

Imports System
Imports System.Text
Imports System.IO
Imports System.Security.Cryptography
Namespace Util.Encrypt
    Public Class Symmetric
#Region "變數宣告"
        Private mEncryptSrcStr As String
        Private mDecryptSrcStr() As Byte
        Private mEncrypt As String
        Private mDecrypt As String
        Private mSakey As String
        Private mSaIV As String
        Private mDSaKey() As Byte
        Private mDSaIV() As Byte
#End Region
#Region "屬性宣告"
        Public WriteOnly Property EncryptSrcStr() As String ''來源欲加密字串
            Set(ByVal Value As String)
                mEncryptSrcStr = Value
            End Set
        End Property
        Public WriteOnly Property DecryptSrcStr() As String ''來源欲解密字串
            Set(ByVal Value As String)
                mDecryptSrcStr = Convert.FromBase64String(Value)
            End Set
        End Property
        Public ReadOnly Property EncryptedString() As String ''加密後字串
            Get
                Return mEncrypt
            End Get
        End Property
        Public ReadOnly Property DecryptedString() As String ''解密後字串
            Get
                Return mDecrypt
            End Get
        End Property
        Public ReadOnly Property SecretKey() As String ''密鑰字串KEY秘密金鑰
            Get
                Return mSakey
            End Get
        End Property
        Public ReadOnly Property SecretIV() As String ''密鑰字串IV起始向量
            Get
                Return mSaIV
            End Get
        End Property

        Public WriteOnly Property DeSecretKey() As String ''密鑰字串KEY秘密金鑰
            Set(ByVal Value As String)
                mDSaKey = Convert.FromBase64String(Value)
            End Set
        End Property
        Public WriteOnly Property DeSecretIV() As String  ''密鑰字串IV起始向量
            Set(ByVal Value As String)
                mDSaIV = Convert.FromBase64String(Value)
            End Set
        End Property

#End Region
        Public Sub New()
        End Sub
        Public Function EcryptSymmetric() As Boolean ''對稱式加密
            '''==產生密鑰
            Dim sa As SymmetricAlgorithm
            Dim tmpSa As ICryptoTransform
            sa = Rijndael.Create()                  'AES (Rijndael) is a symmetric-key block cipher
            sa.GenerateKey()                        '產生隨機的 (32*8) 位的密鑰
            sa.Mode = CipherMode.ECB                '區串流優先等級處理模式
            sa.Padding = PaddingMode.Zeros          '末尾資料區串流優先等級的填充模式
            mSakey = Convert.ToBase64String(sa.Key) '取得SymmetricAlgorithm的對稱演算法的秘密金鑰
            mSaIV = Convert.ToBase64String(sa.IV)   '取得SymmetricAlgorithm的對稱演算法的起始向量
            tmpSa = sa.CreateEncryptor(Convert.FromBase64String(mSakey), Convert.FromBase64String(mSaIV))
            '''==============================================================================================
            Dim ms As MemoryStream
            Dim cs As CryptoStream
            Dim Bufffer As Byte() = New Byte() {}
            ms = New MemoryStream
            cs = New CryptoStream(ms, tmpSa, CryptoStreamMode.Write)
            If mEncryptSrcStr <> String.Empty Then
                Bufffer = Encoding.UTF8.GetBytes(mEncryptSrcStr)
                cs.Write(Bufffer, 0, Bufffer.Length)
                cs.FlushFinalBlock()
                cs.Close()
                cs = Nothing
                mEncrypt = String.Empty
                mEncrypt = Convert.ToBase64String(ms.ToArray()) '加密後BASE64內容字串
                If mEncrypt <> String.Empty Then
                    Return True
                Else
                    Return False
                End If
                ms.Close()
            Else
                Throw New System.Exception("Error,加密原始字串內容是空值!")
            End If

        End Function

        Public Function DecryptSymmetric() As Boolean ''對稱式解密
            Dim ms As MemoryStream
            Dim sa As SymmetricAlgorithm
            Dim tmpSa As ICryptoTransform
            Dim cs As CryptoStream
            ms = New MemoryStream
            sa = Rijndael.Create()                  'AES (Rijndael) is a symmetric-key block cipher
            sa.Mode = CipherMode.ECB                '區串流優先等級處理模式
            sa.Padding = PaddingMode.Zeros          '末尾資料區串流優先等級的填充模式
            sa.Key = mDSaKey
            sa.IV = mDSaIV
            tmpSa = sa.CreateDecryptor
            cs = New CryptoStream(ms, tmpSa, CryptoStreamMode.Write)
            cs.Write(mDecryptSrcStr, 0, mDecryptSrcStr.Length)
            cs = Nothing
            mDecrypt = Encoding.UTF8.GetString(ms.ToArray()) '解密後內容字串
            If mDecrypt <> String.Empty Then
                Return True
            Else
                Return False
            End If
        End Function

    End Class
End Namespace

'------------------------------------------------------------------
'『非對稱式』加密,
'''此方法無法將加密過的密碼做逆向的解密工作,
'''通常適用於會員機制的伺服器端的密碼欄位儲存方式,
'''此目的是為了不讓具有資料庫管理權限的管理者直接看到使用者密碼,
'''而造成使用者密碼不當曝光的情況發生。
'
'------------------------------------------------------------------
'
'此架構必須設計兩個儲存『加密後密碼』及『加密的亂數』欄位
'以會員機制為例:
'註冊時:新的使用者註冊時會輸入密碼,儲存時我們便可使用
'        CreateSalt()加密的亂數及CreateHash()加密亂數
'        儲存於資料庫中。
'登入時:使用者會輸入帳戶及密碼,此時前端輸入的密碼為未加密過的密碼
'        ,此時將此密碼經過先前產生出來的『加密的亂數』再做一次
'        CreateHash()產生的加密密碼後,與原來資料庫內儲存的密碼做
'        比對即可,上述方法可呼叫CheckAuthentication()即可。       
'
'------------------------------------------------------------------
Imports System
Imports System.Text
Imports System.IO
Imports System.Security.Cryptography
Imports System.Web.Security.FormsAuthentication
Namespace Util.Encrypt
    Public Class Asymmetric
        ''CreateSalt 產生經過 RNGCryptoServiceProvider 所加密的亂數
        ''這是被用來傳遞給CreateHash()做串連使用者前端畫面所輸入的密碼之方法
        Public Function CreateSalt() As String
            Dim rng As RNGCryptoServiceProvider = New RNGCryptoServiceProvider '實作密碼編譯亂數產生器 (RNG)。
            Dim size As Integer
            size = CInt(Int((20 * Rnd()) + 1))
            Dim buff() As Byte = New Byte(size) {}
            rng.GetBytes(buff)
            Return Convert.ToBase64String(buff)
        End Function
        ''CreateHash 產生雜湊運算後的字串
        ''salt 為CreateSalt() 所產生的加密字串
        ''pwd 為前端使用者在畫面所輸入的密碼
        Public Function CreateHash(ByVal pwd As String, ByVal salt As String) As String
            Dim saltPwd As String = String.Concat(pwd, salt)
            Dim data() As Byte = Encoding.UTF8.GetBytes(saltPwd)
            Dim result() As Byte
            Dim shaM As New SHA1Managed
            result = shaM.ComputeHash(data)
            Dim hashPwd As String = Convert.ToBase64String(result)
            Return hashPwd
        End Function
        ''pwd 未加密過的密碼,也就是前端使用者所輸入的密碼
        ''hashedPwd 已儲存在資料庫中且加密過的密碼
        ''salt 已儲存在資料庫中且經過 RNGCryptoServiceProvider 所產生的加密亂數
        Public Function CheckAuthentication(ByVal pwd As String, ByVal salt As String, ByVal hashedPwd As String) As Boolean
            Dim hashPwdcmp As String = CreateHash(pwd, salt)
            Dim cp As Boolean
            If hashedPwd.Equals(hashPwdcmp) Then
                cp = True
            Else
                cp = False
            End If
            Return cp
        End Function
    End Class
End Namespace

沒有留言:

張貼留言