玄铁剑

成功的途径:抄,创造,研究,发明...
posts - 128, comments - 42, trackbacks - 0, articles - 174

创建自定义加密权限

Posted on 2008-12-09 21:35 玄铁剑 阅读(424) 评论(0)  编辑 收藏 引用 所属分类: ASP.NET相关

Microsoft Corporation

目标

使用本单元以:

  • 开发、实现并使用自定义 CAS 权限。

  • 使用自定义代码访问权限来控制到由 DPAPI 提供的非托管加密功能的访问。

适用于

本单元适用于下列产品和技术:

  • Microsoft® Windows® 2000 Server 和 Windows 2000 Professional、Windows Server™ 2003、Windows XP Professional 操作系统

  • Internet Information Server (IIS)

  • Microsoft .NET Framework 1.1

如何使用本单元

要从本单元受益最多:

  • 您必须具备使用 Visual C# .NET 和 Visual Studio .NET 进行编程的经验。

  • 请阅读“如何创建 DPAPI 库”。该单元演示了如何创建本单元所用的托管 DPAPI 包装程序集。

本页内容

摘要 摘要
须知 须知
创建 EncryptionPermission 类 创建 EncryptionPermission 类
创建 EncryptionPermissionAttribute 类 创建 EncryptionPermissionAttribute 类
在 GAC 中安装权限程序集 在 GAC 中安装权限程序集
更新 DPAPI 托管包装代码 更新 DPAPI 托管包装代码
从中等信任的 Web 应用程序调用 DPAPI 从中等信任的 Web 应用程序调用 DPAPI

摘要

.NET Framework 的代码访问安全性 (CAS) 功能可扩展。这使您能够实现自己的权限以控制到重要自定义功能的访问。

本单元主要说明如何创建自定义 CAS 权限以控制到托管数据保护 API (DPAPI) 包装代码的编程访问。该代码在以下站点的 MSDN 库文章“如何:创建 DPAPI 库”中进行阐述:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnnetsec/html/SecNetHT07.asp。

须知

代码访问安全性权限必须源自 System.Security.CodeAccessPermission,它可实现由 IPermission 接口定义的 Demand 方法,同时还可实现其他方法,如 IStackWalk 接口定义的 Assert、Deny 以及 PermitOnly 。

代码访问权限(不是身份权限)还可实现 IUnrestrictedPermission 接口,以指示该权限是不受限制的权限集的一部分。这意味着该权限会被自动授予任何具有完全信任的代码。本单元中使用的自定义 EncryptionPermission 的继承层次结构如图 1 所示。

fh15secmod01

图 1. 自定义 EncryptionPermission 继承层次结构

自定义 EncryptionPermission 类维护以下状态:

  • EncryptionPermissionFlag。确定被授予该权限的代码能够加密数据还是解密数据,或二者均可。

  • StorePermissionFlag。确定被授予该权限的代码能够通过机器存储还是当前用户存储使用 DPAPI,或二者均可。

创建 EncryptionPermission 类

EncryptionPermission 类是自定义权限实现,用于授权到非托管 DPAPI 功能的访问。

