C# 安全代码审查:如何处理解密的对称密钥?
在以下代码中:C# 安全代码审查:如何处理解密的对称密钥?,c#,security,encryption,azure,rsa,C#,Security,Encryption,Azure,Rsa,在以下代码中:symmetricCryptoKey表示应始终保护的私有信息,因为它是加密对称密钥的解密版本 问题: 在多租户环境(托管在Azure上)中,我是否可以进行其他增强来保护内存,特别是与symmetricCryptoKey或keyCache的交互 TL;DR代码示例 byte[] symmetricCryptoKey = RSA.Decrypt(key.Key, true); AesManaged algorithm
symmetricCryptoKey
表示应始终保护的私有信息,因为它是加密对称密钥的解密版本
问题:
- 在多租户环境(托管在Azure上)中,我是否可以进行其他增强来保护内存,特别是与
或keyCache的交互symmetricCryptoKey
byte[] symmetricCryptoKey = RSA.Decrypt(key.Key, true);
AesManaged algorithm = new AesManaged();
algorithm.IV = key.iv;
algorithm.Key = symmetricCryptoKey;
keyCache[key.Version] = algorithm;
完整的代码文件
使用EncryptDecrypt.Exceptions;
使用Microsoft.WindowsAzure.Storage;
使用制度;
使用System.Collections.Generic;
使用System.Data.Services.Client;
Net系统;
使用System.Security.Cryptography;
使用System.Security.Cryptography.X509证书;
命名空间加密解密
{
///
///存储各种加密密钥,这样我们就不需要一直从存储中加载它们
///
///
///我们应该做些什么来保护这个类使用的内存?
///
内部类AzureTableCryptoKeyStore:IDisposable
{
私有字典keyCache=新字典();
内部CloudStorageAccount KeyStoreAccount{get;private set;}
内部AzureTableCryptoKeyStore(CloudStorageAccount帐户)
{
this.keystreaccount=acct;
SymmetricKeyStore keyTable=新的SymmetricKeyStore(acct);
List allkey=null;
尝试
{
allKeys=keyTable.GetAllKeys();
}
捕获(DataServiceQueryException dsq)
{
if(dsq.Response.StatusCode==(int)HttpStatusCode.NotFound)
{
//表还没有创建,所以没有任何键。我想我们还是继续吧。
allKeys=新列表(0);
}
其他的
{
抛出新的AzureTableCryptoInitializationException(“未能从存储器加载加密密钥”,dsq);
}
}
捕获(DataServiceClientException dsce)
{
if(dsce.StatusCode==(int)HttpStatusCode.NotFound)
{
//表还没有创建,所以没有任何键。我想我们还是继续吧。
allKeys=新列表(0);
}
其他的
{
抛出新的AzureTableCryptoInitializationException(“未能从存储器加载加密密钥”,dsce);
}
}
捕获(例外情况除外)
{
抛出新的AzureTableCryptoInitializationException(“无法加载加密密钥表”,ex);
}
foreach(所有键中的var键)
{
尝试
{
X509Certificate2 certificate=CertificateHelper.GetCertificateByThumbprint(key.CertificateThumbprint);
如果(证书==null)
{
//找不到此密钥的证书,请继续
继续;
}
RSA加密服务提供商RSA;
尝试
{
RSA=(RSACryptServiceProvider)certificate.PrivateKey;
}
捕获(加密例外)
{
抛出新的AzureTableCryptoPrivateKeyNotAccessibleException(key.Version,key.CertificateThumbprint);
}
byte[]symmetricCryptoKey=RSA.Decrypt(key.key,true);
AES托管算法=新AES托管();
算法4.IV=密钥4.IV;
算法密钥=symmetricCryptoKey;
keyCache[key.Version]=算法;
}
捕获(AzureTableCryptoException)
{
//只要把这些再翻一遍
投掷;
}
捕获(例外情况除外)
{
抛出新的AzureTableCryptoInitializationException(“初始化加密密钥版本时出错”+key.version,ex);
}
}
}
内部ICryptoTransform GetDecryptor(int版本)
{
返回GetAlgorithm(version).CreateDecryptor();
}
内部ICryptoTransform GetEncryptor(int版本)
{
返回GetAlgorithm(version).CreateEncryptor();
}
私有对称算法(int版)
{
对称算法;
如果(!keyCache.TryGetValue(版本,输出算法))
{
抛出新的AzureTableCryptoNotFoundException(版本);
}
返回算法;
}
公共空间处置()
{
字典缓存=键缓存;
keyCache=null;
foreach(cache.Values中的var algo)
{
算法清除();
算法Dispose();
}
}
}
}
您可以使用SecureString之类的东西来防止内存嗅探器抓取密钥:
它们当然不是完美的,因为如果程序本身拥有解密它的所有信息,那么计算机中就有查看字符串所需的所有信息。不过,它确实减少了可能被破坏的情况。我真的不担心这一点。如果您的代码有一个对称密钥,那么对该密钥所做的任何“加密”实际上只是混淆;因为任何对您的进程有内存访问权限的人都可以读取您用来解密正在使用的对称密钥的任何密钥。只要确保在处理完相关内存后将其归零(您的代码似乎已经这样做了)。@BillyONeal-我正在考虑对我的da中托管的服务器使用这种方法
using EncryptDecrypt.Exceptions;
using Microsoft.WindowsAzure.Storage;
using System;
using System.Collections.Generic;
using System.Data.Services.Client;
using System.Net;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace EncryptDecrypt
{
/// <summary>
/// Store the various encryption keys so that we don't need to load them from storage all the time
/// </summary>
/// <remarks>
/// Is there something we should be doing to secure the memory used by this class?
/// </remarks>
internal class AzureTableCryptoKeyStore : IDisposable
{
private Dictionary<int, SymmetricAlgorithm> keyCache = new Dictionary<int, SymmetricAlgorithm>();
internal CloudStorageAccount KeyStoreAccount { get; private set; }
internal AzureTableCryptoKeyStore(CloudStorageAccount acct)
{
this.KeyStoreAccount = acct;
SymmetricKeyStore keyTable = new SymmetricKeyStore(acct);
List<SymmetricKey> allKeys = null;
try
{
allKeys = keyTable.GetAllKeys();
}
catch (DataServiceQueryException dsq)
{
if (dsq.Response.StatusCode == (int)HttpStatusCode.NotFound)
{
//Table hasn't been created, so there aren't any keys. Guess we'll just go with it.
allKeys = new List<SymmetricKey>(0);
}
else
{
throw new AzureTableCryptoInitializationException("Failed to load encryption keys from storage", dsq);
}
}
catch (DataServiceClientException dsce)
{
if (dsce.StatusCode == (int)HttpStatusCode.NotFound)
{
//Table hasn't been created, so there aren't any keys. Guess we'll just go with it.
allKeys = new List<SymmetricKey>(0);
}
else
{
throw new AzureTableCryptoInitializationException("Failed to load encryption keys from storage", dsce);
}
}
catch (Exception ex)
{
throw new AzureTableCryptoInitializationException("Could not load encryption keys table", ex);
}
foreach (var key in allKeys)
{
try
{
X509Certificate2 certificate = CertificateHelper.GetCertificateByThumbprint(key.CertificateThumbprint);
if (certificate == null)
{
//Can't find the cert for this key, just continue
continue;
}
RSACryptoServiceProvider RSA;
try
{
RSA = (RSACryptoServiceProvider)certificate.PrivateKey;
}
catch (CryptographicException)
{
throw new AzureTableCryptoPrivateKeyNotAccessibleException(key.Version, key.CertificateThumbprint);
}
byte[] symmetricCryptoKey = RSA.Decrypt(key.Key, true);
AesManaged algorithm = new AesManaged();
algorithm.IV = key.iv;
algorithm.Key = symmetricCryptoKey;
keyCache[key.Version] = algorithm;
}
catch (AzureTableCryptoException)
{
//Just rethrow these
throw;
}
catch (Exception ex)
{
throw new AzureTableCryptoInitializationException("Error initializing crypto key version " + key.Version, ex);
}
}
}
internal ICryptoTransform GetDecryptor(int version)
{
return GetAlgorithm(version).CreateDecryptor();
}
internal ICryptoTransform GetEncryptor(int version)
{
return GetAlgorithm(version).CreateEncryptor();
}
private SymmetricAlgorithm GetAlgorithm(int version)
{
SymmetricAlgorithm algo;
if (!keyCache.TryGetValue(version, out algo))
{
throw new AzureTableCryptoNotFoundException(version);
}
return algo;
}
public void Dispose()
{
Dictionary<int, SymmetricAlgorithm> cache = keyCache;
keyCache = null;
foreach (var algo in cache.Values)
{
algo.Clear();
algo.Dispose();
}
}
}
}