c# - 安全代码审查 : What to do with decrypted symmetric keys?

标签 c# security encryption azure rsa

在以下代码中:symmetryCryptoKey 表示应始终受到保护的私有(private)信息,因为它是加密对称 key 的解密版本。

问题:

  • 是否可以进行其他增强来保护 Multi-Tenancy 环境(托管在 Azure 上)中的内存,特别是与 symmetryCryptoKey 或 keyCache 的交互?

TL;DR 代码示例

                byte[] symmetricCryptoKey = RSA.Decrypt(key.Key, true);

                AesManaged algorithm = new AesManaged();
                algorithm.IV = key.iv;
                algorithm.Key = symmetricCryptoKey;
                keyCache[key.Version] = algorithm;

完整代码文件... Codeplex source

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();
            }
        }
    }
}

最佳答案

您可以使用一些东西(例如 SecureString)来帮助防止内存嗅探器获取 key :

How is SecureString "encrypted" and still usable?

它们当然并不完美,因为如果程序本身具有解密它的所有信息,那么计算机中就有查看字符串所需的所有信息。不过,它确实减少了可能受到损害的情况。

关于c# - 安全代码审查 : What to do with decrypted symmetric keys?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13390751/

相关文章:

c# - 测试比较数组方法失败

c# - 桌面应用程序部署——尝试编写只读数据库 sqlite

c++ - 创建加密安全密码。并验证它是否有效

python - Python 的快速 RC4 密码流?

python - AES key 的内容重要吗?

c# - 如何跟踪 Nuget.Server 上的包下载?

c# - 如何在 C# 中应用多个 .Tag 属性?

php - 如何免费检查网站安全?

php - 加密 session ID

c++ - 如何在没有 CPU 拷贝的情况下上传 GPU 操作生成的 DXT5 压缩像素数据?