创建 CustomPermission 类

  1. 创建新的 Visual C#TM 开发工具“类库”项目 CustomPermission,并将 class1.cs 重命名为 EncryptionPermission.cs。

  2. 向该程序集添加强名称,以便可将其安装在 GAC 中。使用 assemblyinfo.cs 中的以下属性:

    [assembly: AssemblyKeyFile(@"..\..\CustomPermissions.snk")]
        
  3. 使用固定的程序集版本。

    [assembly: AssemblyVersion("1.0.0.1")]
        
  4. 将以下 using 语句添加到 EncryptionPermission.cs 顶端。

    using System.Security;
        using System.Security.Permissions;
        
  5. 将以下枚举类型添加到 CustomPermissions 命名空间。

    [Flags, Serializable]
        public enum EncryptionPermissionFlag
        {Encrypt = 0x01, Decrypt = 0x02}
        [Flags, Serializable]
        public enum StorePermissionFlag
        {User = 0x01, Machine = 0x02}
        
  6. 利用 [Serializable] 属性向 EncryptionPermission 类添加序列化支持,然后将其从 CodeAccessSecurity 和 IUnrestrictedPermission 导出。.并且,密封该类,如下所示。

    [Serializable]
        public sealed class EncryptionPermission : CodeAccessPermission,
        IUnrestrictedPermission
        
  7. 添加两个私有成员变量以维持权限状态。

    private EncryptionPermissionFlag _permFlag;
        private StorePermissionFlag _storePermFlag;
        
  8. 用以下构造函数替换默认的构造函数。

    // It is convention for permission types to provide a constructor
        // that accepts the PermissionState enumeration.
        public EncryptionPermission(PermissionState state)
        {
        if (state.Equals(PermissionState.Unrestricted))
        {
        _permFlag = EncryptionPermissionFlag.Encrypt |
        EncryptionPermissionFlag.Decrypt;
        _storePermFlag = StorePermissionFlag.User | StorePermissionFlag.Machine;
        }
        else
        {
        _permFlag &= ~(EncryptionPermissionFlag.Encrypt |
        EncryptionPermissionFlag.Decrypt);
        _storePermFlag &= ~(StorePermissionFlag.User |
        StorePermissionFlag.Machine);
        }
        }
        // This constructor allows you to specify the encryption type (encrypt
        // or decrypt) by using the EncryptionPermissionFlag enumeration and the DPAPI
        // key store to use (user or machine) as defined by the StorePermissionFlag
        // enumeration.
        public EncryptionPermission(EncryptionPermissionFlag cipher,
        StorePermissionFlag store)
        {
        _permFlag = cipher;
        _storePermFlag = store;
        }
        public EncryptionPermission()
        {
        _permFlag &= ~EncryptionPermissionFlag.Encrypt |
        EncryptionPermissionFlag.Decrypt;
        _storePermFlag &= ~(StorePermissionFlag.User | StorePermissionFlag.Machine);
        }
        
  9. 添加以下公共属性以允许使用者应用程序设置权限类状态。

    // Set this property to true to allow encryption.
        public bool Encrypt
        {
        set {
        if(true == value)
        {
        _permFlag |= EncryptionPermissionFlag.Encrypt;
        }
        else
        {
        _permFlag &= ~EncryptionPermissionFlag.Encrypt;
        }
        }
        get {
        return (_permFlag & EncryptionPermissionFlag.Encrypt).Equals(
        EncryptionPermissionFlag.Encrypt);
        }
        }
        // Set this property to true to allow decryption.
        public bool Decrypt
        {
        set {
        if(true == value)
        {
        _permFlag |= EncryptionPermissionFlag.Decrypt;
        }
        else
        {
        _permFlag &= ~EncryptionPermissionFlag.Decrypt;
        }
        }
        get {
        return (_permFlag & EncryptionPermissionFlag.Decrypt).Equals(
        EncryptionPermissionFlag.Decrypt);
        }
        }
        // Set this property to true to use the DPAPI machine key.
        public bool MachineStore
        {
        set {
        if(true == value)
        {
        _storePermFlag |= StorePermissionFlag.Machine;
        }
        else
        {
        _storePermFlag &= ~StorePermissionFlag.Machine;
        }
        }
        get {
        return (_storePermFlag & StorePermissionFlag.Machine).Equals(
        StorePermissionFlag.Machine);
        }
        }
        // Set this property to true to use the DPAPI user key.
        public bool UserStore
        {
        set {
        if(true == value)
        {
        _storePermFlag |= StorePermissionFlag.User;
        }
        else
        {
        _storePermFlag &= ~StorePermissionFlag.User;
        }
        }
        get {
        return (_storePermFlag & StorePermissionFlag.User).Equals(
        StorePermissionFlag.User);
        }
        }
        
  10. 实现 IPermission.Copy。这会创建与当前权限实例完全相同的副本,并将其返回到调用方。

    public override IPermission Copy()
        {
        return  new EncryptionPermission(_permFlag, _storePermFlag);
        }
        
  11. 实现 IPermission.Intersect。这会返回一个权限对象,该对象即当前权限和提供权限之间的交集。

    public override IPermission Intersect(IPermission target)
        {
        // An input of null indicates a permission with no state.
        // There can be no common state, so the method returns null.
        if (target == null)
        return null;
        if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
        "Argument must be of type EncryptionPermission.");
        // Cast target to an EncryptionPermission.
        EncryptionPermission targetPerm = (EncryptionPermission)target;
        EncryptionPermissionFlag intersectEncryption = this._permFlag &
        targetPerm._permFlag;
        StorePermissionFlag intersectStore = this._storePermFlag &
        targetPerm._storePermFlag;
        return new EncryptionPermission(intersectEncryption, intersectStore);
        }
        
  12. 实现 IPermission.Union。这会返回一个权限对象,该对象即当前权限和提供权限的并集。

    public override IPermission Union(IPermission target)
        {
        if (target == null)
        return Copy();
        if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
        "Argument must be of type EncryptionPermission.");
        // Cast the target to an EncryptionPermission.
        EncryptionPermission targetPerm = (EncryptionPermission)target;
        EncryptionPermissionFlag unionEncryption = this._permFlag |
        targetPerm._permFlag;
        StorePermissionFlag unionStore = this._storePermFlag |
        targetPerm._storePermFlag;
        return new EncryptionPermission(unionEncryption, unionStore);
        }
        
  13. 实现 IPermission.IsSubsetOf。该方法会返回一个布尔值,以指示当前权限是否是提供权限的子集。要成为子集,则当前权限中状态的每一项也必须位于目标权限内。

    public override bool IsSubsetOf(IPermission target)
        {
        // An input of null indicates a permission with no state.
        // The permission can only be a subset if it's in a similar empty state.
        bool canEncrypt, canDecrypt;
        bool canUseMachineStore, canUseUserStore;
        bool canTargetEncrypt, canTargetDecrypt;
        bool canTargetUseMachineStore, canTargetUseUserStore;
        canEncrypt = (this._permFlag &
        EncryptionPermissionFlag.Encrypt).
        Equals(EncryptionPermissionFlag.Encrypt);
        canDecrypt = (this._permFlag &
        EncryptionPermissionFlag.Decrypt).
        Equals(EncryptionPermissionFlag.Decrypt);
        canUseMachineStore = (this._storePermFlag &
        StorePermissionFlag.Machine).
        Equals(StorePermissionFlag.Machine);
        canUseUserStore = (this._storePermFlag &
        StorePermissionFlag.User).
        Equals(StorePermissionFlag.User);
        if (target == null)
        {
        if ((canEncrypt == false && canDecrypt == false) && (canUseMachineStore ==
        false  && canUseUserStore == false))
        return true;
        else
        return false;
        }
        if (!(target.GetType().Equals(this.GetType())))
        throw new ArgumentException(
        "Argument must be of type EncryptionPermission.");
        // Cast the target to an EncryptionPermission.
        EncryptionPermission targetPerm = (EncryptionPermission)target;
        canTargetEncrypt = (targetPerm._permFlag &
        EncryptionPermissionFlag.Encrypt).
        Equals(EncryptionPermissionFlag.Encrypt);
        canTargetDecrypt = (targetPerm._permFlag &
        EncryptionPermissionFlag.Decrypt).
        Equals(EncryptionPermissionFlag.Decrypt);
        canTargetUseMachineStore = (targetPerm._storePermFlag &
        StorePermissionFlag.Machine).
        Equals(StorePermissionFlag.Machine);
        canTargetUseUserStore = (targetPerm._storePermFlag &
        StorePermissionFlag.User).
        Equals(StorePermissionFlag.User);
        // Every value set (true) in this permission must be in the target.
        // The following code checks to see if the current permission is a subset
        // of the target. If the current permission has something that the target
        // does not have, it cannot be a subset.
        if(canEncrypt == true && canTargetEncrypt == false)
        return false;
        if(canDecrypt == true && canTargetDecrypt == false)
        return false;
        if(canUseMachineStore == true && canTargetUseMachineStore == false)
        return false;
        if(canUseUserStore == true && canTargetUseUserStore == false)
        return false;
        return true;
        }
        
  14. 实现 ISecurityEncodable.ToXml 和 FromXml。这些方法将权限对象的实例转换为 XML 格式,反之亦然。这些方法用于支持序列化。例如,在将安全属性存储在程序集元数据中时使用这些方法。

    public override SecurityElement ToXml()
        {
        // Create a new element. The tag name must always be IPermission.
        SecurityElement elem = new SecurityElement("IPermission");
        // Determine the fully qualified type name (including the assembly name) of
        // the EncryptionPermission class. (The security system uses this name to
        // locate and load the class.)
        string name = typeof(EncryptionPermission).AssemblyQualifiedName;
        // Add attributes for the class name and protocol version.
        // The version must currently be 1.
        elem.AddAttribute("class", name);
        elem.AddAttribute("version", "1" );
        if (IsUnrestricted())
        {
        // Using the Unrestricted attribute is consistent with the
        // built-in .NET Framework permission types and helps keep
        // the encoding compact.
        elem.AddAttribute("Unrestricted", Boolean.TrueString);
        }
        else
        {
        // Encode each state field as an attribute of the Permission element.
        // To compact, encode only nondefault state parameters.
        elem.AddAttribute("Flags", this._permFlag.ToString());
        elem.AddAttribute("Stores", this._storePermFlag.ToString());
        }
        // Return the completed element.
        return elem;
        }
        // Converts a SecurityElement (or tree of elements) to a permission
        // instance.
        public override void FromXml(SecurityElement elem)
        {
        string attrVal = "";
        // Check for an unrestricted instance.
        attrVal = elem.Attribute("Unrestricted");
        if (attrVal != null)
        {
        if(attrVal.ToLower().Equals("true"))
        {
        this._permFlag = EncryptionPermissionFlag.Encrypt |
        EncryptionPermissionFlag.Decrypt;
        this._storePermFlag = StorePermissionFlag.Machine |
        StorePermissionFlag.User;
        }
        return;
        }
        //Turn off the permission and store flags.
        this._permFlag &= ~(EncryptionPermissionFlag.Encrypt |
        EncryptionPermissionFlag.Decrypt);
        this._storePermFlag &= ~(StorePermissionFlag.Machine |
        StorePermissionFlag.User);
        attrVal = elem.Attribute("Flags");
        if (attrVal != null)
        {
        if(!attrVal.Trim().Equals(""))
        {
        this._permFlag =
        (EncryptionPermissionFlag)Enum.Parse(typeof(EncryptionPermissionFlag),
        attrVal);
        }
        }
        attrVal = elem.Attribute("Stores");
        if (attrVal != null)
        {
        if(!attrVal.Trim().Equals(""))
        {
        this._storePermFlag =
        (StorePermissionFlag)Enum.Parse(typeof(StorePermissionFlag),
        attrVal);
        }
        }
        }
        
  15. 实现 IUnrestrictedPermission.IsUnrestricted。如果权限实例处于不受限制的状态,则该方法返回 true。本例中,不受限制的 EncryptionPermission 实例允许代码使用 DPAPI 机器和用户存储来加密和解密数据。

    public bool IsUnrestricted()
        {
        bool canEncrypt, canDecrypt, canUseUserStore, canUseMachineStore;
        canEncrypt = (this._permFlag &
        EncryptionPermissionFlag.Encrypt).
        Equals(EncryptionPermissionFlag.Encrypt);
        canDecrypt = (this._permFlag &
        EncryptionPermissionFlag.Decrypt).
        Equals(EncryptionPermissionFlag.Decrypt);
        canUseUserStore = (this._storePermFlag &
        StorePermissionFlag.User).
        Equals(StorePermissionFlag.User);
        canUseMachineStore = (this._storePermFlag &
        StorePermissionFlag.Machine).
        Equals(StorePermissionFlag.Machine);
        return ((canEncrypt && canDecrypt) &&
        (canUseUserStore && canUseMachineStore));
        }
        

