DpAPI Encrypted Aes Key Problems

P

Phil C.

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/default.asp?url=/library/en-us/dnnetsec/html/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.Auto)> _

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.Auto)> _

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.Auto)> _

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(dataToEncrypt, 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(dataToEncrypt,
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(dataToEncrypt,
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(dataToDecrypt,
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(dataToDecrypt,
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(dataToDecrypt,
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.AesKeyString())
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Staff online

Members online

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,052
Latest member
LucyCarper

Latest Threads

Top