using System;
using System.Text;
using System.Runtime.InteropServices;
namespace DataProtection
{
/// <summary>
/// Summary description for DataProtector.
/// </summary>
public class DataProtector
{
[DllImport("Crypt32.dll", SetLastError=true,CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool CryptProtectData(ref DATA_BLOB pDataIn,
String szDataDescr,
ref DATA_BLOB pOptionalEntropy,
IntPtr pvReserved,
ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct,
int dwFlags,
ref DATA_BLOB pDataOut);
[DllImport("Crypt32.dll", SetLastError=true,
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool CryptUnprotectData(ref DATA_BLOB pDataIn,
String szDataDescr,
ref DATA_BLOB pOptionalEntropy,
IntPtr pvReserved,
ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct,
int dwFlags,
ref DATA_BLOB pDataOut);
[DllImport("kernel32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags,
ref IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
ref String lpBuffer, int nSize,
IntPtr *Arguments);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public String szPrompt;
}
static private IntPtr NullPtr = ((IntPtr)((int)(0)));
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
public enum Store {USE_MACHINE_STORE = 1, USE_USER_STORE};
private Store store;
public DataProtector(Store tempStore)
{
store = tempStore;
}
public byte[] Encrypt(byte[] plainText, byte[] optionalEntropy)
{
bool retVal = false;
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPromptstruct(ref prompt);
int dwFlags;
try
{
try
{
int bytesSize = plainText.Length;
plainTextBlob.pbData = Marshal.AllocHGlobal(bytesSize);
if(IntPtr.Zero == plainTextBlob.pbData)
{
throw new Exception("Unable to allocate plaintext buffer.");
}
plainTextBlob.cbData = bytesSize;
Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize);
}
catch(Exception ex)
{
throw new Exception("Exception marshalling data. " + ex.Message);
}
if(Store.USE_MACHINE_STORE == store)
{//Using the machine store, should be providing entropy.
dwFlags = CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
//Check to see if the entropy is null
if(null == optionalEntropy)
{//Allocate something
optionalEntropy = new byte[0];
}
try
{
int bytesSize = optionalEntropy.Length;
entropyBlob.pbData = Marshal.AllocHGlobal(optionalEntropy.Length);;
if(IntPtr.Zero == entropyBlob.pbData)
{
throw new Exception("Unable to allocate entropy data buffer.");
}
Marshal.Copy(optionalEntropy, 0, entropyBlob.pbData, bytesSize);
entropyBlob.cbData = bytesSize;
}
catch(Exception ex)
{
throw new Exception("Exception entropy marshalling data. " +
ex.Message);
}
}
else
{//Using the user store
dwFlags = CRYPTPROTECT_UI_FORBIDDEN;
}
retVal = CryptProtectData(ref plainTextBlob, "", ref entropyBlob,
IntPtr.Zero, ref prompt, dwFlags,
ref cipherTextBlob);
if(false == retVal)
{
throw new Exception("Encryption failed. " +
GetErrorMessage(Marshal.GetLastWin32Error()));
}
}
catch(Exception ex)
{
throw new Exception("Exception encrypting. " + ex.Message);
}
byte[] cipherText = new byte[cipherTextBlob.cbData];
Marshal.Copy(cipherTextBlob.pbData, cipherText, 0, cipherTextBlob.cbData);
return cipherText;
}
public byte[] Decrypt(byte[] cipherText, byte[] optionalEntropy)
{
bool retVal = false;
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPromptstruct(ref prompt);
try
{
try
{
int cipherTextSize = cipherText.Length;
cipherBlob.pbData = Marshal.AllocHGlobal(cipherTextSize);
if(IntPtr.Zero == cipherBlob.pbData)
{
throw new Exception("Unable to allocate cipherText buffer.");
}
cipherBlob.cbData = cipherTextSize;
Marshal.Copy(cipherText, 0, cipherBlob.pbData, cipherBlob.cbData);
}
catch(Exception ex)
{
throw new Exception("Exception marshalling data. " + ex.Message);
}
DATA_BLOB entropyBlob = new DATA_BLOB();
int dwFlags;
if(Store.USE_MACHINE_STORE == store)
{//Using the machine store, should be providing entropy.
dwFlags = CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
//Check to see if the entropy is null
if(null == optionalEntropy)
{//Allocate something
optionalEntropy = new byte[0];
}
try
{
int bytesSize = optionalEntropy.Length;
entropyBlob.pbData = Marshal.AllocHGlobal(bytesSize);
if(IntPtr.Zero == entropyBlob.pbData)
{
throw new Exception("Unable to allocate entropy buffer.");
}
entropyBlob.cbData = bytesSize;
Marshal.Copy(optionalEntropy, 0, entropyBlob.pbData, bytesSize);
}
catch(Exception ex)
{
throw new Exception("Exception entropy marshalling data. " +
ex.Message);
}
}
else
{//Using the user store
dwFlags = CRYPTPROTECT_UI_FORBIDDEN;
}
retVal = CryptUnprotectData(ref cipherBlob, null, ref entropyBlob,
IntPtr.Zero, ref prompt, dwFlags,
ref plainTextBlob);
if(false == retVal)
{
throw new Exception("Decryption failed. " +
GetErrorMessage(Marshal.GetLastWin32Error()));
}
//Free the blob and entropy.
if(IntPtr.Zero != cipherBlob.pbData)
{
Marshal.FreeHGlobal(cipherBlob.pbData);
}
if(IntPtr.Zero != entropyBlob.pbData)
{
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}
catch(Exception ex)
{
throw new Exception("Exception decrypting. " + ex.Message);
}
byte[] plainText = new byte[plainTextBlob.cbData];
Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainTextBlob.cbData);
return plainText;
}
private void InitPromptstruct(ref CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}
private unsafe static String GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = new IntPtr();
IntPtr prtArguments = new IntPtr();
int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0,
ref lpMsgBuf, messageSize, &prtArguments);
if(0 == retVal)
{
throw new Exception("Failed to format message for error code " +
errorCode + ". ");
}
return lpMsgBuf;
}
}
}
using System.Text;
using System.Runtime.InteropServices;
namespace DataProtection
{
/// <summary>
/// Summary description for DataProtector.
/// </summary>
public class DataProtector
{
[DllImport("Crypt32.dll", SetLastError=true,CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool CryptProtectData(ref DATA_BLOB pDataIn,
String szDataDescr,
ref DATA_BLOB pOptionalEntropy,
IntPtr pvReserved,
ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct,
int dwFlags,
ref DATA_BLOB pDataOut);
[DllImport("Crypt32.dll", SetLastError=true,
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private static extern bool CryptUnprotectData(ref DATA_BLOB pDataIn,
String szDataDescr,
ref DATA_BLOB pOptionalEntropy,
IntPtr pvReserved,
ref CRYPTPROTECT_PROMPTSTRUCT pPromptStruct,
int dwFlags,
ref DATA_BLOB pDataOut);
[DllImport("kernel32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags,
ref IntPtr lpSource,
int dwMessageId,
int dwLanguageId,
ref String lpBuffer, int nSize,
IntPtr *Arguments);
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
internal struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public String szPrompt;
}
static private IntPtr NullPtr = ((IntPtr)((int)(0)));
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
public enum Store {USE_MACHINE_STORE = 1, USE_USER_STORE};
private Store store;
public DataProtector(Store tempStore)
{
store = tempStore;
}
public byte[] Encrypt(byte[] plainText, byte[] optionalEntropy)
{
bool retVal = false;
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPromptstruct(ref prompt);
int dwFlags;
try
{
try
{
int bytesSize = plainText.Length;
plainTextBlob.pbData = Marshal.AllocHGlobal(bytesSize);
if(IntPtr.Zero == plainTextBlob.pbData)
{
throw new Exception("Unable to allocate plaintext buffer.");
}
plainTextBlob.cbData = bytesSize;
Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize);
}
catch(Exception ex)
{
throw new Exception("Exception marshalling data. " + ex.Message);
}
if(Store.USE_MACHINE_STORE == store)
{//Using the machine store, should be providing entropy.
dwFlags = CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
//Check to see if the entropy is null
if(null == optionalEntropy)
{//Allocate something
optionalEntropy = new byte[0];
}
try
{
int bytesSize = optionalEntropy.Length;
entropyBlob.pbData = Marshal.AllocHGlobal(optionalEntropy.Length);;
if(IntPtr.Zero == entropyBlob.pbData)
{
throw new Exception("Unable to allocate entropy data buffer.");
}
Marshal.Copy(optionalEntropy, 0, entropyBlob.pbData, bytesSize);
entropyBlob.cbData = bytesSize;
}
catch(Exception ex)
{
throw new Exception("Exception entropy marshalling data. " +
ex.Message);
}
}
else
{//Using the user store
dwFlags = CRYPTPROTECT_UI_FORBIDDEN;
}
retVal = CryptProtectData(ref plainTextBlob, "", ref entropyBlob,
IntPtr.Zero, ref prompt, dwFlags,
ref cipherTextBlob);
if(false == retVal)
{
throw new Exception("Encryption failed. " +
GetErrorMessage(Marshal.GetLastWin32Error()));
}
}
catch(Exception ex)
{
throw new Exception("Exception encrypting. " + ex.Message);
}
byte[] cipherText = new byte[cipherTextBlob.cbData];
Marshal.Copy(cipherTextBlob.pbData, cipherText, 0, cipherTextBlob.cbData);
return cipherText;
}
public byte[] Decrypt(byte[] cipherText, byte[] optionalEntropy)
{
bool retVal = false;
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPromptstruct(ref prompt);
try
{
try
{
int cipherTextSize = cipherText.Length;
cipherBlob.pbData = Marshal.AllocHGlobal(cipherTextSize);
if(IntPtr.Zero == cipherBlob.pbData)
{
throw new Exception("Unable to allocate cipherText buffer.");
}
cipherBlob.cbData = cipherTextSize;
Marshal.Copy(cipherText, 0, cipherBlob.pbData, cipherBlob.cbData);
}
catch(Exception ex)
{
throw new Exception("Exception marshalling data. " + ex.Message);
}
DATA_BLOB entropyBlob = new DATA_BLOB();
int dwFlags;
if(Store.USE_MACHINE_STORE == store)
{//Using the machine store, should be providing entropy.
dwFlags = CRYPTPROTECT_LOCAL_MACHINE|CRYPTPROTECT_UI_FORBIDDEN;
//Check to see if the entropy is null
if(null == optionalEntropy)
{//Allocate something
optionalEntropy = new byte[0];
}
try
{
int bytesSize = optionalEntropy.Length;
entropyBlob.pbData = Marshal.AllocHGlobal(bytesSize);
if(IntPtr.Zero == entropyBlob.pbData)
{
throw new Exception("Unable to allocate entropy buffer.");
}
entropyBlob.cbData = bytesSize;
Marshal.Copy(optionalEntropy, 0, entropyBlob.pbData, bytesSize);
}
catch(Exception ex)
{
throw new Exception("Exception entropy marshalling data. " +
ex.Message);
}
}
else
{//Using the user store
dwFlags = CRYPTPROTECT_UI_FORBIDDEN;
}
retVal = CryptUnprotectData(ref cipherBlob, null, ref entropyBlob,
IntPtr.Zero, ref prompt, dwFlags,
ref plainTextBlob);
if(false == retVal)
{
throw new Exception("Decryption failed. " +
GetErrorMessage(Marshal.GetLastWin32Error()));
}
//Free the blob and entropy.
if(IntPtr.Zero != cipherBlob.pbData)
{
Marshal.FreeHGlobal(cipherBlob.pbData);
}
if(IntPtr.Zero != entropyBlob.pbData)
{
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}
catch(Exception ex)
{
throw new Exception("Exception decrypting. " + ex.Message);
}
byte[] plainText = new byte[plainTextBlob.cbData];
Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainTextBlob.cbData);
return plainText;
}
private void InitPromptstruct(ref CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}
private unsafe static String GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;
int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
IntPtr ptrlpSource = new IntPtr();
IntPtr prtArguments = new IntPtr();
int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0,
ref lpMsgBuf, messageSize, &prtArguments);
if(0 == retVal)
{
throw new Exception("Failed to format message for error code " +
errorCode + ". ");
}
return lpMsgBuf;
}
}
}
VB.NET Code
Imports System
Imports System.Text
Imports System.Runtime.InteropServices
Namespace DataProtectionVB
Public Enum Store
MachineStore = 1
UserStore
End Enum
#Region " Custom Exception"
Public Class DataProtectionException
Inherits Exception
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal message As String)
MyBase.New(message)
End Sub
Public Sub New(ByVal message As String, ByVal innerException As Exception)
MyBase.New(message, innerException)
End Sub
End Class
#End Region
Public Class DataProtector
#Region " Dll Imports"
Private Declare Auto Function CryptProtectData Lib "Crypt32.dll" ( _
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
Private Declare Auto Function CryptUnprotectData Lib "Crypt32.dll" ( _
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
Private Declare Auto Function FormatMessage Lib "kernel32.dll" ( _
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 Region
#Region " Structure definistions and constraints "
Friend Structure DATA_BLOB
Public cbData As Integer
Public pbData As IntPtr
End Structure
Friend Structure CRYPTPROTECT_PROMPTSTRUCT
Public cbSize As Integer
Public dwPromptFlags As Integer
Public hwndApp As IntPtr
Public szPrompt As String
End Structure
Private Const CRYPTOPROTECT_UI_FORBIDDEN = &H1
Private Const CRYPTPROTECT_LOCAL_MACHINE = &H4
#End Region
#Region " Constructors "
Private _store As Store
Public Sub New(ByVal store As Store)
_store = store
End Sub
#End Region
#Region " Encrypt and Decrypt "
Public Function Encrypt(ByVal plainText As Byte()) As Byte()
Dim entropy(0) As Byte
Return Encrypt(plainText, entropy)
End Function
Public Function Encrypt(ByVal plainText As Byte(), _
ByVal entropyText As Byte()) As Byte()
Dim retVal As Boolean = False
Dim plainTextBlob As New DATA_BLOB
Dim cipherTextBlob As New DATA_BLOB
Dim entropyBlob As New DATA_BLOB
Dim prompt As New CRYPTPROTECT_PROMPTSTRUCT
InitProptstruct(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 OutOfMemoryException( _
"Unable to allocate memory for buffer.")
End If
plainTextBlob.cbData = bytesSize
Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize)
Catch ex As Exception
Throw New Exception("Exception marshalling data.", ex)
End Try
If _store = Store.MachineStore Then
dwFlags = CRYPTPROTECT_LOCAL_MACHINE Or CRYPTOPROTECT_UI_FORBIDDEN
Try
Dim bytesSize = entropyText.Length
entropyBlob.pbData = Marshal.AllocHGlobal(bytesSize)
If entropyBlob.pbData.Equals(IntPtr.Zero) Then
Throw New OutOfMemoryException( _
"Unable to allocate entropy data buffer.")
End If
Marshal.Copy(entropyText, 0, entropyBlob.pbData, bytesSize)
entropyBlob.cbData = bytesSize
Catch ex As Exception
Throw New Exception("Exception marshalling data.", ex)
End Try
Else
dwFlags = CRYPTOPROTECT_UI_FORBIDDEN
End If
retVal = CryptProtectData(plainTextBlob, String.Empty, entropyBlob, _
IntPtr.Zero, prompt, dwFlags, cipherTextBlob)
If retVal = False Then
Throw New DataProtectionException( _
"Encryption failed. " & GetErrorMessage(Marshal.GetLastWin32Error))
End If
Catch ex As Exception
Throw New Exception("Exception encrypting.", ex)
End Try
Dim cipherText(cipherTextBlob.cbData) As Byte
Marshal.Copy(cipherTextBlob.pbData, cipherText, 0, cipherTextBlob.cbData)
Return cipherText
End Function
Public Function Decrypt(ByVal cipherText As Byte()) As Byte()
Dim entropy(0) As Byte
Return Decrypt(cipherText, entropy)
End Function
Public Function Decrypt(ByVal cipherText As Byte(), _
ByVal entropyText As Byte()) As Byte()
Dim retVal As Boolean
Dim plainTextBlob As New DATA_BLOB
Dim cipherBlob As New DATA_BLOB
Dim prompt As New CRYPTPROTECT_PROMPTSTRUCT
InitProptstruct(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)
End Try
Dim entropyBlob As New DATA_BLOB
Dim dwFlags As Integer
If _store = Store.MachineStore Then
dwFlags = CRYPTPROTECT_LOCAL_MACHINE Or CRYPTOPROTECT_UI_FORBIDDEN
Try
Dim byteSize As Integer = entropyText.Length
entropyBlob.pbData = Marshal.AllocHGlobal(byteSize)
If entropyBlob.pbData.Equals(IntPtr.Zero) Then
Throw New OutOfMemoryException( _
"Unable to allocate entropy buffer.")
End If
entropyBlob.cbData = byteSize
Marshal.Copy(entropyText, 0, entropyBlob.pbData, byteSize)
Catch ex As Exception
Throw New Exception("Exception entropy marshalling data.", ex)
End Try
Else
dwFlags = CRYPTOPROTECT_UI_FORBIDDEN
End If
retVal = CryptUnprotectData(cipherBlob, String.Empty, _
entropyBlob, IntPtr.Zero, _
prompt, dwFlags, plainTextBlob)
If retVal = False Then
Throw New DataProtectionException( _
"Decryption failed. " & GetErrorMessage(Marshal.GetLastWin32Error))
End If
If Not cipherBlob.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)
End Try
Dim plainText(plainTextBlob.cbData) As Byte
Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainTextBlob.cbData)
Return plainText
End Function
#End Region
#Region " Helper Functions "
Private Sub InitProptstruct(ByRef ps As CRYPTPROTECT_PROMPTSTRUCT)
ps.cbSize = Marshal.SizeOf(ps.GetType)
ps.dwPromptFlags = 0
ps.hwndApp = IntPtr.Zero
ps.szPrompt = String.Empty
End Sub
Private 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_IGNORE_INSERTS _
Or FORMAT_MESSAGE_FROM_SYSTEM
Dim ptrlpSource As New IntPtr
Dim prtArguments As New IntPtr
Dim retVal = 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
End Class
End Namespace
Imports System.Text
Imports System.Runtime.InteropServices
Namespace DataProtectionVB
Public Enum Store
MachineStore = 1
UserStore
End Enum
#Region " Custom Exception"
Public Class DataProtectionException
Inherits Exception
Public Sub New()
MyBase.New()
End Sub
Public Sub New(ByVal message As String)
MyBase.New(message)
End Sub
Public Sub New(ByVal message As String, ByVal innerException As Exception)
MyBase.New(message, innerException)
End Sub
End Class
#End Region
Public Class DataProtector
#Region " Dll Imports"
Private Declare Auto Function CryptProtectData Lib "Crypt32.dll" ( _
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
Private Declare Auto Function CryptUnprotectData Lib "Crypt32.dll" ( _
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
Private Declare Auto Function FormatMessage Lib "kernel32.dll" ( _
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 Region
#Region " Structure definistions and constraints "
Friend Structure DATA_BLOB
Public cbData As Integer
Public pbData As IntPtr
End Structure
Friend Structure CRYPTPROTECT_PROMPTSTRUCT
Public cbSize As Integer
Public dwPromptFlags As Integer
Public hwndApp As IntPtr
Public szPrompt As String
End Structure
Private Const CRYPTOPROTECT_UI_FORBIDDEN = &H1
Private Const CRYPTPROTECT_LOCAL_MACHINE = &H4
#End Region
#Region " Constructors "
Private _store As Store
Public Sub New(ByVal store As Store)
_store = store
End Sub
#End Region
#Region " Encrypt and Decrypt "
Public Function Encrypt(ByVal plainText As Byte()) As Byte()
Dim entropy(0) As Byte
Return Encrypt(plainText, entropy)
End Function
Public Function Encrypt(ByVal plainText As Byte(), _
ByVal entropyText As Byte()) As Byte()
Dim retVal As Boolean = False
Dim plainTextBlob As New DATA_BLOB
Dim cipherTextBlob As New DATA_BLOB
Dim entropyBlob As New DATA_BLOB
Dim prompt As New CRYPTPROTECT_PROMPTSTRUCT
InitProptstruct(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 OutOfMemoryException( _
"Unable to allocate memory for buffer.")
End If
plainTextBlob.cbData = bytesSize
Marshal.Copy(plainText, 0, plainTextBlob.pbData, bytesSize)
Catch ex As Exception
Throw New Exception("Exception marshalling data.", ex)
End Try
If _store = Store.MachineStore Then
dwFlags = CRYPTPROTECT_LOCAL_MACHINE Or CRYPTOPROTECT_UI_FORBIDDEN
Try
Dim bytesSize = entropyText.Length
entropyBlob.pbData = Marshal.AllocHGlobal(bytesSize)
If entropyBlob.pbData.Equals(IntPtr.Zero) Then
Throw New OutOfMemoryException( _
"Unable to allocate entropy data buffer.")
End If
Marshal.Copy(entropyText, 0, entropyBlob.pbData, bytesSize)
entropyBlob.cbData = bytesSize
Catch ex As Exception
Throw New Exception("Exception marshalling data.", ex)
End Try
Else
dwFlags = CRYPTOPROTECT_UI_FORBIDDEN
End If
retVal = CryptProtectData(plainTextBlob, String.Empty, entropyBlob, _
IntPtr.Zero, prompt, dwFlags, cipherTextBlob)
If retVal = False Then
Throw New DataProtectionException( _
"Encryption failed. " & GetErrorMessage(Marshal.GetLastWin32Error))
End If
Catch ex As Exception
Throw New Exception("Exception encrypting.", ex)
End Try
Dim cipherText(cipherTextBlob.cbData) As Byte
Marshal.Copy(cipherTextBlob.pbData, cipherText, 0, cipherTextBlob.cbData)
Return cipherText
End Function
Public Function Decrypt(ByVal cipherText As Byte()) As Byte()
Dim entropy(0) As Byte
Return Decrypt(cipherText, entropy)
End Function
Public Function Decrypt(ByVal cipherText As Byte(), _
ByVal entropyText As Byte()) As Byte()
Dim retVal As Boolean
Dim plainTextBlob As New DATA_BLOB
Dim cipherBlob As New DATA_BLOB
Dim prompt As New CRYPTPROTECT_PROMPTSTRUCT
InitProptstruct(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)
End Try
Dim entropyBlob As New DATA_BLOB
Dim dwFlags As Integer
If _store = Store.MachineStore Then
dwFlags = CRYPTPROTECT_LOCAL_MACHINE Or CRYPTOPROTECT_UI_FORBIDDEN
Try
Dim byteSize As Integer = entropyText.Length
entropyBlob.pbData = Marshal.AllocHGlobal(byteSize)
If entropyBlob.pbData.Equals(IntPtr.Zero) Then
Throw New OutOfMemoryException( _
"Unable to allocate entropy buffer.")
End If
entropyBlob.cbData = byteSize
Marshal.Copy(entropyText, 0, entropyBlob.pbData, byteSize)
Catch ex As Exception
Throw New Exception("Exception entropy marshalling data.", ex)
End Try
Else
dwFlags = CRYPTOPROTECT_UI_FORBIDDEN
End If
retVal = CryptUnprotectData(cipherBlob, String.Empty, _
entropyBlob, IntPtr.Zero, _
prompt, dwFlags, plainTextBlob)
If retVal = False Then
Throw New DataProtectionException( _
"Decryption failed. " & GetErrorMessage(Marshal.GetLastWin32Error))
End If
If Not cipherBlob.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)
End Try
Dim plainText(plainTextBlob.cbData) As Byte
Marshal.Copy(plainTextBlob.pbData, plainText, 0, plainTextBlob.cbData)
Return plainText
End Function
#End Region
#Region " Helper Functions "
Private Sub InitProptstruct(ByRef ps As CRYPTPROTECT_PROMPTSTRUCT)
ps.cbSize = Marshal.SizeOf(ps.GetType)
ps.dwPromptFlags = 0
ps.hwndApp = IntPtr.Zero
ps.szPrompt = String.Empty
End Sub
Private 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_IGNORE_INSERTS _
Or FORMAT_MESSAGE_FROM_SYSTEM
Dim ptrlpSource As New IntPtr
Dim prtArguments As New IntPtr
Dim retVal = 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
End Class
End Namespace