创建 EncryptionPermissionAttribute 类

.NET Framework 使用与其合作伙伴权限类相关联的属性类来编码权限实例。您需要权限属性来支持声明性安全语法。

创建 EncryptionPermissionAttribute 类

  1. 将一个新类文件添加到当前项目,EncryptionPermissionAttribute.cs。

  2. 将以下 using 语句添加到新文件的顶端。

    using System.Security;
        using System.Diagnostics;
        using System.Security.Permissions;
        
  3. 从 CodeAccessSecurityAttribute 导出属性类,并将其密封。

    public sealed class EncryptionPermissionAttribute :
        CodeAccessSecurityAttribute
        
  4. 向该类添加序列化支持,并使用 AttributeUsage 属性来指示可以使用自定义权限属性的位置。

    [Serializable,
        AttributeUsage(AttributeTargets.Method |      // Can use on methods
        AttributeTargets.Constructor | // Can use on constructors
        AttributeTargets.Class |       // Can use on classes
        AttributeTargets.Struct |      // Can use on structures
        AttributeTargets.Assembly,     // Can use at the assembly level
        AllowMultiple = true,          // Can use multiple attribute
        // instances per program element
        // (class, method and so on)
        Inherited = false)]            // Can not be inherited
        
  5. 向该类添加私有成员变量以镜像由关联的权限类维持的状态。

    // The following state fields mirror those used in the associated
        // permission type.
        private bool _encrypt = false;
        private bool _decrypt = false;
        private bool _machineStore = false;
        private bool _userStore = false;
        
  6. 用以下构造函数替换默认的构造函数。

    // Pass the action code back to the base class.
        public EncryptionPermissionAttribute(SecurityAction action) : base(action)
        {
        }
        
  7. 添加以下公共属性以镜像这些由关联的权限类提供的各项。

    public bool Encrypt
        {
        get {
        return _encrypt;
        }
        set {
        _encrypt = value;
        }
        }
        public bool Decrypt
        {
        get {
        return _decrypt;
        }
        set {
        _decrypt = value;
        }
        }
        public bool UserStore
        {
        get {
        return _userStore;
        }
        set {
        _userStore = value;
        }
        }
        public bool MachineStore
        {
        get {
        return _machineStore;
        }
        set {
        _machineStore = value;
        }
        }
        
  8. 实现 SecurityPermissionAttribute.CreatePermission。该方法会创建一个权限对象,该对象随后被序列化并通过程序集的元数据中指定的 SecurityAction 枚举进行保留。

    public override IPermission CreatePermission()
        {
        // The runtime automatically provides a property to indicate
        // whether or not an unrestricted instance is required.
        if((Unrestricted) || ((_encrypt && _decrypt) &&
        (_userStore && _machineStore)))
        {
        return new EncryptionPermission(PermissionState.Unrestricted);
        }
        // Copy the state from the attribute to the permission object
        EncryptionPermissionFlag cipher = 0x0;
        StorePermissionFlag store = 0x0;
        if(_encrypt)
        cipher |= EncryptionPermissionFlag.Encrypt;
        if(_decrypt)
        cipher |= EncryptionPermissionFlag.Decrypt;
        if(_userStore)
        store |= StorePermissionFlag.User;
        if(_machineStore)
        store |= StorePermissionFlag.Machine;
        // Return the final permission.
        return new EncryptionPermission(cipher, store);
        }
        
  9. 生成解决方案。

