DPAPI

Posted on 2005-01-17 22:39  TonyChen  阅读(2270)  评论(0编辑  收藏  举报

    DPAPI特别有用,因为它能够消除使用密码的应用程序所带来的密钥管理问题。虽然加密能确保数据安全,但您必须采取额外的步骤来确保密钥的安全。 DPAPI 使用与 DPAPI 函数的调用代码关联的用户帐户的密码,以便派生加密密钥。因此,是操作系统(而非应用程序)管理着密钥。
    DPAPI能够与计算机存储或用户存储(需要一个已加载的用户配置文件)配合使用。DPAPI 默认情况下用于用户存储,但您可以通过将 CRYPTPROTECT_LOCAL_MACHINE 标志传递给 DPAPI 函数来指定使用计算机存储。
    这种用户配置文件方式提供了一个额外的安全层,因为它限制了哪些用户能访问机密内容。只有加密该数据的用户才能解密该数据。但是,当通过 ASP.NET Web 应用程序使用 DPAPI 时,使用用户配置文件需要您执行额外的开发工作,因为您需要采取明确的步骤来加载和卸载用户配置文件(ASP.NET 不会自动加载用户配置文件)。
    计算机存储方式更容易开发,因为它不需要管理用户配置文件。但是,除非使用一个附加的熵参数,否则并不安全,因为该计算机的任何用户都可以解密数据。(熵是一个设计用来使解密机密内容更为困难的随机值)。使用附加的熵参数出现的问题在于它必须由应用程序安全地存储起来,这带来了另一个密钥管理问题。

注意:

    如果您将 DPAPI 和计算机存储一起使用,那么加密字符串仅适用于给定的计算机,因此您必须在每台计算机上生成加密数据。不要在场或群集中将加密数据从一台计算机复制到另一台计算机。
    如果将 DPAPI 和用户存储一起使用,则可以用一个漫游的用户配置文件在任何一台计算机上解密数据。
    DPAPI只在2k以上的系统上才有,win9x系列就不要想了.

下面的演示如何调用DPAPI(DataProtection类,来自于MS的IssueVision)

// Uses the Data Protection API (DPAPI) to encrypt and decrypt secrets
// based on the logged in user or local machine. 

using System;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;


namespace ConsoleApplication
{
    
/// <summary>
    
/// Class1 的摘要说明。
    
/// </summary>

    class Class1
    
{
        
/// <summary>
        
/// 应用程序的主入口点。
        
/// </summary>

        [STAThread]
        
static void Main(string[] args)
        
{
            
//
            
// TODO: 在此处添加代码以启动应用程序
            
//
            string strSource, strEncrypt, strDecrypt;
            
            Console.WriteLine(
"请输入一个字符串,按回车结束:");
            strSource 
= Console.ReadLine();
            
            Console.WriteLine(
"以下为使用DPAPI加密得到的密码:");
            strEncrypt 
= DataProtection.Encrypt(strSource, DataProtection.Store.Machine);
            Console.WriteLine(strEncrypt);

            Console.WriteLine(
"以下为使用DPAPI解密得到的字符串:");
            strDecrypt 
= DataProtection.Decrypt(strEncrypt, DataProtection.Store.Machine);
            Console.WriteLine(strDecrypt);

            Console.WriteLine(
"按回车结束。。。");
            Console.ReadLine();
            
        }

    }



    
public sealed class DataProtection 
    
{
        
// use local machine or user to encrypt and decrypt the data
        public enum Store
        
{
            Machine,
            User
        }


        
// const values
        private class Consts 
        
{
            
// specify an entropy so other DPAPI applications can't see the data
            public readonly static byte[] EntropyData = ASCIIEncoding.ASCII.GetBytes("B0D125B7-967E-4f94-9305-A6F9AF56A19A");
        }


        
// static class
        private DataProtection()
        
{
        }


        
// public methods

        
// encrypt the data using DPAPI, returns a base64-encoded encrypted string
        public static string Encrypt(string data, Store store)
        
{
            
// holds the result string
            string  result = "";

            
// blobs used in the CryptProtectData call
            Win32.DATA_BLOB inBlob = new Win32.DATA_BLOB();
            Win32.DATA_BLOB entropyBlob 
= new Win32.DATA_BLOB();
            Win32.DATA_BLOB outBlob 
= new Win32.DATA_BLOB();

            
try 
            
{
                
// setup flags passed to the CryptProtectData call
                int flags = Win32.CRYPTPROTECT_UI_FORBIDDEN | 
                    (
int)((store == Store.Machine) ? Win32.CRYPTPROTECT_LOCAL_MACHINE : 0);

                
// setup input blobs, the data to be encrypted and entropy blob
                SetBlobData(ref inBlob, ASCIIEncoding.ASCII.GetBytes(data));
                SetBlobData(
ref entropyBlob, Consts.EntropyData);

                
// call the DPAPI function, returns true if successful and fills in the outBlob
                if (Win32.CryptProtectData(ref inBlob, ""ref entropyBlob, IntPtr.Zero, IntPtr.Zero, flags, ref outBlob)) 
                
{
                    
byte[] resultBits = GetBlobData(ref outBlob);
                    
if (resultBits != null
                        result 
= Convert.ToBase64String(resultBits);
                }

            }

            
catch
            
{
                
// an error occurred, return an empty string
            }

            
finally 
            
{
                
// clean up
                if (inBlob.pbData.ToInt32() != 0
                    Marshal.FreeHGlobal(inBlob.pbData);

                
if (entropyBlob.pbData.ToInt32() != 0
                    Marshal.FreeHGlobal(entropyBlob.pbData);
            }


            
return result;
        }


        
// decrypt the data using DPAPI, data is a base64-encoded encrypted string
        public static string Decrypt( string  data,  Store store) 
        
{
            
// holds the result string
            string result = "";

            
// blobs used in the CryptUnprotectData call
            Win32.DATA_BLOB inBlob = new Win32.DATA_BLOB();
            Win32.DATA_BLOB entropyBlob 
= new Win32.DATA_BLOB();
            Win32.DATA_BLOB outBlob 
= new Win32.DATA_BLOB();

            
try 
            
{
                
// setup flags passed to the CryptUnprotectData call
                int flags = Win32.CRYPTPROTECT_UI_FORBIDDEN |
                    (
int)((store == Store.Machine) ? Win32.CRYPTPROTECT_LOCAL_MACHINE : 0);

                
// the CryptUnprotectData works with a byte array, convert string data
                byte[] bits = Convert.FromBase64String(data);

                
// setup input blobs, the data to be decrypted and entropy blob
                SetBlobData(ref inBlob, bits);
                SetBlobData(
ref entropyBlob, Consts.EntropyData);

                
// call the DPAPI function, returns true if successful and fills in the outBlob
                if (Win32.CryptUnprotectData(ref inBlob, nullref entropyBlob, IntPtr.Zero, IntPtr.Zero, flags, ref outBlob)) 
                
{
                    
byte[] resultBits = GetBlobData(ref outBlob);
                    
if (resultBits != null
                        result 
= ASCIIEncoding.ASCII.GetString(resultBits);
                }

            }

            
catch 
            
{
                
// an error occurred, return an empty string
            }

            
finally 
            
{
                
// clean up
                if (inBlob.pbData.ToInt32() != 0
                    Marshal.FreeHGlobal(inBlob.pbData);
        
                
if (entropyBlob.pbData.ToInt32() != 0
                    Marshal.FreeHGlobal(entropyBlob.pbData);
            }


            
return result;
        }



        
// internal methods

        
Data Protection API

        
// helper method that fills in a DATA_BLOB, copies 
        
// data from managed to unmanaged memory
        private static void SetBlobData(ref Win32.DATA_BLOB blob,  byte[] bits) 
        
{
            blob.cbData 
= bits.Length;
            blob.pbData 
= Marshal.AllocHGlobal(bits.Length);
            Marshal.Copy(bits, 
0, blob.pbData, bits.Length);
        }


        
// helper method that gets data from a DATA_BLOB, 
        
// copies data from unmanaged memory to managed
        private static byte[] GetBlobData(ref Win32.DATA_BLOB blob) 
        
{
            
// return an empty string if the blob is empty
            if (blob.pbData.ToInt32() == 0
                
return null;

            
// copy information from the blob
            byte[] data = new byte[blob.cbData];
            Marshal.Copy(blob.pbData, data, 
0, blob.cbData);
            Win32.LocalFree(blob.pbData);

            
return data;
        }

    }



}



Copyright © 2024 TonyChen
Powered by .NET 8.0 on Kubernetes