![]() |
DpAPI Encrypted Aes Key Problems
Hi.
I used the Microsoft Dpapi to encrypt a symmetric AES key generated from the code below INTO TEXT. The text dpapi encrypted Aes key is stored in the web.config file of my app in a custom config handler section. When I reverse decrypt the key with the dpapi in the classes I need the key, I get a wrong keysize error. I think the problem may lie in the byte to text conversion with my Aes generation, or in the DPapi. I have problems with the Dpapi Text Wrappers if I don't use Encoding.ASCII instead of Encoding.Unicode If I don't use Convert.ToBase64String to copy the key as text, I get garbage characters in ascii. Any help is appreciated. Phil Boston, MA Keygen: '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''' Imports System Imports System.IO Imports System.Text Imports System.Security.Cryptography Public Class KeyGen Friend Function CreateKey() As String 'Create a new AES Service Provider Dim aesProvider As New RijndaelManaged 'Declare the key size aesProvider.KeySize = 256 aesProvider.BlockSize = 256 aesProvider.GenerateKey() Return Convert.ToBase64String(aesProvider.Key) End Function End Class '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''' Dpapi Data Protector: 'Listing A: The DataProtector class 'From Builder.com code 'Phil Czapla 1/18/05 'This class is a VB.NET version of the DataProtector class available on MSDN with the addition of methods that make it easier to use with strings. Option Strict On Imports System.Runtime.InteropServices Imports System.Text Namespace Microsoft.Win32.DPAPI '************************************************* ********************************** ' This code has been translated from the DPAPI examples in C# ' at http://msdn.microsoft.com/library/de...SecNetHT08.asp ' I've added methods to do string encryption and decryption with ' base64 encoding '************************************************* ********************************** Public NotInheritable Class DataProtector #Region "Unmanaged APIs" <DllImport("Crypt32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Au to)> _ Private Shared Function CryptProtectData( _ ByRef pDataIn As DATA_BLOB, _ ByVal szDataDescr As String, _ ByRef pOptionalEntropy As DATA_BLOB, _ ByVal pvReserved As IntPtr, _ ByRef pPromptStruct As CRYPTPROTECT_PROMPTSTRUCT, _ ByVal dwFlags As Integer, _ ByRef pDataOut As DATA_BLOB) As Boolean End Function <DllImport("Crypt32.dll", SetLastError:=True, CharSet:=System.Runtime.InteropServices.CharSet.Au to)> _ Private Shared Function CryptUnprotectData( _ ByRef pDataIn As DATA_BLOB, _ ByVal szDataDescr As String, _ ByRef pOptionalEntropy As DATA_BLOB, _ ByVal pvReserved As IntPtr, _ ByRef pPromptStruct As CRYPTPROTECT_PROMPTSTRUCT, _ ByVal dwFlags As Integer, _ ByRef pDataOut As DATA_BLOB) As Boolean End Function <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _ Private Structure DATA_BLOB Public cbData As Integer Public pbData As IntPtr End Structure <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Unicode)> _ Private Structure CRYPTPROTECT_PROMPTSTRUCT Public cbSize As Integer Public dwPromptFlags As Integer Public hwndApp As IntPtr Public szPrompt As String End Structure <DllImport("kernel32.dll", CharSet:=System.Runtime.InteropServices.CharSet.Au to)> _ Private Shared Function FormatMessage(ByVal dwFlags As Integer, _ ByRef lpSource As IntPtr, _ ByVal dwMessageId As Integer, _ ByVal dwLanguageId As Integer, _ ByRef lpBuffer As String, _ ByVal nSize As Integer, _ ByVal Arguments As IntPtr) As Integer End Function 'Private Shared NullPtr As IntPtr = IntPtr.Zero Private Const CRYPTPROTECT_UI_FORBIDDEN As Integer = &H1 Private Const CRYPTPROTECT_LOCAL_MACHINE As Integer = &H4 #End Region #Region "Declarations and Utilities" Public Enum Store USE_MACHINE_STORE USE_USER_STORE End Enum Private Shared Sub InitPromptstruct(ByRef ps As CRYPTPROTECT_PROMPTSTRUCT) ps.cbSize = Marshal.SizeOf(GetType(CRYPTPROTECT_PROMPTSTRUCT)) ps.dwPromptFlags = 0 ps.hwndApp = IntPtr.Zero ps.szPrompt = Nothing End Sub Private Shared Function GetErrorMessage(ByVal errorCode As Integer) As String Dim FORMAT_MESSAGE_ALLOCATE_BUFFER As Integer = &H100 Dim FORMAT_MESSAGE_IGNORE_INSERTS As Integer = &H200 Dim FORMAT_MESSAGE_FROM_SYSTEM As Integer = &H1000 Dim messageSize As Integer = 255 Dim lpMsgBuf As String = "" Dim dwFlags As Integer = FORMAT_MESSAGE_ALLOCATE_BUFFER Or FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS Dim ptrlpSource As IntPtr = New IntPtr Dim prtArguments As IntPtr = New IntPtr Dim retVal As Integer = FormatMessage(dwFlags, ptrlpSource, errorCode, 0, lpMsgBuf, messageSize, prtArguments) If retVal = 0 Then Throw New Exception("Failed to format message for error code " & errorCode & ". ") End If Return lpMsgBuf End Function #End Region #Region "Encrypt Strings" ' These methods return the Base64 encoded string suitable for storing in a web.config file Public Overloads Shared Function EncryptString(ByVal plainText As String) As String Dim dataToEncrypt() As Byte = Encoding.ASCII.GetBytes(plainText) ' Not passing optional entropy and use the machine store Return Convert.ToBase64String(DataProtector.Encrypt(dataT oEncrypt, Nothing, Store.USE_MACHINE_STORE)) End Function Public Overloads Shared Function EncryptString(ByVal plainText As String, ByVal entropyText As String) As String Dim dataToEncrypt() As Byte = Encoding.ASCII.GetBytes(plainText) Dim entropyData() As Byte = Encoding.ASCII.GetBytes(entropyText) ' Passing optional entropy and use the machine store Return Convert.ToBase64String(DataProtector.Encrypt(dataT oEncrypt, entropyData, DataProtector.Store.USE_MACHINE_STORE)) End Function Public Overloads Shared Function EncryptString(ByVal plainText As String, ByVal entropyText As String, ByVal store As Store) As String Dim dataToEncrypt() As Byte = Encoding.ASCII.GetBytes(plainText) Dim entropyData() As Byte = Encoding.ASCII.GetBytes(entropyText) ' Passing optional entropy and store Return Convert.ToBase64String(DataProtector.Encrypt(dataT oEncrypt, entropyData, store)) End Function #End Region #Region "Decrypt Strings" ' These methods return the ASCII representation of a base64 encoded string Public Overloads Shared Function DecryptString(ByVal base64Text As String) As String Dim dataToDecrypt() As Byte = Convert.FromBase64String(base64Text) ' Not passing optional entropy and use the machine store Return Encoding.ASCII.GetString(DataProtector.Decrypt(dat aToDecrypt, Nothing, Store.USE_MACHINE_STORE)) End Function Public Overloads Shared Function DecryptString(ByVal base64Text As String, ByVal entropyText As String) As String Dim dataToDecrypt() As Byte = Convert.FromBase64String(base64Text) Dim entropyDataToDecrypt() As Byte = Encoding.ASCII.GetBytes(entropyText) ' Passing optional entropy and use the machine store Return Encoding.ASCII.GetString(DataProtector.Decrypt(dat aToDecrypt, entropyDataToDecrypt, DataProtector.Store.USE_MACHINE_STORE)) End Function Public Overloads Shared Function DecryptString(ByVal base64Text As String, ByVal entropyText As String, ByVal store As Store) As String Dim dataToDecrypt() As Byte = Convert.FromBase64String(base64Text) Dim entropyDataToDecrypt() As Byte = Encoding.ASCII.GetBytes(entropyText) ' Not passing optional entropy and use the machine store Return Encoding.ASCII.GetString(DataProtector.Decrypt(dat aToDecrypt, entropyDataToDecrypt, store)) End Function #End Region Public Shared Function Encrypt(ByVal plainText As Byte(), _ ByVal optionalEntropy As Byte(), _ ByVal store As Store) As Byte() Dim retVal As Boolean = False Dim plainTextBlob As DATA_BLOB = New DATA_BLOB Dim cipherTextBlob As DATA_BLOB = New DATA_BLOB Dim entropyBlob As DATA_BLOB = New DATA_BLOB Dim prompt As CRYPTPROTECT_PROMPTSTRUCT = New CRYPTPROTECT_PROMPTSTRUCT InitPromptstruct(prompt) Dim dwFlags As Integer Try Try Dim bytesSize As Integer = plainText.Length plainTextBlob.pbData = Marshal.AllocHGlobal(bytesSize) If plainTextBlob.pbData.Equals(IntPtr.Zero) Then Throw New Exception("Unable to allocate plaintext buffer.") End If plainTextBlob.cbData = bytesSize Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize) Catch ex As Exception Throw New Exception("Exception marshalling data. " & ex.Message) End Try If store.USE_MACHINE_STORE = store Then ' Using the machine store, should be providing entropy. dwFlags = CRYPTPROTECT_LOCAL_MACHINE Or CRYPTPROTECT_UI_FORBIDDEN ' Check to see if the entropy is null If optionalEntropy Is Nothing Then ' Allocate something optionalEntropy = New Byte() {} End If Try Dim bytesSize As Integer = optionalEntropy.Length entropyBlob.pbData = Marshal.AllocHGlobal(optionalEntropy.Length) If entropyBlob.pbData.Equals(IntPtr.Zero) Then Throw New Exception("Unable to allocate entropy data buffer.") End If Marshal.Copy(optionalEntropy, 0, entropyBlob.pbData, bytesSize) entropyBlob.cbData = bytesSize Catch ex As Exception Throw New Exception("Exception entropy marshalling data. " & ex.Message) End Try Else ' Using the user store dwFlags = CRYPTPROTECT_UI_FORBIDDEN End If retVal = CryptProtectData(plainTextBlob, "", entropyBlob, IntPtr.Zero, prompt, dwFlags, cipherTextBlob) If False = retVal Then Throw New Exception("Encryption failed. " & GetErrorMessage(Marshal.GetLastWin32Error())) End If Catch ex As Exception Throw New Exception("Exception encrypting. " + ex.Message) End Try Dim cipherText(cipherTextBlob.cbData) As Byte Marshal.Copy(cipherTextBlob.pbData, cipherText, 0, cipherTextBlob.cbData) Return cipherText End Function Public Shared Function Decrypt(ByVal cipherText As Byte(), _ ByVal optionalEntropy As Byte(), _ ByVal store As Store) As Byte() Dim retVal As Boolean = False Dim plainTextBlob As DATA_BLOB = New DATA_BLOB Dim cipherBlob As DATA_BLOB = New DATA_BLOB Dim prompt As CRYPTPROTECT_PROMPTSTRUCT = New CRYPTPROTECT_PROMPTSTRUCT InitPromptstruct(prompt) Try Try Dim cipherTextSize As Integer = cipherText.Length cipherBlob.pbData = Marshal.AllocHGlobal(cipherTextSize) If cipherBlob.pbData.Equals(IntPtr.Zero) Then Throw New Exception("Unable to allocate cipherText buffer.") End If cipherBlob.cbData = cipherTextSize Marshal.Copy(cipherText, 0, cipherBlob.pbData, cipherBlob.cbData) Catch ex As Exception Throw New Exception("Exception marshalling data. " & ex.Message) End Try Dim entropyBlob As DATA_BLOB = New DATA_BLOB Dim dwFlags As Integer If store.USE_MACHINE_STORE = store Then ' Using the machine store, should be providing entropy. dwFlags = CRYPTPROTECT_LOCAL_MACHINE Or CRYPTPROTECT_UI_FORBIDDEN ' Check to see if the entropy is null If optionalEntropy Is Nothing Then ' Allocate something optionalEntropy = New Byte() {} End If Try Dim bytesSize As Integer = optionalEntropy.Length entropyBlob.pbData = Marshal.AllocHGlobal(bytesSize) If entropyBlob.pbData.Equals(IntPtr.Zero) Then Throw New Exception("Unable to allocate entropy buffer.") End If entropyBlob.cbData = bytesSize Marshal.Copy(optionalEntropy, 0, entropyBlob.pbData, bytesSize) Catch ex As Exception Throw New Exception("Exception entropy marshalling data. " & ex.Message) End Try Else ' Using the user store dwFlags = CRYPTPROTECT_UI_FORBIDDEN End If retVal = CryptUnprotectData(cipherBlob, Nothing, entropyBlob, IntPtr.Zero, prompt, dwFlags, plainTextBlob) If Not retVal Then Throw New Exception("Decryption failed. " & GetErrorMessage(Marshal.GetLastWin32Error())) End If ' Free the blob and entropy. If Not cipherBlob.pbData.Equals(IntPtr.Zero) Then Marshal.FreeHGlobal(cipherBlob.pbData) End If If Not entropyBlob.pbData.Equals(IntPtr.Zero) Then Marshal.FreeHGlobal(entropyBlob.pbData) End If Catch ex As Exception Throw New Exception("Exception decrypting. " & ex.Message) End Try Dim plainText(plainTextBlob.cbData) As Byte Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainTextBlob.cbData) Return plainText End Function End Class End Namespace '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''' '''''''''''''''''''''''''''''''''''''''''''''''''' ''''''''''''''''''''''''' Retrieving Aes Key from web config: Private _key() As Byte = utf8encoder.GetBytes(Processor.configHandler.AesKe yString()) |
| All times are GMT. The time now is 11:02 AM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.