在 GAC 中安装权限程序集

您必须对实现自定义安全权限的所有程序集授予完全信任。实际上,这意味着您需要在使用程序集的计算机上安装该程序集,以确保默认的安全策略授予其完全信任。My_Computer_Zone 内的代码由默认的策略授予完全信任。

在 GAC 中安装程序集是确保代码访问安全策略授予其完全信任的一种方法。GAC 是适合于权限程序集的位置,原因在于该程序集由本地计算机上的代码访问安全策略使用,并且它对于本地计算机上安装的所有 .NET Framework 应用程序均可用。

要在本地计算机的 GAC 中安装自定义权限程序集,请运行以下命令。

gacutil.exe /i custompermission.dll

更新 DPAPI 托管包装代码

.NET Framework 类库目前并未公开 DPAPI 功能。要从 .NET Framework 应用程序调用 DPAPI,必须使用 P/Invoke。有关演示如何创建托管 DPAPI 包装程序集的代码的信息,请参阅“How To Create a DPAPI Library”。

不做进一步的修改,您只可从完全信任代码调用参考“如何……”方法文章中的托管 DPAPI 包装。若要能够从部分信任代码(例如,中等信任的 ASP.NET Web 应用程序)调用 DPAPI 包装,您必须将对非托管 DPAPI 函数的调用置于沙箱内方可。为此,需进行以下修改:

  • 宣告 DPAPI 包装代码中的非托管代码权限。这意味着任何调用代码均不要求非托管代码权限。

  • 通过要求自定义 EncryptionPermission 在包装内授权调用代码。根据 Demand/Assert 使用模式,Demand 调用在 Assert 调用前出现。有关安全使用 Assert 的详细信息,请参阅单元“Code Access Security in Practice”中的“Assert and RevertAssert”。

