使用私钥签名数据时触发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大多是因为当前进程无足够权限访问密钥容器,右键程序或开发工具选择「以管理员身份运行」即可。 - 调整密钥容器权限:若管理员运行仍无效,需手动修改密钥容器访问权限:
- 管理员模式打开命令提示符,执行
certutil -user -store My找到对应证书的Container字段值; - 执行
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
相关产品推荐
相关产品推荐

