// <summary>
/// Window自带加密解密DPAPI
/// </summary>
public class DPAPI
{
#region
/// <summary>
/// DPAPI加密
/// </summary>
/// <param name="pPlainText"></param>
/// <param name="szDescription"></param>
/// <param name="pEntropy"></param>
/// <param name="pReserved"></param>
/// <param name="pPrompt"></param>
/// <param name="dwFlags"></param>
/// <param name="pCipherText"></param>
/// <returns></returns>
[DllImport("crypt32.dll", EntryPoint = "CryptProtectData", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern bool DPAPIEncrypt(ref DATA_BLOB pPlainText, string szDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pCipherText);
/// <summary>
/// DPAPI解密
/// </summary>
/// <param name="pCipherText"></param>
/// <param name="pszDescription"></param>
/// <param name="pEntropy"></param>
/// <param name="pReserved"></param>
/// <param name="pPrompt"></param>
/// <param name="dwFlags"></param>
/// <param name="pPlainText"></param>
/// <returns></returns>
[DllImport("crypt32.dll", EntryPoint = "CryptUnprotectData", SetLastError = true, CharSet = System.Runtime.InteropServices.CharSet.Auto)]
public static extern bool DPAPIDecrypt(ref DATA_BLOB pCipherText, ref string pszDescription, ref DATA_BLOB pEntropy, IntPtr pReserved, ref CRYPTPROTECT_PROMPTSTRUCT pPrompt, int dwFlags, ref DATA_BLOB pPlainText);
#endregion
#region
/// <summary>
/// 密钥类型
/// </summary>
public enum KeyType
{
/// <summary>
/// 用户存储
/// </summary>
UserKey = 1,
/// <summary>
/// 机器存储
/// </summary>
MachineKey
};
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct DATA_BLOB
{
public int cbData;
public IntPtr pbData;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct CRYPTPROTECT_PROMPTSTRUCT
{
public int cbSize;
public int dwPromptFlags;
public IntPtr hwndApp;
public string szPrompt;
}
private static IntPtr NullPtr = ((IntPtr)((int)(0)));
private static KeyType defaultKeyType = KeyType.UserKey;
private const int CRYPTPROTECT_UI_FORBIDDEN = 0x1;
private const int CRYPTPROTECT_LOCAL_MACHINE = 0x4;
#endregion
private static void InitPrompt(ref CRYPTPROTECT_PROMPTSTRUCT ps)
{
ps.cbSize = Marshal.SizeOf(typeof(CRYPTPROTECT_PROMPTSTRUCT));
ps.dwPromptFlags = 0;
ps.hwndApp = NullPtr;
ps.szPrompt = null;
}
private static void InitBLOB(byte[] data, ref DATA_BLOB blob)
{
blob.pbData = Marshal.AllocHGlobal(data.Length);
if (blob.pbData == IntPtr.Zero)
throw new Exception("无法为BLOB结构分配数据缓冲区");
blob.cbData = data.Length;
Marshal.Copy(data, 0, blob.pbData, data.Length);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="plainText">要加密明文</param>
/// <returns></returns>
public static string Encrypt(string plainText)
{
return Encrypt(defaultKeyType, plainText, String.Empty, String.Empty);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="keyType">密钥类型</param>
/// <param name="plainText">要加密明文</param>
/// <returns></returns>
public static string Encrypt(KeyType keyType, string plainText)
{
return Encrypt(keyType, plainText, String.Empty, String.Empty);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="keyType">密钥类型</param>
/// <param name="plainText">要加密明文</param>
/// <param name="entropy"></param>
/// <returns></returns>
public static string Encrypt(KeyType keyType, string plainText, string entropy)
{
return Encrypt(keyType, plainText, entropy, String.Empty);
}
/// <summary>
/// 加密
/// </summary>
/// <param name="keyType">密钥类型</param>
/// <param name="plainText">要加密明文</param>
/// <param name="entropy"></param>
/// <param name="description"></param>
/// <returns></returns>
public static string Encrypt(KeyType keyType, string plainText, string entropy, string description)
{
if (plainText == null)
plainText = String.Empty;
if (entropy == null)
entropy = String.Empty;
return Convert.ToBase64String(Encrypt(keyType, Encoding.UTF8.GetBytes(plainText), Encoding.UTF8.GetBytes(entropy), description));
}
/// <summary>
/// 加密
/// </summary>
/// <param name="keyType">密钥类型</param>
/// <param name="plainTextBytes">要加密明文</param>
/// <param name="entropyBytes"></param>
/// <param name="description"></param>
/// <returns></returns>
public static byte[] Encrypt(KeyType keyType, byte[] plainTextBytes, byte[] entropyBytes, string description)
{
if (plainTextBytes == null)
plainTextBytes = new byte[0];
if (entropyBytes == null)
entropyBytes = new byte[0];
if (description == null)
description = String.Empty;
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPrompt(ref prompt);
try
{
try
{
InitBLOB(plainTextBytes, ref plainTextBlob);//将明文字节转换为BLOB结构。
}
catch (Exception ex)
{
throw new Exception("无法初始化纯文本BLOB", ex);
}
try
{
InitBLOB(entropyBytes, ref entropyBlob);//将熵字节转换为BLOB结构
}
catch (Exception ex)
{
throw new Exception("无法初始化熵BLOB。", ex);
}
int flags = CRYPTPROTECT_UI_FORBIDDEN;
if (keyType == KeyType.MachineKey)
flags |= CRYPTPROTECT_LOCAL_MACHINE;
bool success = DPAPIEncrypt(ref plainTextBlob, description, ref entropyBlob, IntPtr.Zero, ref prompt, flags, ref cipherTextBlob);
if (!success)
{
throw new Exception("CryptProtectData失败", new Win32Exception(Marshal.GetLastWin32Error()));
}
byte[] cipherTextBytes = new byte[cipherTextBlob.cbData];
Marshal.Copy(cipherTextBlob.pbData, cipherTextBytes, 0, cipherTextBlob.cbData);
return cipherTextBytes;
}
catch (Exception ex)
{
throw new Exception("DPAPI无法加密数据", ex);
}
finally
{
if (plainTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(plainTextBlob.pbData);
if (cipherTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(cipherTextBlob.pbData);
if (entropyBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cipherText">要解密的密文</param>
/// <returns></returns>
public static string Decrypt(string cipherText)
{
string description;
return Decrypt(cipherText, String.Empty, out description);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cipherText">要解密的密文</param>
/// <param name="description"></param>
/// <returns></returns>
public static string Decrypt(string cipherText, out string description)
{
return Decrypt(cipherText, String.Empty, out description);
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cipherText">要解密的密文</param>
/// <param name="entropy"></param>
/// <param name="description"></param>
/// <returns></returns>
public static string Decrypt(string cipherText, string entropy, out string description)
{
if (entropy == null)
entropy = String.Empty;
return Encoding.UTF8.GetString(Decrypt(Convert.FromBase64String(cipherText), Encoding.UTF8.GetBytes(entropy), out description));
}
/// <summary>
/// 解密
/// </summary>
/// <param name="cipherTextBytes">要解密的密文</param>
/// <param name="entropyBytes"></param>
/// <param name="description"></param>
/// <returns></returns>
public static byte[] Decrypt(byte[] cipherTextBytes, byte[] entropyBytes, out string description)
{
DATA_BLOB plainTextBlob = new DATA_BLOB();
DATA_BLOB cipherTextBlob = new DATA_BLOB();
DATA_BLOB entropyBlob = new DATA_BLOB();
CRYPTPROTECT_PROMPTSTRUCT prompt = new CRYPTPROTECT_PROMPTSTRUCT();
InitPrompt(ref prompt);
description = String.Empty;
try
{
try
{
InitBLOB(cipherTextBytes, ref cipherTextBlob);
}
catch (Exception ex)
{
throw new Exception("无法初始化密文BLOB", ex);
}
try
{
InitBLOB(entropyBytes, ref entropyBlob);
}
catch (Exception ex)
{
throw new Exception("无法初始化熵BLOB", ex);
}
int flags = CRYPTPROTECT_UI_FORBIDDEN;
bool success = DPAPIDecrypt(ref cipherTextBlob, ref description, ref entropyBlob, IntPtr.Zero, ref prompt, flags, ref plainTextBlob);
if (!success)
{
throw new Exception("CryptUnprotectData失败", new Win32Exception(Marshal.GetLastWin32Error()));
}
byte[] plainTextBytes = new byte[plainTextBlob.cbData];
Marshal.Copy(plainTextBlob.pbData, plainTextBytes, 0, plainTextBlob.cbData);
return plainTextBytes;
}
catch (Exception ex)
{
throw new Exception("DPAPI无法解密数据", ex);
}
finally
{
if (plainTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(plainTextBlob.pbData);
if (cipherTextBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(cipherTextBlob.pbData);
if (entropyBlob.pbData != IntPtr.Zero)
Marshal.FreeHGlobal(entropyBlob.pbData);
}
}
}