You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用私钥签名数据时触发PrivilegeNotHeldException异常求助

私钥签名权限异常:PrivilegeNotHeldException 解决方法

问题场景

使用私钥对数据签名时,无法从私钥证书中获取所需数据,触发System.Security.AccessControl.PrivilegeNotHeldException异常,具体异常信息如下:

((System.Security.Cryptography.RSACryptoServiceProvider)privateCertificate.PrivateKey).CspKeyContainerInfo.CryptoKeySecurity = ((System.Security.Cryptography.RSACryptoServiceProvider)privateCertificate.PrivateKey).CspKeyContainerInfo.CryptoKeySecurity
   threw an exception of type 'System.Security.AccessControl.PrivilegeNotHeldException'

相关C#代码如下:

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            // 从.cer文件加载公钥
            X509Certificate2 publicCertificate = new X509Certificate2("public.cer");
            RSAParameters publicKey = ((RSA)publicCertificate.PublicKey.Key).ExportParameters(false);

            // 从.pfx文件加载私钥
            X509Certificate2 privateCertificate = new X509Certificate2("private.pfx", "marwadi", X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
            RSACryptoServiceProvider privateKey = (RSACryptoServiceProvider)privateCertificate.PrivateKey;

            // 待加密的消息
            string originalMessage = "Vivek";

            // 将消息转换为字节数组
            byte[] originalBytes = Encoding.UTF8.GetBytes(originalMessage);

            // 使用公钥加密消息
            byte[] encryptedBytes = Encryption(originalBytes, publicKey, true);

            // 为加密数据生成签名
            byte[] signature = GenerateSignature(encryptedBytes, privateKey);

            // 解密前验证签名
            if (VerifySignature(encryptedBytes, signature, publicKey))
            {
                // 使用私钥解密消息
                byte[] decryptedData = Decryption(encryptedBytes, privateKey);

                // 将解密后的字节数组转换回字符串
                string decryptedMessage = Encoding.UTF8.GetString(decryptedData);

                // 显示结果
                Console.WriteLine("原始消息: " + originalMessage);
                Console.WriteLine("加密消息: " + Convert.ToBase64String(encryptedBytes));
                Console.WriteLine("签名: " + Convert.ToBase64String(signature));
                Console.WriteLine("解密消息: " + decryptedMessage);
            }
            else
            {
                Console.WriteLine("无效签名,终止解密。");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("发生错误: " + e.Message);
            Console.WriteLine("堆栈跟踪: " + e.StackTrace);
        }

        Console.ReadKey();
    }

    static public byte[] Encryption(byte[] data, RSAParameters publicKey, bool doOAEPPadding)
    {
        try
        {
            byte[] encryptedData;
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.ImportParameters(publicKey);
                encryptedData = rsa.Encrypt(data, doOAEPPadding);
            }
            return encryptedData;
        }
        catch (CryptographicException e)
        {
            Console.WriteLine("加密错误: " + e.Message);
            Console.WriteLine("堆栈跟踪: " + e.StackTrace);
            return null;
        }
    }

    static public byte[] GenerateSignature(byte[] data, RSACryptoServiceProvider privateKey)
    {
        try
        {
            RSAPKCS1SignatureFormatter rsaFormatter = new RSAPKCS1SignatureFormatter(privateKey);
            rsaFormatter.SetHashAlgorithm(nameof(SHA256));
            return rsaFormatter.CreateSignature(data);
        }
        catch (CryptographicException e)
        {
            Console.WriteLine("签名生成错误: " + e.Message);
            Console.WriteLine("堆栈跟踪: " + e.StackTrace);
            return null;
        }
    }

    static public bool VerifySignature(byte[] data, byte[] signature, RSAParameters publicKey)
    {
        try
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.ImportParameters(publicKey);
                RSAPKCS1SignatureDeformatter rsaDeformatter = new RSAPKCS1SignatureDeformatter(rsa);
                rsaDeformatter.SetHashAlgorithm(nameof(SHA256));
                return rsaDeformatter.VerifySignature(data, signature);
            }
        }
        catch (CryptographicException e)
        {
            Console.WriteLine("签名验证错误: " + e.Message);
            Console.WriteLine("堆栈跟踪: " + e.StackTrace);
            return false;
        }
    }

    static public byte[] Decryption(byte[] data, RSAParameters publicKey)
    {
        try
        {
            using (RSACryptoServiceProvider rsa = new RSACryptoServiceProvider())
            {
                rsa.ImportParameters(publicKey);
                return rsa.Decrypt(data, true);
            }
        }
        catch (CryptographicException e)
        {
            Console.WriteLine("解密错误: " + e.Message);
            Console.WriteLine("堆栈跟踪: " + e.StackTrace);
            return null;
        }
    }
}

解决方法

  • 以管理员权限运行程序:PrivilegeNotHeldException大多是因为当前进程无足够权限访问密钥容器,右键程序或开发工具选择「以管理员身份运行」即可。
  • 调整密钥容器权限:若管理员运行仍无效,需手动修改密钥容器访问权限:
    1. 管理员模式打开命令提示符,执行certutil -user -store My找到对应证书的Container字段值;
    2. 执行icacls "C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\<容器名称>" /grant <用户名>:R,替换占位符为实际值,给当前用户赋予读取权限。
  • 修改证书加载参数:将X509KeyStorageFlags.MachineKeySet替换为UserKeySet,把密钥存储在当前用户容器中,降低权限限制:
    X509Certificate2 privateCertificate = new X509Certificate2("private.pfx", "marwadi", X509KeyStorageFlags.UserKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
    
  • 避免访问敏感属性:若代码无需修改密钥安全设置,不要直接读取CspKeyContainerInfo.CryptoKeySecurity,该操作会触发权限检查。

内容的提问来源于stack exchange,提问作者Vivek Patel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 16:25:28