Azure Blob存储无Key Vault透明加密实现报错求助
Azure Blob存储自定义密钥管理的客户端加密实现问题及解决思路
场景需求
- 在B2B场景下实现Azure Blob存储的透明数据加密,不能将密钥存入Key Vault
- 加密流程:生成对称密钥加密Blob数据,再用客户公钥加密该对称密钥后存储
- 解密流程:客户用私钥解密对称密钥,再解密Blob数据
遇到的问题
现有示例全是基于Key Vault的,微软文档只提了可以外部实现密钥管理,但没给具体示例。自己写KeyEncryptionKey相关代码后,调用UploadBlobAsync时直接报**"Operation WrapKey is not supported with the given key"**;要是不指定KeyWrapAlgorithm,又会提示参数为空。
你尝试的代码如下:
var symmetricSecurityKey = new SymmetricSecurityKey(_context.EncryptionKey); var jsonWebKey = JsonWebKeyConverter.ConvertFromSymmetricSecurityKey(symmetricSecurityKey); jsonWebKey.AdditionalData["iv"] = Convert.ToBase64String(_context.IV); string jsonSerializedKey = JsonSerializer.Serialize(jsonWebKey); Azure.Security.KeyVault.Keys.JsonWebKey keyvaultKey = (Azure.Security.KeyVault.Keys.JsonWebKey)JsonSerializer.Deserialize<Azure.Security.KeyVault.Keys.JsonWebKey>(jsonSerializedKey); keyvaultKey.KeyType = KeyType.Rsa; var cryptoClient = new CryptographyClient(keyvaultKey); var keyResolver = new KeyResolver(new DefaultAzureCredential()); // We want the key to be passed from ClientSideEncryptionOptions encryptionOptions = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V2_0) { KeyEncryptionKey = cryptoClient, KeyResolver = keyResolver, // String value that the client library will use when calling IKeyEncryptionKey.WrapKey() KeyWrapAlgorithm = "RSA-OAEP" };
问题根源与解决思路
问题出在哪
- 你把对称密钥转成JWK后强行改成
KeyType.Rsa,本质还是对称密钥,CryptographyClient不认这种伪造的RSA密钥——RSA密钥需要n、e这类公钥参数,对称密钥根本没有,自然不支持WrapKey操作。 KeyResolver用DefaultAzureCredential是用来访问Key Vault的,和你自定义密钥管理的需求完全不搭,根本没必要加这个。
正确实现方式
别用Key Vault的现成类了,直接自己实现IKeyEncryptionKey和IKeyResolver接口,加密时用客户公钥做WrapKey,解密时用客户私钥做UnwrapKey就行。
自定义IKeyEncryptionKey(加密时包装对称密钥)
public class CustomRsaKeyEncryptionKey : IKeyEncryptionKey { private readonly RSA _rsaPublicKey; public string KeyId { get; } public string Algorithm => "RSA-OAEP"; public CustomRsaKeyEncryptionKey(string keyId, RSA rsaPublicKey) { KeyId = keyId; _rsaPublicKey = rsaPublicKey; } public async Task<byte[]> WrapKeyAsync(string algorithm, byte[] key, CancellationToken cancellationToken = default) { if (algorithm != Algorithm) throw new NotSupportedException($"不支持算法 {algorithm}"); return await Task.FromResult(_rsaPublicKey.Encrypt(key, RSAEncryptionPadding.OaepSHA256)); } }
自定义IKeyResolver(解密时找到对应私钥)
public class CustomKeyResolver : IKeyResolver { private readonly Dictionary<string, RSA> _privateKeys; public CustomKeyResolver(Dictionary<string, RSA> privateKeys) { _privateKeys = privateKeys; } public async Task<IKeyEncryptionKey> ResolveKeyAsync(string keyId, CancellationToken cancellationToken = default) { if (_privateKeys.TryGetValue(keyId, out var rsaPrivateKey)) { return await Task.FromResult(new CustomRsaKeyEncryptionKey(keyId, rsaPrivateKey)); } throw new KeyNotFoundException($"找不到ID为 {keyId} 的密钥"); } }
加密场景使用示例
// 加载客户的RSA公钥(替换成实际的公钥加载逻辑,比如从PEM字符串导入) RSA customerRsaPublicKey = RSA.Create(); customerRsaPublicKey.ImportFromPem("-----BEGIN PUBLIC KEY-----...-----END PUBLIC KEY-----"); // 创建自定义密钥加密对象 var kek = new CustomRsaKeyEncryptionKey("customer-key-1", customerRsaPublicKey); // 配置客户端加密选项 var encryptionOptions = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V2_0) { KeyEncryptionKey = kek, KeyResolver = new CustomKeyResolver(new Dictionary<string, RSA>()), // 加密时Resolver可以空着 KeyWrapAlgorithm = "RSA-OAEP" }; // 创建带加密的Blob客户端并上传 var blobClient = new BlobClient(new Uri("你的Blob地址"), new DefaultAzureCredential(), encryptionOptions); await blobClient.UploadAsync("本地文件路径", true);
解密场景使用示例
// 加载客户的RSA私钥(替换成实际的私钥加载逻辑) RSA customerRsaPrivateKey = RSA.Create(); customerRsaPrivateKey.ImportFromPem("-----BEGIN PRIVATE KEY-----...-----END PRIVATE KEY-----"); // 创建包含私钥的Resolver var keyResolver = new CustomKeyResolver(new Dictionary<string, RSA> { {"customer-key-1", customerRsaPrivateKey} }); // 配置解密用的加密选项 var decryptionOptions = new ClientSideEncryptionOptions(ClientSideEncryptionVersion.V2_0) { KeyResolver = keyResolver, KeyWrapAlgorithm = "RSA-OAEP" }; // 创建Blob客户端并解密下载 var blobClient = new BlobClient(new Uri("你的Blob地址"), new DefaultAzureCredential(), decryptionOptions); await blobClient.DownloadToAsync("本地保存路径");
关键注意点
- 客户的RSA密钥长度至少要2048位,符合Azure客户端加密的要求
- Blob数据加密用的对称密钥是SDK自动生成的,不用你手动创建,你只负责用客户公钥包装这个自动生成的密钥就行
- 存储加密后的对称密钥时,要绑定对应的密钥ID,方便解密时Resolver找到匹配的私钥
内容的提问来源于stack exchange,提问作者CloudAnywhere
相关产品推荐
相关产品推荐

