internal static async Task <string> RotateEncryptionHelper(KeyRotationEntity rotationEntity, TableRequestOptions modifiedOptions, CancellationToken cancellationToken) { // Validate arguments: String encryptionDataString = rotationEntity.encryptionMetadataJson; TableEncryptionPolicy.ValidateKeyRotationArguments(rotationEntity, modifiedOptions, !String.IsNullOrWhiteSpace(encryptionDataString)); // Deserialize the old encryption data and validate: EncryptionData tableEncryptionData = Newtonsoft.Json.JsonConvert.DeserializeObject <EncryptionData>(encryptionDataString); if (tableEncryptionData.WrappedContentKey.EncryptedKey == null) { throw new InvalidOperationException(SR.KeyRotationNoKeyID); } // Use the key resolver to resolve the old KEK. Azure.KeyVault.Core.IKey oldKey = await modifiedOptions.EncryptionPolicy.KeyResolver.ResolveKeyAsync(tableEncryptionData.WrappedContentKey.KeyId, cancellationToken).ConfigureAwait(false); if (oldKey == null) { throw new ArgumentException(SR.KeyResolverCannotResolveExistingKey); } // Use the old KEK to unwrap the CEK. byte[] unwrappedOldKey = await oldKey.UnwrapKeyAsync(tableEncryptionData.WrappedContentKey.EncryptedKey, tableEncryptionData.WrappedContentKey.Algorithm, cancellationToken).ConfigureAwait(false); // Use the new KEK to re-wrap the CEK. Tuple <byte[], string> wrappedNewKeyTuple = await modifiedOptions.EncryptionPolicy.Key.WrapKeyAsync(unwrappedOldKey, null /* algorithm */, cancellationToken).ConfigureAwait(false); TaskCompletionSource <string> tcs = new TaskCompletionSource <string>(); tableEncryptionData.WrappedContentKey = new WrappedKey(modifiedOptions.EncryptionPolicy.Key.Kid, wrappedNewKeyTuple.Item1, wrappedNewKeyTuple.Item2); return(Newtonsoft.Json.JsonConvert.SerializeObject(tableEncryptionData)); }
public void TableQueryProjectionEncryptionNoSelect() { // Insert Entity EncryptedBaseEntity ent1 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() }; ent1.Populate(); EncryptedBaseEntity ent2 = new EncryptedBaseEntity() { PartitionKey = Guid.NewGuid().ToString(), RowKey = DateTime.Now.Ticks.ToString() }; ent2.Populate(); // Create the Key to be used for wrapping. SymmetricKey aesKey = new SymmetricKey("symencryptionkey"); TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = new TableEncryptionPolicy(aesKey, null) }; currentTable.Execute(TableOperation.Insert(ent1), options, null); currentTable.Execute(TableOperation.Insert(ent2), options, null); tableClient.DefaultRequestOptions.PayloadFormat = TablePayloadFormat.Json; // Create the resolver to be used for unwrapping. DictionaryKeyResolver resolver = new DictionaryKeyResolver(); resolver.Add(aesKey); TableEncryptionPolicy encryptionPolicy = new TableEncryptionPolicy(null, resolver); IEnumerable<EncryptedBaseEntity> entities = null; CloudTableClient encryptingTableClient = new CloudTableClient(this.tableClient.StorageUri, this.tableClient.Credentials); encryptingTableClient.DefaultRequestOptions.EncryptionPolicy = encryptionPolicy; encryptingTableClient.DefaultRequestOptions.RequireEncryption = true; entities = encryptingTableClient.GetTableReference(currentTable.Name).CreateQuery<EncryptedBaseEntity>().Select(ent => ent); foreach (EncryptedBaseEntity ent in entities) { ent.Validate(); } }
public void CloudTableEncryptionCrossPlatformTesting() { CloudTable testTable = this.tableClient.GetTableReference(GenerateRandomTableName()); try { testTable.CreateIfNotExists(); // Hard code some sample data, then see if we can decrypt it. // This key is used only for test, do not use to encrypt any sensitive data. SymmetricKey sampleKEK = new SymmetricKey("key1", Convert.FromBase64String(@"rFz7+tv4hRiWdWUJMFlxl1xxtU/qFUeTriGaxwEcxjU=")); // This data here was created using Fiddler to capture the .NET library uploading an encrypted entity, encrypted with the specified KEK and CEK. // Note that this data is lacking the library information in the KeyWrappingMetadata. DynamicTableEntity dteNetOld = new DynamicTableEntity("pk", "netUp"); dteNetOld.Properties["sampleProp"] = new EntityProperty(Convert.FromBase64String(@"27cLSlSFqy9C0xUCr57XAA==")); dteNetOld.Properties["sampleProp2"] = new EntityProperty(Convert.FromBase64String(@"pZR6Ln/DwbwyyOCEezL/hg==")); dteNetOld.Properties["sampleProp3"] = new EntityProperty(Convert.FromBase64String(@"JOix4N8eX/WuCtIvlD2QxQ==")); dteNetOld.Properties["_ClientEncryptionMetadata1"] = new EntityProperty("{\"WrappedContentKey\":{\"KeyId\":\"key1\",\"EncryptedKey\":\"pwSKxpJkwCS2zCaykh0m8e4OApeLuQ4FiahZ9zdwxaLL1HsWqQ4DSw==\",\"Algorithm\":\"A256KW\"},\"EncryptionAgent\":{\"Protocol\":\"1.0\",\"EncryptionAlgorithm\":\"AES_CBC_256\"},\"ContentEncryptionIV\":\"obTAQcYeFQ3IU7Jfcema7Q==\",\"KeyWrappingMetadata\":{}}"); dteNetOld.Properties["_ClientEncryptionMetadata2"] = new EntityProperty(Convert.FromBase64String(@"MWA7LlvXSJnKhf8f7MVhfjWECkxrCyCXGIlYY6ucpr34IVDU7fN6IHvKxV15WiXp")); testTable.Execute(TableOperation.Insert(dteNetOld)); // This data here was created using Fiddler to capture the Java library uploading an encrypted entity, encrypted with the specified KEK and CEK. // Note that this data is lacking the KeyWrappingMetadata. It also constructs an IV with PK + RK + column name. DynamicTableEntity dteJavaOld = new DynamicTableEntity("pk", "javaUp"); dteJavaOld.Properties["sampleProp"] = new EntityProperty(Convert.FromBase64String(@"sa3bCvXq79ImSPveChS+cg==")); dteJavaOld.Properties["sampleProp2"] = new EntityProperty(Convert.FromBase64String(@"KXjuBNn9DesCmMcdVpamJw==")); dteJavaOld.Properties["sampleProp3"] = new EntityProperty(Convert.FromBase64String(@"wykVEni1rV+H6oNjoNml6A==")); dteJavaOld.Properties["_ClientEncryptionMetadata1"] = new EntityProperty("{\"WrappedContentKey\":{\"KeyId\":\"key1\",\"EncryptedKey\":\"2F4rIuDmGPgEmhpvTtE7x6281BetKz80EsgRwGxTjL8rRt7Z7GrOgg==\",\"Algorithm\":\"A256KW\"},\"EncryptionAgent\":{\"Protocol\":\"1.0\",\"EncryptionAlgorithm\":\"AES_CBC_256\"},\"ContentEncryptionIV\":\"8st/uXffG+6DxBhw4D1URw==\"}"); dteJavaOld.Properties["_ClientEncryptionMetadata2"] = new EntityProperty(Convert.FromBase64String(@"WznUoytxkvl9KhZ4mNlqkBvRTUHN/D5IgJmNl7kQBOtFBOSgZZrTfZXKH8GjmvKA")); testTable.Execute(TableOperation.Insert(dteJavaOld)); TableEncryptionPolicy policy = new TableEncryptionPolicy(sampleKEK, null); TableRequestOptions options = new TableRequestOptions() { EncryptionPolicy = policy }; options.EncryptionResolver = (pk, rk, propName) => true; foreach (DynamicTableEntity dte in testTable.ExecuteQuery(new TableQuery(), options)) { Assert.AreEqual(dte.Properties["sampleProp"].StringValue, "sampleValue", "String not properly decoded."); Assert.AreEqual(dte.Properties["sampleProp2"].StringValue, "sampleValue", "String not properly decoded."); Assert.AreEqual(dte.Properties["sampleProp3"].StringValue, "sampleValue", "String not properly decoded."); Assert.AreEqual(dte.Properties.Count, 3, "Incorrect number of properties returned."); } } finally { testTable.DeleteIfExists(); } }