DpAPI Encrypted Aes Key Problems

Discussion in 'ASP .Net Security' started by Phil C., Mar 5, 2005.

  1. Phil C.

    Phil C. Guest

    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())
     
    Phil C., Mar 5, 2005
    #1
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. BigLuzer
    Replies:
    1
    Views:
    1,424
    Cowboy \(Gregory A. Beamer\)
    Nov 21, 2006
  2. Phil C.
    Replies:
    3
    Views:
    246
    Joe Kaplan \(MVP - ADSI\)
    Feb 25, 2005
  3. Phil C.
    Replies:
    8
    Views:
    193
    charlestek
    Mar 17, 2005
  4. Phil C.
    Replies:
    2
    Views:
    453
    Phil C.
    Jul 19, 2005
  5. Nate Wiger

    New AES gem available -- fast-aes

    Nate Wiger, Jan 20, 2010, in forum: Ruby
    Replies:
    3
    Views:
    198
    Pål Bergström
    Jul 1, 2010
Loading...

Share This Page