修改 DPAPI 托管包装

  1. 通过“如何创建 DPAPI 库”中的以下指令构建 DPAPI 托管包装。

  2. 向 CustomPermission 程序集添加引用。

  3. 从托管包装库中打开 dataprotection.cs,并在该文件顶端现有的 using 语句下添加以下 using 语句。

    using System.Security;
        using System.Security.Permissions;
        using CustomPermissions;
        
  4. 在 dataprotection.cs 中找到 Encrypt 方法,并在该 Encrypt 方法中的外部 try 块顶端添加以下代码。

    // Set the storeFlag depending on how the caller uses
        // the managed DPAPI wrapper.
        StorePermissionFlag storeFlag;
        if(Store.USE_MACHINE_STORE == store)
        {
        storeFlag = StorePermissionFlag.Machine;
        }
        else
        {
        storeFlag = StorePermissionFlag.User;
        }
        // Demand custom EncryptionPermission.
        (new EncryptionPermission(EncryptionPermissionFlag.Encrypt, storeFlag)).
        Demand();
        // Assert the unmanaged code permission.
        (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
        // Now use P/Invoke to call the unmanaged DPAPI functions.
        
  5. 将以下 finally 块添加到该 Encrypt 方法中的外部 try 块。

    finally
        {
        CodeAccessPermission.RevertAssert();
        }
        
  6. 找到 dataprotection.cs 中的 Decrypt 方法,并将以下代码添加到外部 try 块的顶端。

    StorePermissionFlag storeFlag;
        if(Store.USE_MACHINE_STORE == store)
        {
        storeFlag = StorePermissionFlag.Machine;
        }
        else
        {
        storeFlag = StorePermissionFlag.User;
        }
        // Demand custom EncryptionPermission.
        (new EncryptionPermission(EncryptionPermissionFlag.Decrypt, storeFlag)).
        Demand();
        // Assert the unmanaged code permission.
        (new SecurityPermission(SecurityPermissionFlag.UnmanagedCode)).Assert();
        
  7. 将以下 finally 块添加到该 Decrypt 方法中的外部 try 块。

    finally
        {
        CodeAccessPermission.RevertAssert();
        }
        

从中等信任的 Web 应用程序调用 DPAPI

要从中等信任的 Web 应用程序或任何部分信任的代码使用 DPAPI 托管包装,您必须配置代码访问安全策略以授予代码自定义 EncryptionPermission。

本步骤中,将创建测试 Web 应用程序,然后修改中等信任的 Web 应用程序的 ASP.NET 代码访问安全策略以授予其 EncryptionPermission。

创建测试 Web 应用程序

  1. 将新的 C# ASP.NET Web 应用程序项目添加当前解决方案。

  2. 向 Dataprotection.dll 程序集添加引用。

  3. 将以下字段添加到 Webform1.aspx。

    • 一个用于要加密数据的输入字段。使用 ID txtDataToEncrypt。

    • 一个用于已加密数据的字段。使用 ID txtEncryptedData。

    • 一个用于已解密数据的字段。使用 ID txtDecryptedData。

    • 一个 Encrypt 按钮。使用 ID btnEncrypt。

    • 一个 Decrypt 按钮。使用 IDbtnDecrypt。

    • 一个用于错误消息的标签。使用 ID lblError。

  4. 将以下 using 语句添加到现有 using 语句之下的 WebForm1.aspx.cs 顶端。

    using DataProtection;
        
  5. 添加以下代码以用于 Encrypt 按钮单击事件处理程序。

    private void btnEncrypt_Click(object sender, System.EventArgs e)
        {
        DataProtector dp = new DataProtector(
        DataProtector.Store.USE_MACHINE_STORE );
        try
        {
        byte[] dataToEncrypt = Encoding.ASCII.GetBytes(txtDataToEncrypt.Text);
        // Not passing optional entropy in this example
        // Could pass random value (stored by the application) for added security
        // when using DPAPI with the machine store.
        txtEncryptedData.Text =
        Convert.ToBase64String(dp.Encrypt(dataToEncrypt,null));
        }
        catch(Exception ex)
        {
        lblError.ForeColor = Color.Red;
        lblError.Text = "Exception.<br>" + ex.Message;
        return;
        }
        lblError.Text = "";
        }
        
  6. 添加以下代码以用于 Decrypt 按钮单击事件处理程序。

    private void btnDecrypt_Click(object sender, System.EventArgs e)
        {
        DataProtector dp = new DataProtector(DataProtector.Store.USE_MACHINE_STORE);
        try
        {
        byte[] dataToDecrypt = Convert.FromBase64String(txtEncryptedData.Text);
        // Optional entropy parameter is null.
        // If entropy was used within the Encrypt method, the same entropy
        // parameter must be supplied here.
        txtDecryptedData.Text =
        Encoding.ASCII.GetString(dp.Decrypt(dataToDecrypt,null));
        }
        catch(Exception ex)
        {
        lblError.ForeColor = Color.Red;
        lblError.Text = "Exception.<br>" + ex.Message;
        return;
        }
        lblError.Text = "";
        }
        
  7. 通过将以下元素添加到 <system.web> 部分内应用程序的 Web.config 文件来配置 Web 应用程序以用于中等信任。

    <trust level="Medium" />
        
  8. 生成解决方案。

修改中等信任策略

  1. 使用 Visual Studio® .NET 或记事本打开中等信任策略文件。该策略文件位于以下位置。

    %windir%\Microsoft.NET\Framework\{version}\CONFIG\web_mediumtrust.config
  2. 通过将以下 <SecurityClass> 元素添加到 <SecurityClasses> 元素来声明 EncryptionPermission。

    <SecurityClass Name="EncryptionPermission"
        Description="CustomPermission.EncryptionPermission,
        CustomPermission, Version=1.0.0.1,
        Culture=neutral,
        PublicKeyToken=951cd7d57a536a94"/>
        

    将 PublicKeyToken 属性值设为程序集指定的公钥标记。要提取自定义权限程序集的公钥标记,请使用以下命令。

    sn -T custompermission.dll

    注 使用大写 -T 开关项。

  3. 找到在中等信任策略文件中的 ASP.NET 命名权限集,并添加以下权限元素。

    <IPermission class="EncryptionPermission"
        version="1" Flags="Encrypt,Decrypt"
        Stores="Machine,User">
        </IPermission>
        
    该权限授予中等信任的 Web 应用程序不受限制的 EncryptionPermission,原因在于它允许代码加密和解密数据,以及使用 DPAPI 机器和用户存储。以上元素演示了支持的语法。它等同于以下内容:
        
    <IPermission class="EncryptionPermission"
        version="1" Unrestricted="true" >
        </IPermission>
        

    通过仅使用相关的属性,您可以授予代码限制的权限。例如,要限制代码仅使用机器存储中的机器密钥解密数据,请使用以下元素。

    <IPermission class="EncryptionPermission"
        version="1" Flags="Decrypt"
        Stores="Machine">
        </IPermission>
        
  4. 保存策略文件。

    现在您可以运行测试 Web 应用程序,并验证通过使用部分信任的 Web 应用程序的 DPAPI 可否加密和解密数据。

有关将高权限代码置于沙箱内和使用 ASP.NET 代码访问安全策略的详细信息,请参阅单元“Using Code Access Security with ASP.NET”。

只有注册用户登录后才能发表评论。