public void ThrowWhenDecryptingLessThanSixtyFiveBytes(byte[] ciphertext) { DataEncryptionKey encryptionKey = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey); AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Deterministic); Assert.Throws <ArgumentException>(() => encryptionAlgorithm.Decrypt(ciphertext)); }
private async Task DecryptObjectAsync( JObject document, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { Debug.Assert(diagnosticsContext != null); foreach (ClientEncryptionIncludedPath path in this.ClientEncryptionPolicy.IncludedPaths) { if (document.TryGetValue(path.Path.Substring(1), out JToken propertyValue)) { string propertyName = path.Path.Substring(1); EncryptionSettingForProperty settingsForProperty = await this.EncryptionSettings.GetEncryptionSettingForPropertyAsync(propertyName, cancellationToken); if (settingsForProperty == null) { throw new ArgumentException($"Invalid Encryption Setting for Property:{propertyName}. "); } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken); this.DecryptProperty( document, aeadAes256CbcHmac256EncryptionAlgorithm, propertyName, propertyValue); } } return; }
private JToken DecryptAndDeserializeValue( JToken jToken, AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm) { byte[] cipherTextWithTypeMarker = jToken.ToObject <byte[]>(); if (cipherTextWithTypeMarker == null) { return(null); } byte[] cipherText = new byte[cipherTextWithTypeMarker.Length - 1]; Buffer.BlockCopy(cipherTextWithTypeMarker, 1, cipherText, 0, cipherTextWithTypeMarker.Length - 1); byte[] plainText = aeadAes256CbcHmac256EncryptionAlgorithm.Decrypt(cipherText); if (plainText == null) { throw new InvalidOperationException($"{nameof(this.DecryptAndDeserializeValue)} returned null plainText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Decrypt)}. "); } return(DeserializeAndAddProperty( plainText, (TypeMarker)cipherTextWithTypeMarker[0])); }
private JToken SerializeAndEncryptValue( JToken jToken, AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm) { JToken propertyValueToEncrypt = jToken; if (propertyValueToEncrypt.Type == JTokenType.Null) { return(propertyValueToEncrypt); } (TypeMarker typeMarker, byte[] plainText) = Serialize(propertyValueToEncrypt); byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(plainText); if (cipherText == null) { throw new InvalidOperationException($"{nameof(this.SerializeAndEncryptValue)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. "); } byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1]; cipherTextWithTypeMarker[0] = (byte)typeMarker; Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length); return(cipherTextWithTypeMarker); }
internal static async Task <Stream> EncryptValueStreamAsync( Stream valueStream, EncryptionSettingForProperty settingsForProperty, CancellationToken cancellationToken) { if (valueStream == null) { throw new ArgumentNullException(nameof(valueStream)); } if (settingsForProperty == null) { throw new ArgumentNullException(nameof(settingsForProperty)); } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken); JToken propertyValueToEncrypt = EncryptionProcessor.BaseSerializer.FromStream <JToken>(valueStream); (EncryptionProcessor.TypeMarker typeMarker, byte[] serializedData) = EncryptionProcessor.Serialize(propertyValueToEncrypt); byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(serializedData); if (cipherText == null) { throw new InvalidOperationException($"{nameof(EncryptValueStreamAsync)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1]; cipherTextWithTypeMarker[0] = (byte)typeMarker; Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length); return(EncryptionProcessor.BaseSerializer.ToStream(cipherTextWithTypeMarker)); }
public async Task <AeadAes256CbcHmac256EncryptionAlgorithm> BuildEncryptionAlgorithmForSettingAsync(CancellationToken cancellationToken) { ClientEncryptionKeyProperties clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync( clientEncryptionKeyId : this.ClientEncryptionKeyId, encryptionContainer : this.encryptionContainer, databaseRid : this.databaseRid, ifNoneMatchEtag : null, shouldForceRefresh : false, cancellationToken : cancellationToken); ProtectedDataEncryptionKey protectedDataEncryptionKey; try { // we pull out the Encrypted Data Encryption Key and build the Protected Data Encryption key // Here a request is sent out to unwrap using the Master Key configured via the Key Encryption Key. protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync( clientEncryptionKeyProperties, this.ClientEncryptionKeyId, cancellationToken); } catch (RequestFailedException ex) when(ex.Status == (int)HttpStatusCode.Forbidden) { // The access to master key was probably revoked. Try to fetch the latest ClientEncryptionKeyProperties from the backend. // This will succeed provided the user has rewraped the Client Encryption Key with right set of meta data. // This is based on the AKV provider implementaion so we expect a RequestFailedException in case other providers are used in unwrap implementation. // first try to force refresh the local cache, we might have a stale cache. clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync( clientEncryptionKeyId : this.ClientEncryptionKeyId, encryptionContainer : this.encryptionContainer, databaseRid : this.databaseRid, ifNoneMatchEtag : null, shouldForceRefresh : true, cancellationToken : cancellationToken); try { // try to build the ProtectedDataEncryptionKey. If it fails, try to force refresh the gateway cache and get the latest client encryption key. protectedDataEncryptionKey = await this.BuildProtectedDataEncryptionKeyAsync( clientEncryptionKeyProperties, this.ClientEncryptionKeyId, cancellationToken); } catch (RequestFailedException exOnRetry) when(exOnRetry.Status == (int)HttpStatusCode.Forbidden) { // the gateway cache could be stale. Force refresh the gateway cache. // bail out if this fails. protectedDataEncryptionKey = await this.ForceRefreshGatewayCacheAndBuildProtectedDataEncryptionKeyAsync( existingCekEtag : clientEncryptionKeyProperties.ETag, refreshRetriedOnException : exOnRetry, cancellationToken : cancellationToken); } } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = new AeadAes256CbcHmac256EncryptionAlgorithm( protectedDataEncryptionKey, this.EncryptionType); return(aeadAes256CbcHmac256EncryptionAlgorithm); }
public void ThrowWhenDecryptionAnInvalidAuthenticationTag() { byte[] invalidAuthTag = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65 }; DataEncryptionKey encryptionKey = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey); AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Deterministic); Assert.Throws <CryptographicException>(() => encryptionAlgorithm.Decrypt(invalidAuthTag)); }
/// <summary> /// Initializes a new instance of MdeEncryptionAlgorithm. /// Uses <see cref="AeadAes256CbcHmac256EncryptionAlgorithm"/> which implements authenticated encryption algorithm with associated data as described /// <see href="http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05">here</see> . /// More specifically this implements AEAD_AES_256_CBC_HMAC_SHA256 algorithm. /// </summary> /// <param name="dataEncryptionKey"> Data Encryption Key </param> /// <param name="encryptionType"> Encryption type </param> public MdeEncryptionAlgorithm( Data.Encryption.Cryptography.DataEncryptionKey dataEncryptionKey, Data.Encryption.Cryptography.EncryptionType encryptionType) { this.mdeAeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate( dataEncryptionKey, encryptionType); }
public void ReturnNullWhenDecryptingNull() { DataEncryptionKey encryptionKey = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey); AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Deterministic); byte[] plaintext = encryptionAlgorithm.Decrypt(null); Assert.Null(plaintext); }
/// <summary> /// Initializes a new instance of MdeEncryptionAlgorithm. /// Uses <see cref="AeadAes256CbcHmac256EncryptionAlgorithm"/> which implements authenticated encryption algorithm with associated data as described /// <see href="http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05">here</see> . /// More specifically this implements AEAD_AES_256_CBC_HMAC_SHA256 algorithm. /// </summary> /// <param name="dekProperties"> Data Encryption Key properties</param> /// <param name="encryptionType"> Encryption type </param> /// <param name="encryptionKeyStoreProvider"> EncryptionKeyStoreProvider for wrapping and unwrapping </param> public MdeEncryptionAlgorithm( DataEncryptionKeyProperties dekProperties, Data.Encryption.Cryptography.EncryptionType encryptionType, EncryptionKeyStoreProvider encryptionKeyStoreProvider, TimeSpan?cacheTimeToLive) { if (dekProperties == null) { throw new ArgumentNullException(nameof(dekProperties)); } if (encryptionKeyStoreProvider == null) { throw new ArgumentNullException(nameof(encryptionKeyStoreProvider)); } KeyEncryptionKey keyEncryptionKey = KeyEncryptionKey.GetOrCreate( dekProperties.EncryptionKeyWrapMetadata.Name, dekProperties.EncryptionKeyWrapMetadata.Value, encryptionKeyStoreProvider); ProtectedDataEncryptionKey protectedDataEncryptionKey; if (cacheTimeToLive.HasValue) { // no caching if (cacheTimeToLive.Value == TimeSpan.Zero) { protectedDataEncryptionKey = new ProtectedDataEncryptionKey( dekProperties.Id, keyEncryptionKey, dekProperties.WrappedDataEncryptionKey); } else { protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate( dekProperties.Id, keyEncryptionKey, dekProperties.WrappedDataEncryptionKey); protectedDataEncryptionKey.TimeToLive = cacheTimeToLive.Value; } } else { protectedDataEncryptionKey = ProtectedDataEncryptionKey.GetOrCreate( dekProperties.Id, keyEncryptionKey, dekProperties.WrappedDataEncryptionKey); } this.mdeAeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate( protectedDataEncryptionKey, encryptionType); }
internal static IEnumerable <byte[]> Encrypt(this IEnumerable source, EncryptionSettings settings) { DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(settings.DataEncryptionKey, settings.EncryptionType); ISerializer serializer = settings.GetSerializer(); foreach (var item in source) { byte[] serializedData = serializer.Serialize(item); yield return(encryptionAlgorithm.Encrypt(serializedData)); } }
public async Task <AeadAes256CbcHmac256EncryptionAlgorithm> BuildEncryptionAlgorithmForSettingAsync(CancellationToken cancellationToken) { ClientEncryptionKeyProperties clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync( clientEncryptionKeyId : this.ClientEncryptionKeyId, encryptionContainer : this.encryptionContainer, databaseRid : this.databaseRid, cancellationToken : cancellationToken); ProtectedDataEncryptionKey protectedDataEncryptionKey; try { // we pull out the Encrypted Data Encryption Key and build the Protected Data Encryption key // Here a request is sent out to unwrap using the Master Key configured via the Key Encryption Key. protectedDataEncryptionKey = this.BuildProtectedDataEncryptionKey( clientEncryptionKeyProperties, this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider, this.ClientEncryptionKeyId); } catch (RequestFailedException ex) { // The access to master key was probably revoked. Try to fetch the latest ClientEncryptionKeyProperties from the backend. // This will succeed provided the user has rewraped the Client Encryption Key with right set of meta data. // This is based on the AKV provider implementaion so we expect a RequestFailedException in case other providers are used in unwrap implementation. if (ex.Status == (int)HttpStatusCode.Forbidden) { clientEncryptionKeyProperties = await this.encryptionContainer.EncryptionCosmosClient.GetClientEncryptionKeyPropertiesAsync( clientEncryptionKeyId : this.ClientEncryptionKeyId, encryptionContainer : this.encryptionContainer, databaseRid : this.databaseRid, cancellationToken : cancellationToken, shouldForceRefresh : true); // just bail out if this fails. protectedDataEncryptionKey = this.BuildProtectedDataEncryptionKey( clientEncryptionKeyProperties, this.encryptionContainer.EncryptionCosmosClient.EncryptionKeyStoreProvider, this.ClientEncryptionKeyId); } else { throw; } } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = new AeadAes256CbcHmac256EncryptionAlgorithm( protectedDataEncryptionKey, this.EncryptionType); return(aeadAes256CbcHmac256EncryptionAlgorithm); }
/// <remarks> /// If there isn't any PathsToEncrypt, input stream will be returned without any modification. /// Else input stream will be disposed, and a new stream is returned. /// In case of an exception, input stream won't be disposed, but position will be end of stream. /// </remarks> public async Task <Stream> EncryptAsync( Stream input, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { if (input == null) { throw new ArgumentNullException(nameof(input)); } Debug.Assert(diagnosticsContext != null); await this.InitEncryptionSettingsIfNotInitializedAsync(cancellationToken); if (this.ClientEncryptionPolicy == null) { return(input); } JObject itemJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(input); foreach (ClientEncryptionIncludedPath pathToEncrypt in this.ClientEncryptionPolicy.IncludedPaths) { string propertyName = pathToEncrypt.Path.Substring(1); // possibly a wrong path configured in the Client Encryption Policy, ignore. if (!itemJObj.TryGetValue(propertyName, out JToken propertyValue)) { continue; } EncryptionSettingForProperty settingforProperty = await this.EncryptionSettings.GetEncryptionSettingForPropertyAsync(propertyName, cancellationToken); if (settingforProperty == null) { throw new ArgumentException($"Invalid Encryption Setting for the Property:{propertyName}. "); } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingforProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken); this.EncryptProperty( itemJObj, propertyValue, aeadAes256CbcHmac256EncryptionAlgorithm); } input.Dispose(); return(EncryptionProcessor.BaseSerializer.ToStream(itemJObj)); }
internal static EncryptionSettings Create( EncryptionSettings settingsForKey, EncryptionType encryptionType) { return(new EncryptionSettings() { ClientEncryptionKeyId = settingsForKey.ClientEncryptionKeyId, DataEncryptionKey = settingsForKey.DataEncryptionKey, EncryptionType = encryptionType, EncryptionSettingTimeToLive = settingsForKey.EncryptionSettingTimeToLive, AeadAes256CbcHmac256EncryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate( settingsForKey.DataEncryptionKey, encryptionType), }); }
public void EncryptToSameCiphertextWhenDeterministicEncryptionTypeSelected(DataEncryptionKey encryptionKey) { EncryptionType encryptionType = EncryptionType.Deterministic; byte[] serializedPlaintext = new byte[] { 1, 2, 3, 4, 5 }; AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, encryptionType); byte[] ciphertext1 = encryptionAlgorithm.Encrypt(serializedPlaintext); byte[] ciphertext2 = encryptionAlgorithm.Encrypt(serializedPlaintext); byte[] ciphertext3 = encryptionAlgorithm.Encrypt(serializedPlaintext); Assert.Equal(ciphertext1, ciphertext2); Assert.Equal(ciphertext2, ciphertext3); Assert.Equal(ciphertext1, ciphertext3); }
public void EncryptToDifferentCiphertextWhenRandomizedEncryptionTypeSelected(DataEncryptionKey encryptionKey) { EncryptionType encryptionType = EncryptionType.Randomized; byte[] serializedPlaintext = new byte[] { 1, 2, 3, 4, 5 }; AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, encryptionType); byte[] ciphertext1 = encryptionAlgorithm.Encrypt(serializedPlaintext); byte[] ciphertext2 = encryptionAlgorithm.Encrypt(serializedPlaintext); byte[] ciphertext3 = encryptionAlgorithm.Encrypt(serializedPlaintext); Assert.NotEqual(ciphertext1, ciphertext2); Assert.NotEqual(ciphertext2, ciphertext3); Assert.NotEqual(ciphertext1, ciphertext3); }
internal static IList Decrypt(this IEnumerable source, EncryptionSettings settings) { DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(settings.DataEncryptionKey, settings.EncryptionType); ISerializer serializer = settings.GetSerializer(); Type type = serializer.GetType().BaseType.GetGenericArguments()[0]; IList list = (IList)Activator.CreateInstance(typeof(List <>).MakeGenericType(type)); foreach (var item in source) { byte[] plaintextData = encryptionAlgorithm.Decrypt((byte[])item); list.Add(serializer.Deserialize(plaintextData)); } return(list); }
/// <remarks> /// If there isn't any PathsToEncrypt, input stream will be returned without any modification. /// Else input stream will be disposed, and a new stream is returned. /// In case of an exception, input stream won't be disposed, but position will be end of stream. /// </remarks> public static async Task <Stream> EncryptAsync( Stream input, EncryptionSettings encryptionSettings, CosmosDiagnosticsContext diagnosticsContext, CancellationToken cancellationToken) { if (input == null) { throw new ArgumentNullException(nameof(input)); } Debug.Assert(diagnosticsContext != null); JObject itemJObj = EncryptionProcessor.BaseSerializer.FromStream <JObject>(input); foreach (string propertyName in encryptionSettings.PropertiesToEncrypt) { // possibly a wrong path configured in the Client Encryption Policy, ignore. if (!itemJObj.TryGetValue(propertyName, out JToken propertyValue)) { continue; } EncryptionSettingForProperty settingforProperty = encryptionSettings.GetEncryptionSettingForProperty(propertyName); if (settingforProperty == null) { throw new ArgumentException($"Invalid Encryption Setting for the Property:{propertyName}. "); } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingforProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken); EncryptProperty( itemJObj, propertyValue, aeadAes256CbcHmac256EncryptionAlgorithm); } input.Dispose(); return(EncryptionProcessor.BaseSerializer.ToStream(itemJObj)); }
public void CacheEncryptionAlgorithmsCorrectlyWhenCallingGetOrCreate() { DataEncryptionKey key1 = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey); DataEncryptionKey key2 = new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey); DataEncryptionKey key3 = new ProtectedDataEncryptionKey("Not_EK", keyEncryptionKey, encryptedDataEncryptionKey); AeadAes256CbcHmac256EncryptionAlgorithm algorithm1 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key1, EncryptionType.Deterministic); AeadAes256CbcHmac256EncryptionAlgorithm algorithm2 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key2, EncryptionType.Deterministic); Assert.Same(algorithm1, algorithm2); AeadAes256CbcHmac256EncryptionAlgorithm algorithm3 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key1, EncryptionType.Deterministic); AeadAes256CbcHmac256EncryptionAlgorithm algorithm4 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key2, EncryptionType.Randomized); Assert.NotSame(algorithm3, algorithm4); AeadAes256CbcHmac256EncryptionAlgorithm algorithm5 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key1, EncryptionType.Randomized); AeadAes256CbcHmac256EncryptionAlgorithm algorithm6 = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(key3, EncryptionType.Randomized); Assert.NotSame(algorithm5, algorithm6); }
public void EncryptAndDecryptToTheSameValue <T>(T originalPlaintext, Serializer <T> serializer) { DataEncryptionKey[] keys = { new ProtectedDataEncryptionKey("EK", keyEncryptionKey, encryptedDataEncryptionKey), new PlaintextDataEncryptionKey("EK", plaintextEncryptionKeyBytes) }; foreach (DataEncryptionKey encryptionKey in keys) { EncryptionType encryptionType = (EncryptionType)random.Next(1, 2); AeadAes256CbcHmac256EncryptionAlgorithm encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, encryptionType); byte[] serializedPlaintext = serializer.Serialize(originalPlaintext); byte[] ciphhertext = encryptionAlgorithm.Encrypt(serializedPlaintext); byte[] decryptedPlaintext = encryptionAlgorithm.Decrypt(ciphhertext); T actualPlaintext = serializer.Deserialize(decryptedPlaintext); Assert.Equal(originalPlaintext, actualPlaintext); } }
private void EncryptProperty( JObject itemJObj, JToken propertyValue, AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm) { /* Top Level can be an Object*/ if (propertyValue.Type == JTokenType.Object) { foreach (JProperty jProperty in propertyValue.Children <JProperty>()) { if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array) { this.EncryptProperty( itemJObj, jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm); } else { jProperty.Value = this.SerializeAndEncryptValue(jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm); } } } else if (propertyValue.Type == JTokenType.Array) { if (propertyValue.Children().Any()) { // objects as array elements. if (propertyValue.Children().First().Type == JTokenType.Object) { foreach (JObject arrayjObject in propertyValue.Children <JObject>()) { foreach (JProperty jProperty in arrayjObject.Properties()) { if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array) { this.EncryptProperty( itemJObj, jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm); } // primitive type else { jProperty.Value = this.SerializeAndEncryptValue(jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm); } } } } // array as elements. else if (propertyValue.Children().First().Type == JTokenType.Array) { foreach (JArray jArray in propertyValue.Value <JArray>()) { for (int i = 0; i < jArray.Count(); i++) { // iterates over individual elements if (jArray[i].Type == JTokenType.Object || jArray[i].Type == JTokenType.Array) { this.EncryptProperty( itemJObj, jArray[i], aeadAes256CbcHmac256EncryptionAlgorithm); } // primitive type else { jArray[i] = this.SerializeAndEncryptValue(jArray[i], aeadAes256CbcHmac256EncryptionAlgorithm); } } } } // array of primitive types. else { for (int i = 0; i < propertyValue.Count(); i++) { propertyValue[i] = this.SerializeAndEncryptValue(propertyValue[i], aeadAes256CbcHmac256EncryptionAlgorithm); } } } } else { itemJObj.Property(propertyValue.Path).Value = this.SerializeAndEncryptValue( itemJObj.Property(propertyValue.Path).Value, aeadAes256CbcHmac256EncryptionAlgorithm); } }
private void DecryptProperty( JObject itemJObj, AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm, string propertyName, JToken propertyValue) { if (propertyValue.Type == JTokenType.Object) { foreach (JProperty jProperty in propertyValue.Children <JProperty>()) { if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array) { this.DecryptProperty( itemJObj, aeadAes256CbcHmac256EncryptionAlgorithm, jProperty.Name, jProperty.Value); } else { jProperty.Value = this.DecryptAndDeserializeValue( jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm); } } } else if (propertyValue.Type == JTokenType.Array) { if (propertyValue.Children().Any()) { if (propertyValue.Children().First().Type == JTokenType.Object) { foreach (JObject arrayjObject in propertyValue.Children <JObject>()) { foreach (JProperty jProperty in arrayjObject.Properties()) { if (jProperty.Value.Type == JTokenType.Object || jProperty.Value.Type == JTokenType.Array) { this.DecryptProperty( itemJObj, aeadAes256CbcHmac256EncryptionAlgorithm, jProperty.Name, jProperty.Value); } else { jProperty.Value = this.DecryptAndDeserializeValue( jProperty.Value, aeadAes256CbcHmac256EncryptionAlgorithm); } } } } else if (propertyValue.Children().First().Type == JTokenType.Array) { foreach (JArray jArray in propertyValue.Value <JArray>()) { for (int i = 0; i < jArray.Count(); i++) { // iterates over individual elements if (jArray[i].Type == JTokenType.Object || jArray[i].Type == JTokenType.Array) { this.DecryptProperty( itemJObj, aeadAes256CbcHmac256EncryptionAlgorithm, jArray[i].Path, jArray[i]); } else { jArray[i] = this.DecryptAndDeserializeValue( jArray[i], aeadAes256CbcHmac256EncryptionAlgorithm); } } } } // primitive type else { for (int i = 0; i < propertyValue.Count(); i++) { propertyValue[i] = this.DecryptAndDeserializeValue( propertyValue[i], aeadAes256CbcHmac256EncryptionAlgorithm); } } } } else { itemJObj.Property(propertyName).Value = this.DecryptAndDeserializeValue( itemJObj.Property(propertyName).Value, aeadAes256CbcHmac256EncryptionAlgorithm); } }
/// <summary> /// Gets a QueryDefinition with Encrypted Parameters. /// </summary> /// <param name="queryDefinition"> Query Definition to be replaced with Encrypted Values.</param> /// <param name="name"> Query Paramerter Name. </param> /// <param name="value"> Query Paramerter Value.</param> /// <param name="path"> Encrypted Property Path. </param> /// <param name="cancellationToken"> cancellation token </param> /// <returns> QueryDefinition with encrypted parameters. </returns> /// <example> /// This example shows how to pass in a QueryDefinition with Encryption support to AddParameterAsync /// to encrypt the required Property for running Query on encrypted data. /// /// <code language="c#"> /// <![CDATA[ /// containerWithEncryption = await this.cosmosDatabase.GetContainer("id").InitializeEncryptionAsync(); /// QueryDefinition withEncryptedParameter = containerWithEncryption.CreateQueryDefinition( /// "SELECT * FROM c where c.PropertyName = @PropertyValue"); /// await withEncryptedParameter.AddParameterAsync( /// "@PropertyName", /// PropertyValue, /// "/PropertyName"); /// ]]> /// </code> /// </example> public static async Task <QueryDefinition> AddParameterAsync( this QueryDefinition queryDefinition, string name, object value, string path, CancellationToken cancellationToken = default) { cancellationToken.ThrowIfCancellationRequested(); if (queryDefinition == null) { throw new ArgumentNullException(nameof(queryDefinition)); } if (string.IsNullOrWhiteSpace(path) || path[0] != '/' || path.LastIndexOf('/') != 0) { throw new InvalidOperationException($"Invalid path {path ?? string.Empty}, {nameof(path)}. "); } if (string.IsNullOrWhiteSpace(name)) { throw new ArgumentNullException(nameof(name)); } if (value == null) { throw new ArgumentNullException(nameof(value)); } QueryDefinition queryDefinitionwithEncryptedValues = queryDefinition; if (queryDefinition is EncryptionQueryDefinition encryptionQueryDefinition) { EncryptionContainer encryptionContainer = (EncryptionContainer)encryptionQueryDefinition.Container; Stream valueStream = encryptionContainer.CosmosSerializer.ToStream(value); // not really required, but will have things setup for subsequent queries or operations on this Container if the Container was never init // or if this was the first operation carried out on this container. await encryptionContainer.EncryptionProcessor.InitEncryptionSettingsIfNotInitializedAsync(cancellationToken); // get the path's encryption setting. EncryptionSettingForProperty settingsForProperty = await encryptionContainer.EncryptionProcessor.EncryptionSettings.GetEncryptionSettingForPropertyAsync( path.Substring(1), cancellationToken); if (settingsForProperty == null) { // property not encrypted. queryDefinitionwithEncryptedValues.WithParameter(name, value); return(queryDefinitionwithEncryptedValues); } if (settingsForProperty.EncryptionType == EncryptionType.Randomized) { throw new ArgumentException($"Unsupported argument with Path: {path} for query. For executing queries on encrypted path requires the use of deterministic encryption type. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } AeadAes256CbcHmac256EncryptionAlgorithm aeadAes256CbcHmac256EncryptionAlgorithm = await settingsForProperty.BuildEncryptionAlgorithmForSettingAsync(cancellationToken : cancellationToken); JToken propertyValueToEncrypt = EncryptionProcessor.BaseSerializer.FromStream <JToken>(valueStream); (EncryptionProcessor.TypeMarker typeMarker, byte[] serializedData) = EncryptionProcessor.Serialize(propertyValueToEncrypt); byte[] cipherText = aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt(serializedData); if (cipherText == null) { throw new InvalidOperationException($"{nameof(AddParameterAsync)} returned null cipherText from {nameof(aeadAes256CbcHmac256EncryptionAlgorithm.Encrypt)}. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } byte[] cipherTextWithTypeMarker = new byte[cipherText.Length + 1]; cipherTextWithTypeMarker[0] = (byte)typeMarker; Buffer.BlockCopy(cipherText, 0, cipherTextWithTypeMarker, 1, cipherText.Length); queryDefinitionwithEncryptedValues.WithParameter(name, cipherTextWithTypeMarker); return(queryDefinitionwithEncryptedValues); } else { throw new ArgumentException("Executing queries on encrypted path requires the use of an encryption - enabled client. Please refer to https://aka.ms/CosmosClientEncryption for more details. "); } }