diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/AzureKeyVaultKeyStoreProvider.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/AzureKeyVaultKeyStoreProvider.cs
new file mode 100644
index 0000000000..2c01f4fb17
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/AzureKeyVaultKeyStoreProvider.cs
@@ -0,0 +1,352 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+using System.Text;
+using Azure.Core;
+using Azure.Security.KeyVault.Keys.Cryptography;
+using Microsoft.Data.Encryption.Cryptography;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.AzureKeyVaultProvider
+{
+ ///
+ /// Implementation of key encryption key store provider that allows client applications to access data when a
+ /// key encryption key is stored in Microsoft Azure Key Vault.
+ ///
+ internal class AzureKeyVaultKeyStoreProvider : EncryptionKeyStoreProvider
+ {
+ #region Properties
+
+ ///
+ /// Name of the Encryption Key Store Provider implemetation
+ ///
+ public override string ProviderName { get; } = "AZURE_KEY_VAULT";
+
+ ///
+ /// Key storage and cryptography client
+ ///
+ private KeyCryptographer KeyCryptographer { get; set; }
+
+ ///
+ /// Algorithm version
+ ///
+ private readonly static byte[] firstVersion = new byte[] { 0x01 };
+
+ private readonly static KeyWrapAlgorithm keyWrapAlgorithm = KeyWrapAlgorithm.RsaOaep;
+
+ ///
+ /// List of Trusted Endpoints
+ ///
+ public readonly string[] TrustedEndPoints;
+
+ #endregion
+
+ #region Constructors
+ ///
+ /// Constructor that takes an implementation of Token Credential that is capable of providing an OAuth Token.
+ ///
+ ///
+ public AzureKeyVaultKeyStoreProvider(TokenCredential tokenCredential) :
+ this(tokenCredential, Constants.AzureKeyVaultPublicDomainNames)
+ { }
+
+ ///
+ /// Constructor that takes an implementation of Token Credential that is capable of providing an OAuth Token and a trusted endpoint.
+ ///
+ /// Instance of an implementation of Token Credential that is capable of providing an OAuth Token.
+ /// TrustedEndpoint is used to validate the key encryption key path.
+ public AzureKeyVaultKeyStoreProvider(TokenCredential tokenCredential, string trustedEndPoint) :
+ this(tokenCredential, new[] { trustedEndPoint })
+ { }
+
+ ///
+ /// Constructor that takes an instance of an implementation of Token Credential that is capable of providing an OAuth Token
+ /// and an array of trusted endpoints.
+ ///
+ /// Instance of an implementation of Token Credential that is capable of providing an OAuth Token
+ /// TrustedEndpoints are used to validate the key encryption key path
+ public AzureKeyVaultKeyStoreProvider(TokenCredential tokenCredential, string[] trustedEndPoints)
+ {
+ tokenCredential.ValidateNotNull(nameof(tokenCredential));
+ trustedEndPoints.ValidateNotNull(nameof(trustedEndPoints));
+ trustedEndPoints.ValidateNotEmpty(nameof(trustedEndPoints));
+ trustedEndPoints.ValidateNotNullOrWhitespaceForEach(nameof(trustedEndPoints));
+
+ KeyCryptographer = new KeyCryptographer(tokenCredential);
+ TrustedEndPoints = trustedEndPoints;
+ }
+ #endregion
+
+ #region Public methods
+
+ ///
+ /// Uses an asymmetric key identified by the key path to sign the key encryption key metadata consisting of (keyEncryptionKeyPath, allowEnclaveComputations bit, providerName).
+ ///
+ /// Identifier of an asymmetric key in Azure Key Vault.
+ /// Indicates whether the key encryption key supports enclave computations.
+ /// The signature of the key encryption key metadata.
+ public override byte[] Sign(string encryptionKeyId, bool allowEnclaveComputations)
+ {
+ ValidateNonEmptyAKVPath(encryptionKeyId, isSystemOp: false);
+
+ // Also validates key is of RSA type.
+ KeyCryptographer.AddKey(encryptionKeyId);
+ byte[] message = CompileKeyEncryptionKeyMetadata(encryptionKeyId, allowEnclaveComputations);
+ return KeyCryptographer.SignData(message, encryptionKeyId);
+ }
+
+ ///
+ /// Uses an asymmetric key identified by the key path to verify the key encryption key metadata consisting of (keyEncryptionKeyPath, allowEnclaveComputations bit, providerName).
+ ///
+ /// Identifier of an asymmetric key in Azure Key Vault
+ /// Indicates whether the key encryption key supports enclave computations.
+ /// The signature of the key encryption key metadata.
+ /// Boolean indicating whether the key encryption key metadata can be verified based on the provided signature.
+ public override bool Verify(string encryptionKeyId, bool allowEnclaveComputations, byte[] signature)
+ {
+ ValidateNonEmptyAKVPath(encryptionKeyId, isSystemOp: true);
+
+ var key = Tuple.Create(encryptionKeyId, allowEnclaveComputations, signature.ToHexString());
+ return GetOrCreateSignatureVerificationResult(key, VerifyKeyEncryptionKeyMetadata);
+
+ bool VerifyKeyEncryptionKeyMetadata()
+ {
+ // Also validates key is of RSA type.
+ KeyCryptographer.AddKey(encryptionKeyId);
+ byte[] message = CompileKeyEncryptionKeyMetadata(encryptionKeyId, allowEnclaveComputations);
+ return KeyCryptographer.VerifyData(message, signature, encryptionKeyId);
+ }
+ }
+
+ ///
+ /// This function uses the asymmetric key specified by the key path
+ /// and decrypts an encrypted data dencryption key with RSA encryption algorithm.
+ ///
+ /// Identifier of an asymmetric key in Azure Key Vault
+ /// The encryption algorithm.
+ /// The ciphertext key.
+ /// Plain text data encryption key
+ public override byte[] UnwrapKey(string encryptionKeyId, KeyEncryptionKeyAlgorithm algorithm, byte[] encryptedKey)
+ {
+ // Validate the input parameters
+ ValidateNonEmptyAKVPath(encryptionKeyId, isSystemOp: true);
+ ValidateEncryptionAlgorithm(algorithm);
+ encryptedKey.ValidateNotNull(nameof(encryptedKey));
+ encryptedKey.ValidateNotEmpty(nameof(encryptedKey));
+ ValidateVersionByte(encryptedKey[0], firstVersion[0]);
+
+ return GetOrCreateDataEncryptionKey(encryptedKey.ToHexString(), DecryptEncryptionKey);
+
+ byte[] DecryptEncryptionKey()
+ {
+ // Also validates whether the key is RSA one or not and then get the key size
+ KeyCryptographer.AddKey(encryptionKeyId);
+
+ int keySizeInBytes = KeyCryptographer.GetKeySize(encryptionKeyId);
+
+ // Get key path length
+ int currentIndex = firstVersion.Length;
+ ushort keyPathLength = BitConverter.ToUInt16(encryptedKey, currentIndex);
+ currentIndex += sizeof(ushort);
+
+ // Get ciphertext length
+ ushort cipherTextLength = BitConverter.ToUInt16(encryptedKey, currentIndex);
+ currentIndex += sizeof(ushort);
+
+ // Skip KeyPath
+ // KeyPath exists only for troubleshooting purposes and doesnt need validation.
+ currentIndex += keyPathLength;
+
+ // validate the ciphertext length
+ if (cipherTextLength != keySizeInBytes)
+ {
+ throw new MicrosoftDataEncryptionException(InvalidCiphertextLengthTemplate.FormatInvariant(cipherTextLength, keySizeInBytes, encryptionKeyId));
+ }
+
+ // Validate the signature length
+ int signatureLength = encryptedKey.Length - currentIndex - cipherTextLength;
+ if (signatureLength != keySizeInBytes)
+ {
+ throw new MicrosoftDataEncryptionException(InvalidSignatureLengthTemplate.FormatInvariant(signatureLength, keySizeInBytes, encryptionKeyId));
+ }
+
+ // Get ciphertext
+ byte[] cipherText = encryptedKey.Skip(currentIndex).Take(cipherTextLength).ToArray();
+ currentIndex += cipherTextLength;
+
+ // Get signature
+ byte[] signature = encryptedKey.Skip(currentIndex).Take(signatureLength).ToArray();
+
+ // Compute the message to validate the signature
+ byte[] message = encryptedKey.Take(encryptedKey.Length - signatureLength).ToArray();
+
+ if (null == message)
+ {
+ throw new MicrosoftDataEncryptionException(NullHash);
+ }
+
+ if (!KeyCryptographer.VerifyData(message, signature, encryptionKeyId))
+ {
+ throw new MicrosoftDataEncryptionException(InvalidSignatureTemplate.FormatInvariant(encryptionKeyId));
+ }
+
+ return KeyCryptographer.UnwrapKey(keyWrapAlgorithm, cipherText, encryptionKeyId);
+ }
+ }
+
+ ///
+ /// This function uses the asymmetric key specified by the key path
+ /// and encrypts an unencrypted data encryption key with RSA encryption algorithm.
+ ///
+ /// Identifier of an asymmetric key in Azure Key Vault
+ /// The encryption algorithm.
+ /// The plaintext key.
+ /// Encrypted data encryption key
+ public override byte[] WrapKey(string encryptionKeyId, KeyEncryptionKeyAlgorithm algorithm, byte[] key)
+ {
+ // Validate the input parameters
+ ValidateNonEmptyAKVPath(encryptionKeyId, isSystemOp: true);
+ ValidateEncryptionAlgorithm(algorithm);
+ key.ValidateNotNull(nameof(key));
+ ValidateDataEncryptionKeyNotEmpty(key);
+
+ // Also validates whether the key is RSA one or not and then get the key size
+ KeyCryptographer.AddKey(encryptionKeyId);
+ int keySizeInBytes = KeyCryptographer.GetKeySize(encryptionKeyId);
+
+ // Construct the encryptedDataEncryptionKey
+ // Format is
+ // firstVersion + keyPathLength + ciphertextLength + keyPath + ciphertext + signature
+
+ // Get the Unicode encoded bytes of cultureinvariant lower case keyEncryptionKeyPath
+ byte[] keyEncryptionKeyPathBytes = Encoding.Unicode.GetBytes(encryptionKeyId.ToLowerInvariant());
+ byte[] keyPathLength = BitConverter.GetBytes((short)keyEncryptionKeyPathBytes.Length);
+
+ // Encrypt the plain text
+ byte[] cipherText = KeyCryptographer.WrapKey(keyWrapAlgorithm, key, encryptionKeyId);
+ byte[] cipherTextLength = BitConverter.GetBytes((short)cipherText.Length);
+
+ if (cipherText.Length != keySizeInBytes)
+ {
+ throw new MicrosoftDataEncryptionException(CipherTextLengthMismatch);
+ }
+
+ // Compute message
+ // SHA-2-256(version + keyPathLength + ciphertextLength + keyPath + ciphertext)
+ byte[] message = firstVersion.Concat(keyPathLength).Concat(cipherTextLength).Concat(keyEncryptionKeyPathBytes).Concat(cipherText).ToArray();
+
+ // Sign the message
+ byte[] signature = KeyCryptographer.SignData(message, encryptionKeyId);
+
+ if (signature.Length != keySizeInBytes)
+ {
+ throw new MicrosoftDataEncryptionException(HashLengthMismatch);
+ }
+
+ ValidateSignature(encryptionKeyId, message, signature);
+
+ return message.Concat(signature).ToArray();
+ }
+
+ #endregion
+
+ #region Private methods
+
+ private void ValidateDataEncryptionKeyNotEmpty(byte[] encryptionKey)
+ {
+ if (encryptionKey.Length == 0)
+ {
+ throw new MicrosoftDataEncryptionException(EmptyDataEncryptionKey);
+ }
+ }
+
+ ///
+ /// Checks if the Azure Key Vault key path is Empty or Null (and raises exception if they are).
+ ///
+ internal void ValidateNonEmptyAKVPath(string keyEncryptionKeyPath, bool isSystemOp)
+ {
+ // throw appropriate error if keyEncryptionKeyPath is null or empty
+ if (string.IsNullOrWhiteSpace(keyEncryptionKeyPath))
+ {
+ string errorMessage = null == keyEncryptionKeyPath
+ ? NullAkvPath
+ : InvalidAkvPathTemplate.FormatInvariant(keyEncryptionKeyPath);
+
+ if (isSystemOp)
+ {
+ throw new MicrosoftDataEncryptionException(errorMessage);
+ }
+
+ throw new MicrosoftDataEncryptionException(errorMessage);
+ }
+
+
+ if (!Uri.TryCreate(keyEncryptionKeyPath, UriKind.Absolute, out Uri parsedUri) || parsedUri.Segments.Length < 3)
+ {
+ // Return an error indicating that the AKV url is invalid.
+ throw new MicrosoftDataEncryptionException(InvalidAkvUrlTemplate.FormatInvariant(keyEncryptionKeyPath));
+ }
+
+ // A valid URI.
+ // Check if it is pointing to trusted endpoint.
+ foreach (string trustedEndPoint in TrustedEndPoints)
+ {
+ if (parsedUri.Host.EndsWith(trustedEndPoint, StringComparison.OrdinalIgnoreCase))
+ {
+ return;
+ }
+ }
+
+ // Return an error indicating that the AKV url is invalid.
+ throw new MicrosoftDataEncryptionException(InvalidAkvKeyPathTrustedTemplate.FormatInvariant(keyEncryptionKeyPath, string.Join(", ", TrustedEndPoints.ToArray())));
+ }
+
+ private void ValidateSignature(string keyEncryptionKeyPath, byte[] message, byte[] signature)
+ {
+ if (!KeyCryptographer.VerifyData(message, signature, keyEncryptionKeyPath))
+ {
+ throw new MicrosoftDataEncryptionException(InvalidSignature);
+ }
+ }
+
+ private byte[] CompileKeyEncryptionKeyMetadata(string keyEncryptionKeyPath, bool allowEnclaveComputations)
+ {
+ string keyEncryptionKeyMetadata = ProviderName + keyEncryptionKeyPath + allowEnclaveComputations;
+ return Encoding.Unicode.GetBytes(keyEncryptionKeyMetadata.ToLowerInvariant());
+ }
+
+
+ internal static void ValidateEncryptionAlgorithm(KeyEncryptionKeyAlgorithm encryptionAlgorithm)
+ {
+ if (encryptionAlgorithm != KeyEncryptionKeyAlgorithm.RSA_OAEP)
+ {
+ throw new MicrosoftDataEncryptionException(InvalidKeyAlgorithm.FormatInvariant(encryptionAlgorithm, KeyEncryptionKeyAlgorithm.RSA_OAEP.ToString()));
+ }
+ }
+
+ internal static void ValidateVersionByte(byte encryptedByte, byte firstVersionByte)
+ {
+ // Validate and decrypt the EncryptedDataEncryptionKey
+ // Format is
+ // version + keyPathLength + ciphertextLength + keyPath + ciphertext + signature
+ //
+ // keyPath is present in the encrypted data encryption key for identifying the original source of the asymmetric key pair and
+ // we will not validate it against the data contained in the KEK metadata (keyEncryptionKeyPath).
+
+ // Validate the version byte
+ if (encryptedByte != firstVersionByte)
+ {
+ throw new MicrosoftDataEncryptionException(InvalidAlgorithmVersionTemplate.FormatInvariant(encryptedByte.ToString(@"X2"), firstVersionByte.ToString("X2")));
+ }
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/Constants.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/Constants.cs
new file mode 100644
index 0000000000..b8db49e2a2
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/Constants.cs
@@ -0,0 +1,26 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.AzureKeyVaultProvider
+{
+ internal static class Constants
+ {
+ ///
+ /// Azure Key Vault Domain Name
+ ///
+ internal static readonly string[] AzureKeyVaultPublicDomainNames = new string[] {
+ @"vault.azure.net", // default
+ @"vault.azure.cn", // Azure China
+ @"vault.usgovcloudapi.net", // US Government
+ @"vault.microsoftazure.de", // Azure Germany
+ @"managedhsm.azure.net", // public HSM vault
+ @"managedhsm.azure.cn", // Azure China HSM vault
+ @"managedhsm.usgovcloudapi.net", // US Government HSM vault
+ @"managedhsm.microsoftazure.de" // Azure Germany HSM vault
+ };
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/KeyCryptographer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/KeyCryptographer.cs
new file mode 100644
index 0000000000..5e065861ee
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/AzureKeyVaultProvider/KeyCryptographer.cs
@@ -0,0 +1,226 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using Azure;
+using Azure.Core;
+using Azure.Security.KeyVault.Keys;
+using Azure.Security.KeyVault.Keys.Cryptography;
+using System;
+using System.Collections.Concurrent;
+using System.Threading.Tasks;
+
+using static Azure.Security.KeyVault.Keys.Cryptography.SignatureAlgorithm;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.AzureKeyVaultProvider
+{
+ internal class KeyCryptographer
+ {
+ ///
+ /// TokenCredential to be used with the KeyClient
+ ///
+ private TokenCredential TokenCredential { get; set; }
+
+ ///
+ /// A mapping of the KeyClient objects to the corresponding Azure Key Vault URI
+ ///
+ private readonly ConcurrentDictionary _keyClientDictionary = new ConcurrentDictionary();
+
+ ///
+ /// Holds references to the fetch key tasks and maps them to their corresponding Azure Key Vault Key Identifier (URI).
+ /// These tasks will be used for returning the key in the event that the fetch task has not finished depositing the
+ /// key into the key dictionary.
+ ///
+ private readonly ConcurrentDictionary>> _keyFetchTaskDictionary = new ConcurrentDictionary>>();
+
+ ///
+ /// Holds references to the Azure Key Vault keys and maps them to their corresponding Azure Key Vault Key Identifier (URI).
+ ///
+ private readonly ConcurrentDictionary _keyDictionary = new ConcurrentDictionary();
+
+ ///
+ /// Holds references to the Azure Key Vault CryptographyClient objects and maps them to their corresponding Azure Key Vault Key Identifier (URI).
+ ///
+ private readonly ConcurrentDictionary _cryptoClientDictionary = new ConcurrentDictionary();
+
+ ///
+ /// Constructs a new KeyCryptographer
+ ///
+ ///
+ internal KeyCryptographer(TokenCredential tokenCredential)
+ {
+ TokenCredential = tokenCredential;
+ }
+
+ ///
+ /// Adds the key, specified by the Key Identifier URI, to the cache.
+ ///
+ ///
+ internal void AddKey(string keyIdentifierUri)
+ {
+ if (TheKeyHasNotBeenCached(keyIdentifierUri))
+ {
+ ParseAKVPath(keyIdentifierUri, out Uri vaultUri, out string keyName, out string keyVersion);
+ CreateKeyClient(vaultUri);
+ FetchKey(vaultUri, keyName, keyVersion, keyIdentifierUri);
+ }
+
+ bool TheKeyHasNotBeenCached(string k) => !_keyDictionary.ContainsKey(k) && !_keyFetchTaskDictionary.ContainsKey(k);
+ }
+
+ ///
+ /// Returns the key specified by the Key Identifier URI
+ ///
+ ///
+ ///
+ internal KeyVaultKey GetKey(string keyIdentifierUri)
+ {
+ if (_keyDictionary.ContainsKey(keyIdentifierUri))
+ {
+ _keyDictionary.TryGetValue(keyIdentifierUri, out KeyVaultKey key);
+ return key;
+ }
+
+ if (_keyFetchTaskDictionary.ContainsKey(keyIdentifierUri))
+ {
+ _keyFetchTaskDictionary.TryGetValue(keyIdentifierUri, out Task> task);
+ return Task.Run(() => task).GetAwaiter().GetResult();
+ }
+
+ // Not a public exception - not likely to occur.
+ throw new MicrosoftDataEncryptionException(AzureKeyVaultKeyNotFound.Format(keyIdentifierUri));
+ }
+
+ ///
+ /// Gets the public Key size in bytes.
+ ///
+ /// The key vault key identifier URI
+ ///
+ internal int GetKeySize(string keyIdentifierUri)
+ {
+ return GetKey(keyIdentifierUri).Key.N.Length;
+ }
+
+ ///
+ /// Generates signature based on RSA PKCS#v1.5 scheme using a specified Azure Key Vault Key URL.
+ ///
+ /// The data to sign
+ /// The key vault key identifier URI
+ ///
+ internal byte[] SignData(byte[] message, string keyIdentifierUri)
+ {
+ CryptographyClient cryptographyClient = GetCryptographyClient(keyIdentifierUri);
+ return cryptographyClient.SignData(RS256, message).Signature;
+ }
+
+ internal bool VerifyData(byte[] message, byte[] signature, string keyIdentifierUri)
+ {
+ CryptographyClient cryptographyClient = GetCryptographyClient(keyIdentifierUri);
+ return cryptographyClient.VerifyData(RS256, message, signature).IsValid;
+ }
+
+ internal byte[] UnwrapKey(KeyWrapAlgorithm keyWrapAlgorithm, byte[] encryptedKey, string keyIdentifierUri)
+ {
+ CryptographyClient cryptographyClient = GetCryptographyClient(keyIdentifierUri);
+ return cryptographyClient.UnwrapKey(keyWrapAlgorithm, encryptedKey).Key;
+ }
+
+ internal byte[] WrapKey(KeyWrapAlgorithm keyWrapAlgorithm, byte[] key, string keyIdentifierUri)
+ {
+ CryptographyClient cryptographyClient = GetCryptographyClient(keyIdentifierUri);
+ return cryptographyClient.WrapKey(keyWrapAlgorithm, key).EncryptedKey;
+ }
+
+ private CryptographyClient GetCryptographyClient(string keyIdentifierUri)
+ {
+ if (_cryptoClientDictionary.ContainsKey(keyIdentifierUri))
+ {
+ _cryptoClientDictionary.TryGetValue(keyIdentifierUri, out CryptographyClient client);
+ return client;
+ }
+
+ CryptographyClient cryptographyClient = new CryptographyClient(GetKey(keyIdentifierUri).Id, TokenCredential);
+ _cryptoClientDictionary.TryAdd(keyIdentifierUri, cryptographyClient);
+
+ return cryptographyClient;
+ }
+
+ ///
+ ///
+ ///
+ /// The Azure Key Vault URI
+ /// The name of the Azure Key Vault key
+ /// The version of the Azure Key Vault key
+ /// The Azure Key Vault key identifier
+ private void FetchKey(Uri vaultUri, string keyName, string keyVersion, string keyResourceUri)
+ {
+ Task> fetchKeyTask = FetchKeyFromKeyVault(vaultUri, keyName, keyVersion);
+ _keyFetchTaskDictionary.AddOrUpdate(keyResourceUri, fetchKeyTask, (k, v) => fetchKeyTask);
+
+ fetchKeyTask
+ .ContinueWith(k => ValidateRsaKey(k.GetAwaiter().GetResult()))
+ .ContinueWith(k => _keyDictionary.AddOrUpdate(keyResourceUri, k.GetAwaiter().GetResult(), (key, v) => k.GetAwaiter().GetResult()));
+
+ Task.Run(() => fetchKeyTask);
+ }
+
+ ///
+ /// Looks up the KeyClient object by it's URI and then fetches the key by name.
+ ///
+ /// The Azure Key Vault URI
+ /// Then name of the key
+ /// Then version of the key
+ ///
+ private Task> FetchKeyFromKeyVault(Uri vaultUri, string keyName, string keyVersion)
+ {
+ _keyClientDictionary.TryGetValue(vaultUri, out KeyClient keyClient);
+ return keyClient.GetKeyAsync(keyName, keyVersion);
+ }
+
+ ///
+ /// Validates that a key is of type RSA
+ ///
+ ///
+ ///
+ private KeyVaultKey ValidateRsaKey(KeyVaultKey key)
+ {
+ if (key.KeyType != KeyType.Rsa && key.KeyType != KeyType.RsaHsm)
+ {
+ throw new MicrosoftDataEncryptionException(NonRsaKeyTemplate.Format(key.KeyType));
+ }
+
+ return key;
+ }
+
+ ///
+ /// Instantiates and adds a KeyClient to the KeyClient dictionary
+ ///
+ /// The Azure Key Vault URI
+ private void CreateKeyClient(Uri vaultUri)
+ {
+ if (!_keyClientDictionary.ContainsKey(vaultUri))
+ {
+ _keyClientDictionary.TryAdd(vaultUri, new KeyClient(vaultUri, TokenCredential));
+ }
+ }
+
+ ///
+ /// Validates and parses the Azure Key Vault URI and key name.
+ ///
+ /// The Azure Key Vault key identifier
+ /// The Azure Key Vault URI
+ /// The name of the key
+ /// The version of the key
+ private void ParseAKVPath(string keyEncryptionKeyPath, out Uri vaultUri, out string keyEncryptionKeyName, out string keyEncryptionKeyVersion)
+ {
+ Uri masterKeyPathUri = new Uri(keyEncryptionKeyPath);
+ vaultUri = new Uri(masterKeyPathUri.GetLeftPart(UriPartial.Authority));
+ keyEncryptionKeyName = masterKeyPathUri.Segments[2];
+ keyEncryptionKeyVersion = masterKeyPathUri.Segments.Length > 3 ? masterKeyPathUri.Segments[3] : null;
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/AeadAes256CbcHmac256EncryptionAlgorithm.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/AeadAes256CbcHmac256EncryptionAlgorithm.cs
new file mode 100644
index 0000000000..5fa45c8c10
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/AeadAes256CbcHmac256EncryptionAlgorithm.cs
@@ -0,0 +1,227 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Security.Cryptography;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+using static Microsoft.Data.Encryption.Cryptography.DataEncryptionKey;
+using static Microsoft.Data.Encryption.Cryptography.EncryptionType;
+using static System.Security.Cryptography.CipherMode;
+using static System.Security.Cryptography.PaddingMode;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// A component for information encryption purposes that uses block ciphers to encrypt and protect data.
+ /// This class implements authenticated encryption algorithm with associated data as described in
+ /// http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05. More specifically this implements
+ /// AEAD_AES_256_CBC_HMAC_SHA256 algorithm.
+ ///
+ internal class AeadAes256CbcHmac256EncryptionAlgorithm : DataProtector
+ {
+ ///
+ /// Block size in bytes. AES uses 16 byte blocks.
+ ///
+ private const int BlockSizeInBytes = 16;
+
+ ///
+ /// Variable indicating whether this algorithm should work in Deterministic mode or Randomized mode.
+ /// For deterministic encryption, we derive an IV from the plaintext data.
+ /// For randomized encryption, we generate a cryptographically random IV.
+ ///
+ private readonly bool isDeterministicEncryptionType;
+
+ ///
+ /// The Data Encryption Key is an encryption key is used to encrypt data.
+ ///
+ private readonly DataEncryptionKey dataEncryptionKey;
+
+ ///
+ /// Byte array with algorithm version used for authentication tag computation.
+ ///
+ private static readonly byte[] version = { 1 };
+
+
+ private static readonly LocalCache, AeadAes256CbcHmac256EncryptionAlgorithm> algorithmCache
+ = new LocalCache, AeadAes256CbcHmac256EncryptionAlgorithm>(maxSizeLimit: 1000);
+
+ ///
+ /// Returns a cached instance of the or, if not present, creates a new one.
+ ///
+ /// The encryption key that is used to encrypt data.
+ /// The type of encryption.
+ /// An object.
+ public static AeadAes256CbcHmac256EncryptionAlgorithm GetOrCreate(DataEncryptionKey dataEncryptionKey, EncryptionType encryptionType)
+ {
+ dataEncryptionKey.ValidateNotNull(nameof(dataEncryptionKey));
+
+ return algorithmCache.GetOrCreate(
+ key: Tuple.Create(dataEncryptionKey, encryptionType),
+ createItem: () => new AeadAes256CbcHmac256EncryptionAlgorithm(dataEncryptionKey, encryptionType)
+ );
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// an encryption key is used to encrypt data
+ /// Determines whether this algorithm should work in Deterministic mode or Randomized mode.
+ public AeadAes256CbcHmac256EncryptionAlgorithm(DataEncryptionKey dataEncryptionKey, EncryptionType encryptionType)
+ {
+ ValidateEncryptionKeySize(dataEncryptionKey.RootKeyBytes.Length);
+
+ this.dataEncryptionKey = dataEncryptionKey;
+ isDeterministicEncryptionType = encryptionType == Deterministic;
+ }
+
+ ///
+ /// Convert information or data into a code, especially to prevent unauthorized access.
+ ///
+ /// The information or data to encrypt.
+ /// The ciphertext information.
+ public override byte[] Encrypt(byte[] plaintext)
+ {
+ if (plaintext.IsNull())
+ {
+ return null;
+ }
+
+ try
+ {
+ Aes aes = Aes.Create();
+ aes.Key = dataEncryptionKey.EncryptionKeyBytes;
+ aes.Mode = CBC;
+ aes.Padding = PKCS7;
+
+ if (isDeterministicEncryptionType)
+ {
+ aes.IV = GetHMACWithSHA256(plaintext, dataEncryptionKey.IvKeyBytes).Take(BlockSizeInBytes).ToArray();
+ }
+
+ ICryptoTransform encryptor = aes.CreateEncryptor();
+ MemoryStream memoryStream = new MemoryStream();
+ CryptoStream cryptoStream = new CryptoStream(memoryStream, encryptor, CryptoStreamMode.Write);
+ cryptoStream.Write(plaintext, 0, plaintext.Length);
+ cryptoStream.FlushFinalBlock();
+ byte[] ciphertext = memoryStream.ToArray();
+ byte[] hmac = GenerateAuthenticationTag(aes.IV, ciphertext);
+
+ return version.Concat(hmac).Concat(aes.IV).Concat(ciphertext).ToArray();
+ }
+ catch (Exception ex)
+ {
+ string lastTenBytesOfKey = GetBytesAsString(dataEncryptionKey.EncryptionKeyBytes, startFromEnd: true, countOfBytes: 10);
+ throw new MicrosoftDataEncryptionException(EncryptionFailed.Format(lastTenBytesOfKey, ex.Message));
+ }
+ }
+
+ ///
+ /// Convert coded information or data into an intelligible message.
+ ///
+ /// The coded information or data.
+ /// An intelligible message.
+ public override byte[] Decrypt(byte[] ciphertext)
+ {
+ if (ciphertext.IsNull())
+ {
+ return null;
+ }
+
+ ValidateCiphertextLength(ciphertext, dataEncryptionKey.EncryptionKeyBytes);
+ ValidateAlgorithmVersion(ciphertext, dataEncryptionKey.EncryptionKeyBytes);
+
+ const int authenticationTagIndex = 1;
+ const int authenticationTagLength = KeySizeInBytes;
+ const int initializationVectorIndex = authenticationTagIndex + authenticationTagLength;
+ const int initializationVectorLength = BlockSizeInBytes;
+ const int encryptedDataIndex = initializationVectorIndex + initializationVectorLength;
+ int encryptedDataLength = ciphertext.Length - encryptedDataIndex;
+
+ byte[] authenticationTag = ciphertext.Skip(authenticationTagIndex).Take(authenticationTagLength).ToArray();
+ byte[] initializationVector = ciphertext.Skip(initializationVectorIndex).Take(initializationVectorLength).ToArray();
+ byte[] encryptedData = ciphertext.Skip(encryptedDataIndex).Take(encryptedDataLength).ToArray();
+
+ ValidateAuthenticationTag(authenticationTag, initializationVector, encryptedData, ciphertext, dataEncryptionKey.EncryptionKeyBytes);
+
+ SymmetricAlgorithm symmetricAlgorithm = Aes.Create();
+ symmetricAlgorithm.Key = dataEncryptionKey.EncryptionKeyBytes;
+ symmetricAlgorithm.Mode = CBC;
+ symmetricAlgorithm.Padding = PKCS7;
+ symmetricAlgorithm.IV = initializationVector;
+
+ ICryptoTransform decryptor = symmetricAlgorithm.CreateDecryptor();
+ MemoryStream memoryStream = new MemoryStream();
+ CryptoStream cryptoStream = new CryptoStream(memoryStream, decryptor, CryptoStreamMode.Write);
+ cryptoStream.Write(encryptedData, 0, encryptedData.Length);
+ cryptoStream.FlushFinalBlock();
+
+ return memoryStream.ToArray();
+ }
+
+ private byte[] GenerateAuthenticationTag(byte[] iv, byte[] ciphertext)
+ {
+ HMACSHA256 hmacSha256 = new HMACSHA256(dataEncryptionKey.MacKeyBytes);
+ byte[] versionSize = { sizeof(byte) };
+ byte[] buffer = version.Concat(iv).Concat(ciphertext).Concat(versionSize).ToArray();
+ byte[] hmac = hmacSha256.ComputeHash(buffer);
+ return hmac;
+ }
+
+ private static void ValidateCiphertextLength(byte[] ciphertext, byte[] encryptionKey)
+ {
+ const int minimumCipherTextLength = sizeof(byte) + BlockSizeInBytes + BlockSizeInBytes + KeySizeInBytes;
+
+ if (ciphertext.Length < minimumCipherTextLength)
+ {
+ ThrowDecryptionFailedException(encryptionKey, ciphertext, InvalidCipherTextSize.Format(ciphertext.Length, minimumCipherTextLength));
+ }
+ }
+
+ private void ValidateAlgorithmVersion(byte[] ciphertext, byte[] encryptionKey)
+ {
+ if (ciphertext[0] != version[0])
+ {
+ ThrowDecryptionFailedException(encryptionKey, ciphertext, InvalidAlgorithmVersion.Format(ciphertext[0].ToString("X2"), version[0].ToString("X2")));
+ }
+ }
+
+ private void ValidateAuthenticationTag(byte[] authenticationTag, byte[] initializationVector, byte[] encryptedData, byte[] ciphertext, byte[] encryptionKey)
+ {
+ byte[] computedAuthenticationTag = GenerateAuthenticationTag(initializationVector, encryptedData);
+
+ if (!authenticationTag.SequenceEqual(computedAuthenticationTag))
+ {
+ ThrowDecryptionFailedException(encryptionKey, ciphertext, InvalidAuthenticationTag);
+ }
+ }
+
+ private void ValidateEncryptionKeySize(int size)
+ {
+ if (size != KeySizeInBytes)
+ {
+ throw new MicrosoftDataEncryptionException(InvalidDataEncryptionKeySize.Format(size));
+ }
+ }
+
+ private static MicrosoftDataEncryptionException ThrowDecryptionFailedException(byte[] encryptionKey, byte[] ciphertext, string reason)
+ {
+ string lastTenBytesOfKey = GetBytesAsString(encryptionKey, startFromEnd: true, countOfBytes: 10);
+ string firstTenBytesOfCiphertext = GetBytesAsString(ciphertext, startFromEnd: false, countOfBytes: 10);
+ throw new MicrosoftDataEncryptionException(DecryptionFailed.Format(lastTenBytesOfKey, firstTenBytesOfCiphertext, reason));
+ }
+
+ private static string GetBytesAsString(byte[] buffer, bool startFromEnd, int countOfBytes)
+ {
+ int count = (buffer.Length > countOfBytes) ? countOfBytes : buffer.Length;
+ int startIndex = startFromEnd ? buffer.Length - count : 0;
+ return BitConverter.ToString(buffer, startIndex, count);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/AssemblyInfo.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/AssemblyInfo.cs
new file mode 100644
index 0000000000..f214dd1350
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/AssemblyInfo.cs
@@ -0,0 +1,12 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Runtime.CompilerServices;
+
+[assembly: CLSCompliant(true)]
+[assembly: InternalsVisibleTo("Microsoft.Data.Encryption.Cryptography.Tests,PublicKey=0024000004800000940000000602000000240000525341310004000001000100393106b45a63d86c5dab7f007ca58b8e485240dae7190662e9bfdca8f15fa6661f5be51918377614d9097f48484e524decee152376565fc3f428bbec06ea23f965d0da06749183fbbac42badcea054f2534f0d55be555980c9d73bab3da62fda265dd3a5bc20d75693fe036c9c5bdee9904456a4cb066cd9c0848087c3c160ba")]
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/DataEncryptionKey.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/DataEncryptionKey.cs
new file mode 100644
index 0000000000..a5a12f9a5c
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/DataEncryptionKey.cs
@@ -0,0 +1,111 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System.Security.Cryptography;
+
+using static System.Text.Encoding;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// An encryption key that is used to encrypt and decrypt data.
+ ///
+ internal abstract class DataEncryptionKey
+ {
+ private byte[] rootKeyBytes;
+ private const int KeySizeInBits = 256;
+ internal const int KeySizeInBytes = KeySizeInBits / 8;
+
+ ///
+ /// The name by which the will be known.
+ ///
+ public string Name { get; protected set; }
+
+ ///
+ /// The hexadecimal string representation of the root key used for equality comparisons.
+ ///
+ protected string rootKeyHexString;
+
+ ///
+ /// The root key used for encryption operations.
+ ///
+ internal byte[] RootKeyBytes
+ {
+ get => rootKeyBytes;
+ set
+ {
+ rootKeyBytes = value;
+ rootKeyHexString = value.ToHexString();
+ }
+ }
+
+ ///
+ /// The encryption key that is used for encryption and decryption.
+ ///
+ internal byte[] EncryptionKeyBytes { get; set; }
+
+ ///
+ /// The MAC key that is used to compute and validate an HMAC.
+ ///
+ internal byte[] MacKeyBytes { get; set; }
+
+ ///
+ /// The IV key that is used to compute a synthetic IV from a given plain text.
+ ///
+ internal byte[] IvKeyBytes { get; set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name by which the will be known.
+ /// Specifies the root key used for encrypting and decrypting.
+ protected DataEncryptionKey(string name, byte[] rootKey)
+ {
+ name.ValidateNotNullOrWhitespace(nameof(name));
+ rootKey.ValidateSize(KeySizeInBytes, nameof(rootKey));
+
+ Name = name;
+
+ string encryptionKeySalt = $"Microsoft SQL Server cell encryption key with encryption algorithm:AEAD_AES_256_CBC_HMAC_SHA256 and key length:{KeySizeInBits}";
+ string macKeySalt = $"Microsoft SQL Server cell MAC key with encryption algorithm:AEAD_AES_256_CBC_HMAC_SHA256 and key length:{KeySizeInBits}";
+ string ivKeySalt = $"Microsoft SQL Server cell IV key with encryption algorithm:AEAD_AES_256_CBC_HMAC_SHA256 and key length:{KeySizeInBits}";
+
+ byte[] encryptionKeyBytes = GetHMACWithSHA256(Unicode.GetBytes(encryptionKeySalt), rootKey);
+ byte[] macKeyBytes = GetHMACWithSHA256(Unicode.GetBytes(macKeySalt), rootKey);
+ byte[] ivKeyBytes = GetHMACWithSHA256(Unicode.GetBytes(ivKeySalt), rootKey);
+
+ RootKeyBytes = rootKey;
+ EncryptionKeyBytes = encryptionKeyBytes;
+ MacKeyBytes = macKeyBytes;
+ IvKeyBytes = ivKeyBytes;
+ }
+
+ ///
+ /// Computes a Hash-based Message Authentication Code (HMAC) by using the SHA256 hash function.
+ ///
+ /// Plain text bytes whose hash has to be computed.
+ /// key used for the HMAC
+ /// HMAC value
+ internal static byte[] GetHMACWithSHA256(byte[] plaintext, byte[] key)
+ {
+ using (HMACSHA256 hmacSha256 = new HMACSHA256(key))
+ {
+ return hmacSha256.ComputeHash(plaintext);
+ }
+ }
+
+ ///
+ /// Determines if the current 's root key is equal to the specified 's root key
+ ///
+ /// The to compare with the current
+ ///
+ public bool RootKeyEquals(DataEncryptionKey otherKey)
+ {
+ return rootKeyHexString.Equals(otherKey.rootKeyHexString);
+ }
+ }
+}
\ No newline at end of file
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/DataProtector.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/DataProtector.cs
new file mode 100644
index 0000000000..0ec979866c
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/DataProtector.cs
@@ -0,0 +1,29 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// The base class used for algorithms that do encryption and decryption of serialized object data.
+ ///
+ internal abstract class DataProtector
+ {
+ ///
+ /// Convert information or data into a code, especially to prevent unauthorized access.
+ ///
+ /// The information or data to encrypt.
+ /// The ciphertext information.
+ public abstract byte[] Encrypt(byte[] plaintext);
+
+ ///
+ /// Convert coded information or data into an intelligible message.
+ ///
+ /// The coded information or data.
+ /// An intelligible message.
+ public abstract byte[] Decrypt(byte[] ciphertext);
+ }
+}
\ No newline at end of file
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/EncryptionKeyStoreProvider.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/EncryptionKeyStoreProvider.cs
new file mode 100644
index 0000000000..e282752bcd
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/EncryptionKeyStoreProvider.cs
@@ -0,0 +1,114 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// Base class for all key store providers. A custom provider must derive from this
+ /// class and override its member functions.
+ ///
+ internal abstract class EncryptionKeyStoreProvider
+ {
+ ///
+ /// A cache of key encryption keys (once they are unwrapped). This is useful for rapidly decrypting multiple data values.
+ ///
+ private readonly LocalCache dataEncryptionKeyCache = new LocalCache() { TimeToLive = TimeSpan.FromHours(2) };
+
+ ///
+ /// A cache for storing the results of signature verification of key encryption key metadata.
+ ///
+ private readonly LocalCache, bool> keyEncryptionKeyMetadataSignatureVerificationCache =
+ new LocalCache, bool>(maxSizeLimit: 2000) { TimeToLive = TimeSpan.FromDays(10) };
+
+ ///
+ /// Gets or sets the lifespan of the decrypted data encryption key in the cache.
+ /// Once the timespan has elapsed, the decrypted data encryption key is discarded
+ /// and must be revalidated.
+ ///
+ ///
+ /// Internally, there is a cache of key encryption keys (once they are unwrapped).
+ /// This is useful for rapidly decrypting multiple data values. The default value is 2 hours.
+ /// Setting the to zero disables caching.
+ ///
+ public TimeSpan? DataEncryptionKeyCacheTimeToLive
+ {
+ get => dataEncryptionKeyCache.TimeToLive;
+ set => dataEncryptionKeyCache.TimeToLive = value;
+ }
+
+ ///
+ /// The unique name that identifies a particular implementation of the abstract .
+ ///
+ public abstract string ProviderName { get; }
+
+ ///
+ /// Unwraps the specified of a data encryption key. The encrypted value is expected to be encrypted using
+ /// the key encryption key with the specified and using the specified .
+ ///
+ /// The key Id tells the provider where to find the key.
+ /// The encryption algorithm.
+ /// The ciphertext key.
+ /// The unwrapped data encryption key.
+ public abstract byte[] UnwrapKey(string encryptionKeyId, KeyEncryptionKeyAlgorithm algorithm, byte[] encryptedKey);
+
+ ///
+ /// Wraps a data encryption key using the key encryption key with the specified and using the specified .
+ ///
+ /// The key Id tells the provider where to find the key.
+ /// The encryption algorithm.
+ /// The plaintext key.
+ /// The wrapped data encryption key.
+ public abstract byte[] WrapKey(string encryptionKeyId, KeyEncryptionKeyAlgorithm algorithm, byte[] key);
+
+ ///
+ /// When implemented in a derived class, digitally signs the key encryption key metadata with the key encryption key referenced
+ /// by the parameter. The input values used to generate the signature should be the specified values of
+ /// the and parameters.
+ ///
+ /// The key Id tells the provider where to find the key.
+ /// Indicates whether the key encryption key supports enclave computations.
+ /// The signature of the key encryption key metadata.
+ public abstract byte[] Sign(string encryptionKeyId, bool allowEnclaveComputations);
+
+ ///
+ /// When implemented in a derived class, this method is expected to verify the specified is valid
+ /// for the key encryption key with the specified and the specified enclave behavior.
+ ///
+ /// The key Id tells the provider where to find the key.
+ /// Indicates whether the key encryption key supports enclave computations.
+ /// The signature of the key encryption key metadata.
+ ///
+ public abstract bool Verify(string encryptionKeyId, bool allowEnclaveComputations, byte[] signature);
+
+ ///
+ /// Returns the cached decrypted data encryption key, or unwraps the encrypted data encryption if not present.
+ ///
+ /// Encrypted Data Encryption Key
+ /// The delegate function that will decrypt the encrypted column encryption key.
+ /// The decrypted data encryption key.
+ ///
+ ///
+ ///
+ protected virtual byte[] GetOrCreateDataEncryptionKey(string encryptedDataEncryptionKey, Func createItem)
+ {
+ return dataEncryptionKeyCache.GetOrCreate(encryptedDataEncryptionKey, createItem);
+ }
+
+ ///
+ /// Returns the cached signature verification result, or proceeds to verify if not present.
+ ///
+ /// The encryptionKeyId, allowEnclaveComputations and hexadecimal signature.
+ /// The delegate function that will perform the verification.
+ ///
+ protected virtual bool GetOrCreateSignatureVerificationResult(Tuple keyInformation, Func createItem)
+ {
+ return keyEncryptionKeyMetadataSignatureVerificationCache.GetOrCreate(keyInformation, createItem);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/EncryptionSettings.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/EncryptionSettings.cs
new file mode 100644
index 0000000000..f20b943ea3
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/EncryptionSettings.cs
@@ -0,0 +1,124 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using Microsoft.Data.Encryption.Cryptography.Serializers;
+using System;
+using static Microsoft.Data.Encryption.Cryptography.EncryptionType;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// Contains the settings to configure how encryption operations are performed on the data of
+ /// arbitrary type .
+ ///
+ /// The data type on which these encryption settings will apply.
+ internal class EncryptionSettings : EncryptionSettings
+ {
+ ///
+ /// Used for serializing and deserializing data objects to and from an array of bytes.
+ ///
+ public Serializer Serializer { get; private set; }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An encryption key is used to encrypt and decrypt data.
+ /// A serializer is used for serializing and deserializing data objects to and from an array of bytes.
+ public EncryptionSettings(DataEncryptionKey dataEncryptionKey, Serializer serializer)
+ : this(dataEncryptionKey, GetDefaultEncryptionType(dataEncryptionKey), serializer) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// An encryption key is used to encrypt and decrypt data.
+ /// The type of encryption.
+ /// A serializer is used for serializing and deserializing data objects to and from an array of bytes.
+ public EncryptionSettings(DataEncryptionKey dataEncryptionKey, EncryptionType encryptionType, Serializer serializer)
+ {
+ DataEncryptionKey = dataEncryptionKey;
+ EncryptionType = encryptionType;
+ Serializer = serializer;
+ }
+
+ ///
+ /// Gets the
+ ///
+ /// returns the
+ public override ISerializer GetSerializer()
+ {
+ return Serializer;
+ }
+ }
+
+ ///
+ /// Contains the settings to configure how encryption operations are performed on data.
+ ///
+ internal abstract class EncryptionSettings : IEquatable
+ {
+ private DataEncryptionKey encryptionKey;
+
+ ///
+ /// Gets the
+ ///
+ public virtual DataEncryptionKey DataEncryptionKey
+ {
+ get => encryptionKey;
+
+ protected set
+ {
+ encryptionKey = value;
+ if (DataEncryptionKey.IsNull())
+ {
+ EncryptionType = Plaintext;
+ }
+ }
+ }
+
+ ///
+ /// Gets the
+ ///
+ public EncryptionType EncryptionType { get; protected set; } = Randomized;
+
+ ///
+ /// Gets the
+ ///
+ /// returns the
+ public abstract ISerializer GetSerializer();
+
+ ///
+ /// Gets the default
+ ///
+ /// An encryption key is used to encrypt and decrypt data.
+ /// Plaintext if the is null, otherwise.
+ protected static EncryptionType GetDefaultEncryptionType(DataEncryptionKey dataEncryptionKey)
+ {
+ return dataEncryptionKey.IsNull() ? Plaintext : Randomized;
+ }
+
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public bool Equals(EncryptionSettings other)
+ {
+ if (other == null)
+ {
+ return false;
+ }
+
+ if (DataEncryptionKey.IsNull() && !other.DataEncryptionKey.IsNull())
+ {
+ return false;
+ }
+
+ return DataEncryptionKey.Equals(other.DataEncryptionKey)
+ && EncryptionType.Equals(other.EncryptionType)
+ && GetSerializer().GetType().Equals(other.GetSerializer().GetType());
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/DataEncryptionKeyAlgorithm.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/DataEncryptionKeyAlgorithm.cs
new file mode 100644
index 0000000000..071383d2de
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/DataEncryptionKeyAlgorithm.cs
@@ -0,0 +1,21 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// Represents the encryption algorithms supported for data encryption.
+ ///
+ internal enum DataEncryptionKeyAlgorithm
+ {
+ ///
+ /// Represents the authenticated encryption algorithm with associated data as described in
+ /// http://tools.ietf.org/html/draft-mcgrew-aead-aes-cbc-hmac-sha2-05.
+ ///
+ AEAD_AES_256_CBC_HMAC_SHA256
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/EncryptionType.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/EncryptionType.cs
new file mode 100644
index 0000000000..0b3caaf962
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/EncryptionType.cs
@@ -0,0 +1,35 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// The type of data encryption.
+ ///
+ ///
+ /// The three encryption types are Plaintext Deterministic and Randomized. Plaintext unencrypted data.
+ /// Deterministic encryption always generates the same encrypted value for any given plain text value.
+ /// Randomized encryption uses a method that encrypts data in a less predictable manner. Randomized encryption is more secure.
+ ///
+ internal enum EncryptionType
+ {
+ ///
+ /// Plaintext unencrypted data.
+ ///
+ Plaintext,
+
+ ///
+ /// Deterministic encryption always generates the same encrypted value for any given plain text value.
+ ///
+ Deterministic,
+
+ ///
+ /// Randomized encryption uses a method that encrypts data in a less predictable manner. Randomized encryption is more secure.
+ ///
+ Randomized
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/KeyEncryptionKeyAlgorithm.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/KeyEncryptionKeyAlgorithm.cs
new file mode 100644
index 0000000000..a25cfb2141
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Enums/KeyEncryptionKeyAlgorithm.cs
@@ -0,0 +1,20 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// Represents the encryption algorithms supported for key encryption.
+ ///
+ internal enum KeyEncryptionKeyAlgorithm
+ {
+ ///
+ /// RSA public key cryptography algorithm with Optimal Asymmetric Encryption Padding (OAEP) padding.
+ ///
+ RSA_OAEP
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Extensions/CryptographyExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Extensions/CryptographyExtensions.cs
new file mode 100644
index 0000000000..fc7a41cf64
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Extensions/CryptographyExtensions.cs
@@ -0,0 +1,351 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using Microsoft.Data.Encryption.Cryptography.Serializers;
+using System;
+using System.Collections.Generic;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// Extension methods for data protection.
+ ///
+ internal static class CryptographyExtensions
+ {
+ private const string hexPrefix = "0x";
+
+ ///
+ /// Encrypts the provided value using the provided .
+ ///
+ /// The value .
+ /// The plaintext value to encrypt.
+ /// The key used to encrypt the value.
+ /// The encrypted value.
+ ///
+ /// This method encrypts using encryption and the
+ /// default serializer registered under type with the
+ ///
+ /// is null.
+ public static byte[] Encrypt(this T plaintext, DataEncryptionKey encryptionKey)
+ {
+ encryptionKey.ValidateNotNull(nameof(encryptionKey));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
+ Serializer serializer = StandardSerializerFactory.Default.GetDefaultSerializer();
+ byte[] serializedData = serializer.Serialize(plaintext);
+ return encryptionAlgorithm.Encrypt(serializedData);
+ }
+
+ ///
+ /// Decrypts the provided value using the provided .
+ ///
+ /// The plaintext value .
+ /// The encrypted value.
+ /// The key used to decrypt the value.
+ /// The decrypted value.
+ ///
+ /// This method decrypts data that was encrypted using encryption and the
+ /// default serializer registered under type with the
+ ///
+ /// is null.
+ public static T Decrypt(this byte[] ciphertext, DataEncryptionKey encryptionKey)
+ {
+ encryptionKey.ValidateNotNull(nameof(encryptionKey));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
+ Serializer serializer = StandardSerializerFactory.Default.GetDefaultSerializer();
+ byte[] plaintextData = encryptionAlgorithm.Decrypt(ciphertext);
+ return serializer.Deserialize(plaintextData);
+ }
+
+ ///
+ /// Encrypts the provided value using the provided .
+ ///
+ /// The value .
+ /// The plaintext value to encrypt.
+ /// The settings used to configure how the should be encrypted.
+ /// The encrypted value.
+ ///
+ /// is null.
+ /// -or-
+ /// is set to .
+ ///
+ public static byte[] Encrypt(this T plaintext, EncryptionSettings encryptionSettings)
+ {
+ encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
+ encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, encryptionSettings.EncryptionType);
+ ISerializer serializer = encryptionSettings.GetSerializer();
+ byte[] serializedData = serializer.Serialize(plaintext);
+ return encryptionAlgorithm.Encrypt(serializedData);
+ }
+
+ ///
+ /// Decrypts the provided value using the provided .
+ ///
+ /// The plaintext value .
+ /// The encrypted value.
+ /// The settings used to configure how the should be decrypted.
+ /// The decrypted value.
+ ///
+ /// is null.
+ /// -or-
+ /// is set to .
+ ///
+ public static T Decrypt(this byte[] ciphertext, EncryptionSettings encryptionSettings)
+ {
+ encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
+ encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, EncryptionType.Plaintext);
+ Serializer serializer = encryptionSettings.Serializer;
+ byte[] plaintextData = encryptionAlgorithm.Decrypt(ciphertext);
+ return serializer.Deserialize(plaintextData);
+ }
+
+ ///
+ /// Encrypts each plaintext value of a sequence using the provided .
+ ///
+ /// The type of the plaintext elements of .
+ /// A sequence of values to encrypt.
+ /// The key used to encrypt the plaintext values of .
+ /// An of whose elements are the result of encrypting each element of .
+ ///
+ /// This method encrypts using encryption and the
+ /// default serializer registered under type with the
+ ///
+ /// is null.
+ public static IEnumerable Encrypt(this IEnumerable source, DataEncryptionKey encryptionKey)
+ {
+ encryptionKey.ValidateNotNull(nameof(encryptionKey));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
+ Serializer serializer = StandardSerializerFactory.Default.GetDefaultSerializer();
+
+ foreach (T item in source)
+ {
+ byte[] serializedData = serializer.Serialize(item);
+ yield return encryptionAlgorithm.Encrypt(serializedData);
+ }
+ }
+
+ ///
+ /// Decrypts each ciphertext value of a sequence using the provided .
+ ///
+ /// The type of the plaintext elements of
+ /// A sequence of encrypted values to decrypt.
+ /// The key used to decrypt the ciphertext values of .
+ /// An whose elements are the result of decrypting each element of .
+ ///
+ /// This method decrypts data that was encrypted using encryption and the
+ /// default serializer registered under type with the
+ ///
+ /// is null.
+ public static IEnumerable Decrypt(this IEnumerable source, DataEncryptionKey encryptionKey)
+ {
+ encryptionKey.ValidateNotNull(nameof(encryptionKey));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionKey, EncryptionType.Randomized);
+ Serializer serializer = StandardSerializerFactory.Default.GetDefaultSerializer();
+ StandardSerializerFactory myFactory = new StandardSerializerFactory();
+ myFactory.RegisterSerializer(typeof(string), new SqlNCharSerializer());
+
+ foreach (byte[] item in source)
+ {
+ byte[] plaintextData = encryptionAlgorithm.Decrypt(item);
+ yield return serializer.Deserialize(plaintextData);
+ }
+ }
+
+ ///
+ /// Encrypts each plaintext value of a sequence using the provided .
+ ///
+ /// The type of the plaintext elements of .
+ /// A sequence of values to encrypt.
+ /// The settings used to configure how the values of should be encrypted.
+ /// An of whose elements are the result of encrypting each element of .
+ ///
+ /// is null.
+ /// -or-
+ /// is set to .
+ ///
+ public static IEnumerable Encrypt(this IEnumerable source, EncryptionSettings encryptionSettings)
+ {
+ encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
+ encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, encryptionSettings.EncryptionType);
+ Serializer serializer = encryptionSettings.Serializer;
+
+ foreach (T item in source)
+ {
+ byte[] serializedData = serializer.Serialize(item);
+ yield return encryptionAlgorithm.Encrypt(serializedData);
+ }
+ }
+
+ ///
+ /// Decrypts each ciphertext value of a sequence using the provided .
+ ///
+ /// The type of the plaintext elements of .
+ /// A sequence of values to decrypt.
+ /// The settings used to configure how the values of should be decrypted.
+ /// An whose elements are the result of decrypting each element of .
+ ///
+ /// is null.
+ /// -or-
+ /// is set to .
+ ///
+ public static IEnumerable Decrypt(this IEnumerable source, EncryptionSettings encryptionSettings)
+ {
+ encryptionSettings.ValidateNotNull(nameof(encryptionSettings));
+ encryptionSettings.ValidateNotPlaintext(nameof(encryptionSettings));
+
+ DataProtector encryptionAlgorithm = AeadAes256CbcHmac256EncryptionAlgorithm.GetOrCreate(encryptionSettings.DataEncryptionKey, EncryptionType.Plaintext);
+ Serializer serializer = encryptionSettings.Serializer;
+
+ foreach (byte[] item in source)
+ {
+ byte[] plaintextData = encryptionAlgorithm.Decrypt(item);
+ yield return serializer.Deserialize(plaintextData);
+ }
+ }
+
+ ///
+ /// Converts an array bytes to its equivalent string representation that is encoded with base-64 digits.
+ ///
+ /// An array of bytes.
+ /// The string representation, in base 64, of the contents of .
+ public static string ToBase64String(this byte[] source) => source.IsNull() ? null : Convert.ToBase64String(source);
+
+ ///
+ /// Converts the specified string, which encodes binary data as base-64 digits, to an equivalent byte array.
+ ///
+ /// The string to convert.
+ /// An array of bytes that is equivalent to .
+ ///
+ /// The length of , ignoring white-space characters, is not zero or a multiple of
+ /// 4. -or- The format of is invalid. contains a non-base-64 character, more
+ /// than two padding characters, or a non-white space-character among the padding characters.
+ ///
+ public static byte[] FromBase64String(this string source) => source.IsNull() ? null : Convert.FromBase64String(source);
+
+ ///
+ /// Converts each byte array in the sequence to its equivalent string representation that is encoded with base-64 digits.
+ ///
+ /// A sequence of byte arrays to convert.
+ /// An of whose elements are the result of being encoded with base-64 digits.
+ public static IEnumerable ToBase64String(this IEnumerable source)
+ {
+ foreach (byte[] item in source)
+ {
+ yield return ToBase64String(item);
+ }
+ }
+
+ ///
+ /// Converts each element of , which encodes binary data as base-64 digits, to an equivalent byte array.
+ ///
+ /// A sequence of strings to convert.
+ /// An of byte arrays that is equivalent to .
+ ///
+ /// The length of a element, ignoring white-space characters, is not zero or a multiple of
+ /// 4. -or- The format of a element is invalid. element contains a non-base-64 character, more
+ /// than two padding characters, or a non-white space-character among the padding characters.
+ ///
+ public static IEnumerable FromBase64String(this IEnumerable source)
+ {
+ foreach (string item in source)
+ {
+ yield return FromBase64String(item);
+ }
+ }
+
+ ///
+ /// Converts the numeric value of each element of a specified array of bytes to its equivalent hexadecimal string representation.
+ ///
+ /// An array of bytes to convert.
+ /// A string of hexadecimal characters
+ ///
+ /// Produces a string of hexadecimal character pairs preceded with "0x", where each pair represents the corresponding element in value; for example, "0x7F2C4A00".
+ ///
+ public static string ToHexString(this byte[] source)
+ {
+ if (source.IsNull())
+ {
+ return null;
+ }
+
+ return hexPrefix + BitConverter.ToString(source).Replace("-", "");
+ }
+
+ ///
+ /// Converts the string representation of a number in hexadecimal to an equivalent array of bytes.
+ ///
+ /// The string to convert.
+ /// An array of bytes that is equivalent to .
+ ///
+ /// The length of is not a multiple of 2, the
+ /// contains a hexadecimal character, or does not begin with the literal prefix '0x'.
+ ///
+ public static byte[] FromHexString(this string source)
+ {
+ return source.IsNull() ? null : ConvertToBytes(source);
+
+ byte[] ConvertToBytes(string hex)
+ {
+ if (hex.Length < 2 || hex.Substring(0, 2) != hexPrefix || hex.Length % 2 != 0)
+ {
+ throw new MicrosoftDataEncryptionException(InvalidHexString);
+ }
+
+ hex = hex.Substring(2);
+
+ byte[] bytes = new byte[hex.Length / 2];
+
+ for (int i = 0; i < hex.Length; i += 2)
+ {
+ bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
+ }
+
+ return bytes;
+ }
+ }
+
+ ///
+ /// Converts each byte array in the sequence to its equivalent string representation that is encoded with hexadecimal digits.
+ ///
+ /// A sequence of byte arrays to convert.
+ /// An of whose elements are the result of being encoded with hexadecimal digits.
+ public static IEnumerable ToHexString(this IEnumerable source)
+ {
+ foreach (byte[] item in source)
+ {
+ yield return ToHexString(item);
+ }
+ }
+
+ ///
+ /// Converts each element of , which encodes binary data as hexadecimal digits, to an equivalent byte array.
+ ///
+ /// A sequence of strings to convert.
+ /// An of byte arrays that is equivalent to .
+ ///
+ /// The length of element is not a multiple of 2, contains a hexadecimal character, or does not begin with the literal prefix '0x'.
+ ///
+ public static IEnumerable FromHexString(this IEnumerable source)
+ {
+ foreach (string item in source)
+ {
+ yield return FromHexString(item);
+ }
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/KeyEncryptionKey.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/KeyEncryptionKey.cs
new file mode 100644
index 0000000000..86e5a9de20
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/KeyEncryptionKey.cs
@@ -0,0 +1,140 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// A represents a key-protecting key stored in an external key store.
+ /// The key protects (encrypts) one or more .
+ ///
+ internal class KeyEncryptionKey
+ {
+ private const KeyEncryptionKeyAlgorithm encryptionAlgorithm = KeyEncryptionKeyAlgorithm.RSA_OAEP;
+ private readonly Lazy signature;
+
+ ///
+ /// A local cache to hold previously created objects for reuse.
+ ///
+ private static readonly LocalCache, KeyEncryptionKey> keyEncryptionKeyCache =
+ new LocalCache, KeyEncryptionKey>();
+
+ ///
+ /// The name of the .
+ ///
+ public string Name { get; private set; }
+
+ ///
+ /// Specifies the key store provider. A key store provider is an object that has access to the .
+ ///
+ public EncryptionKeyStoreProvider KeyStoreProvider { get; private set; }
+
+ ///
+ /// The path of the key in the store. The format of the key path is specific
+ /// to the implementation.
+ ///
+ public string Path { get; private set; }
+
+ ///
+ /// Specifies that the is enclave-enabled. You can share all encryption keys,
+ /// encrypted with the , with a secure enclave and use them for computations inside the enclave.
+ ///
+ public bool IsEnclaveSupported { get; private set; }
+
+ ///
+ /// A binary result of digitally signing key path and the
+ /// setting with the master key. The signature reflects whether
+ /// is specified or not. The signature protects the signed values from being altered by unauthorized users.
+ ///
+ public byte[] Signature { get => signature.Value; }
+
+ ///
+ /// Returns a cached instance of the or, if not present, creates a new one.
+ ///
+ /// The name of the .
+ /// The path of the key in the store.
+ /// A component that has access to the .
+ /// Specifies whether the is enclave-enabled.
+ /// A object.
+ public static KeyEncryptionKey GetOrCreate(string name, string path, EncryptionKeyStoreProvider keyStoreProvider, bool isEnclaveSupported = false)
+ {
+ name.ValidateNotNullOrWhitespace(nameof(name));
+ path.ValidateNotNullOrWhitespace(nameof(name));
+ keyStoreProvider.ValidateNotNull(nameof(keyStoreProvider));
+
+ return keyEncryptionKeyCache.GetOrCreate(
+ key: Tuple.Create(name, path, keyStoreProvider, isEnclaveSupported),
+ createItem: () => new KeyEncryptionKey(name, path, keyStoreProvider, isEnclaveSupported)
+ );
+ }
+
+ ///
+ /// Constructs a new master key.
+ ///
+ /// The name of the .
+ /// The path of the key in the store.
+ /// A component that has access to the .
+ /// Specifies whether the is enclave-enabled.
+ public KeyEncryptionKey(string name, string path, EncryptionKeyStoreProvider keyStoreProvider, bool isEnclaveSupported = false)
+ {
+ name.ValidateNotNullOrWhitespace(nameof(name));
+ path.ValidateNotNullOrWhitespace(nameof(name));
+ keyStoreProvider.ValidateNotNull(nameof(keyStoreProvider));
+
+ Name = name;
+ Path = path;
+ KeyStoreProvider = keyStoreProvider;
+ IsEnclaveSupported = isEnclaveSupported;
+ signature = new Lazy(() => KeyStoreProvider.Sign(encryptionKeyId: path, allowEnclaveComputations: isEnclaveSupported));
+ }
+
+ ///
+ /// Encrypts an EncryptionKey
+ ///
+ /// The to encrypt.
+ /// The encrypted
+ public byte[] EncryptEncryptionKey(byte[] plaintextEncryptionKey)
+ {
+ return KeyStoreProvider.WrapKey(Path, encryptionAlgorithm, plaintextEncryptionKey);
+ }
+
+ ///
+ /// Decrypts an
+ ///
+ /// The to decrypt.
+ /// The decrypted
+ public byte[] DecryptEncryptionKey(byte[] encryptedEncryptionKey)
+ {
+ return KeyStoreProvider.UnwrapKey(Path, encryptionAlgorithm, encryptedEncryptionKey);
+ }
+
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ if (!(obj is KeyEncryptionKey other))
+ {
+ return false;
+ }
+
+ return Name.Equals(other.Name)
+ && KeyStoreProvider.Equals(other.KeyStoreProvider)
+ && Path.Equals(other.Path)
+ && IsEnclaveSupported.Equals(other.IsEnclaveSupported);
+ }
+
+ ///
+ /// Generates a hash code for the current object.
+ ///
+ /// A hash code for the current object.
+ public override int GetHashCode() => Tuple.Create(Name, KeyStoreProvider, Path, IsEnclaveSupported).GetHashCode();
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/LocalCache.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/LocalCache.cs
new file mode 100644
index 0000000000..567ef53b15
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/LocalCache.cs
@@ -0,0 +1,95 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using Microsoft.Extensions.Caching.Memory;
+using System;
+
+using static System.Math;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// LocalCache is to reuse heavy objects.
+ /// When performing a heavy creation operation, we will save the result in our cache container.
+ /// The next time that we need that result, we will pull it from the cache container, instead of performing the heavy operation again.
+ ///
+ internal class LocalCache
+ {
+ ///
+ /// A simple thread-safe implementation of an in-memory Cache.
+ /// When the process dies, the cache dies with it.
+ ///
+ private readonly MemoryCache cache;
+
+ private readonly int maxSize;
+
+ ///
+ /// Sets an absolute expiration time, relative to now.
+ ///
+ internal TimeSpan? TimeToLive { get; set; }
+
+ ///
+ /// Gets the count of the current entries for diagnostic purposes.
+ ///
+ internal int Count => cache.Count;
+
+ ///
+ /// Constructs a new LocalCache object.
+ ///
+ internal LocalCache(int maxSizeLimit = int.MaxValue)
+ {
+ maxSizeLimit.ValidatePositive(nameof(maxSize));
+
+ maxSize = maxSizeLimit;
+ cache = new MemoryCache(new MemoryCacheOptions());
+ }
+
+ ///
+ /// Looks for the cache entry that maps to the value. If it exists (cache hit) it will simply be
+ /// returned. Otherwise, the delegate function will be invoked to create the value.
+ /// It will then get stored it in the cache and set the time-to-live before getting returned.
+ ///
+ /// The encrypted key bytes.
+ /// The delegate function that will decrypt the encrypted column encryption key.
+ /// The decrypted column encryption key.
+ internal TValue GetOrCreate(TKey key, Func createItem)
+ {
+ if (TimeToLive <= TimeSpan.Zero)
+ {
+ return createItem();
+ }
+
+ if (!cache.TryGetValue(key, out TValue cacheEntry))
+ {
+ if (cache.Count == maxSize)
+ {
+ cache.Compact(Max(0.10, 1.0 / maxSize));
+ }
+
+ cacheEntry = createItem();
+ var cacheEntryOptions = new MemoryCacheEntryOptions
+ {
+ AbsoluteExpirationRelativeToNow = TimeToLive
+ };
+
+ cache.Set(key, cacheEntry, cacheEntryOptions);
+ }
+
+ return cacheEntry;
+ }
+
+ ///
+ /// Determines whether the LocalCache contains the specified key.
+ ///
+ ///
+ ///
+ internal bool Contains(TKey key)
+ {
+ return cache.TryGetValue(key, out _);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/MicrosoftDataEncryptionException.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/MicrosoftDataEncryptionException.cs
new file mode 100644
index 0000000000..88dac74a10
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/MicrosoftDataEncryptionException.cs
@@ -0,0 +1,23 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption
+{
+ ///
+ /// Represents an exception thrown by the Data Encryption SDK.
+ ///
+ internal sealed class MicrosoftDataEncryptionException : Exception
+ {
+ ///
+ /// Initializes a new instance of MicrosoftDataEncryptionException with the specified error message.
+ ///
+ /// The message describing the error.
+ public MicrosoftDataEncryptionException(string message) : base(message) { }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/PlaintextDataEncryptionKey.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/PlaintextDataEncryptionKey.cs
new file mode 100644
index 0000000000..b91b2d69ab
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/PlaintextDataEncryptionKey.cs
@@ -0,0 +1,108 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Security.Cryptography;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// An encryption key that is used to encrypt and decrypt data.
+ ///
+ internal class PlaintextDataEncryptionKey : DataEncryptionKey
+ {
+ ///
+ /// A local cache to hold previously created objects for reuse.
+ ///
+ ///
+ /// The retension period is defined by the property.
+ ///
+ private static readonly LocalCache, PlaintextDataEncryptionKey> encryptionKeyCache
+ = new LocalCache, PlaintextDataEncryptionKey>() { TimeToLive = TimeSpan.FromHours(2) };
+
+ ///
+ /// Sets an absolute expiration time, relative to now.
+ ///
+ ///
+ /// The default is 2 hours. Setting the will apply to every new
+ /// object instantiated by the method after this
+ /// change and before the next change.
+ /// If the object returned by the method already
+ /// existed in the cache before this change (cache hit) then the returned
+ /// object will have the value attributed to it that existed at the time
+ /// it was originally created.
+ ///
+ public static TimeSpan TimeToLive
+ {
+ get => encryptionKeyCache.TimeToLive.Value;
+ set => encryptionKeyCache.TimeToLive = value;
+ }
+
+ ///
+ /// Returns a cached instance of the or, if not present, creates a new one
+ ///
+ /// The name by which the will be known.
+ /// The unencrypted value.
+ /// An object.
+ public static PlaintextDataEncryptionKey GetOrCreate(string name, byte[] unencryptedKey)
+ {
+ name.ValidateNotNullOrWhitespace(nameof(name));
+ unencryptedKey.ValidateNotNullOrEmpty(nameof(unencryptedKey));
+
+ return encryptionKeyCache.GetOrCreate(
+ key: Tuple.Create(name, unencryptedKey.ToHexString()),
+ createItem: () => new PlaintextDataEncryptionKey(name, unencryptedKey)
+ );
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name by which the will be known.
+ ///
+ /// Generates a new 256 bit cryptographically strong random key.
+ ///
+ public PlaintextDataEncryptionKey(string name) : base(name, GenerateNewColumnEncryptionKey()) { }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The name by which the will be known.
+ /// The unencrypted value.
+ public PlaintextDataEncryptionKey(string name, byte[] unencryptedKey) : base(name, unencryptedKey) { }
+
+ private static byte[] GenerateNewColumnEncryptionKey()
+ {
+ byte[] plainTextColumnEncryptionKey = new byte[32];
+ RandomNumberGenerator rng = RandomNumberGenerator.Create();
+ rng.GetBytes(plainTextColumnEncryptionKey);
+
+ return plainTextColumnEncryptionKey;
+ }
+
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ if (!(obj is PlaintextDataEncryptionKey other))
+ {
+ return false;
+ }
+
+ return Name.Equals(other.Name) && RootKeyEquals(other);
+ }
+
+ ///
+ /// Generates a hash code for the current object.
+ ///
+ /// A hash code for the current object.
+ public override int GetHashCode() => Tuple.Create(Name, rootKeyHexString).GetHashCode();
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/ProtectedDataEncryptionKey.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/ProtectedDataEncryptionKey.cs
new file mode 100644
index 0000000000..e375ad9128
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/ProtectedDataEncryptionKey.cs
@@ -0,0 +1,135 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Security.Cryptography;
+
+namespace Microsoft.Data.Encryption.Cryptography
+{
+ ///
+ /// A , protected by a , that is used to encrypt and decrypt data.
+ ///
+ internal class ProtectedDataEncryptionKey : DataEncryptionKey
+ {
+ ///
+ /// A local cache to hold previously created objects for reuse.
+ ///
+ ///
+ /// The retension period is defined by the property.
+ ///
+ private static readonly LocalCache, ProtectedDataEncryptionKey> encryptionKeyCache
+ = new LocalCache, ProtectedDataEncryptionKey>() { TimeToLive = TimeSpan.FromHours(2) };
+
+ ///
+ /// Sets an absolute expiration time, relative to now.
+ ///
+ ///
+ /// The default is 2 hours. Setting the will apply to every new
+ /// object instantiated by the method after this
+ /// change and before the next change.
+ /// If the object returned by the method already
+ /// existed in the cache before this change (cache hit) then the returned
+ /// object will have the value attributed to it that existed at the time
+ /// it was originally created.
+ ///
+ public static TimeSpan TimeToLive
+ {
+ get => encryptionKeyCache.TimeToLive.Value;
+ set => encryptionKeyCache.TimeToLive = value;
+ }
+
+ ///
+ /// Specifies the used for encrypting and decrypting the .
+ ///
+ public KeyEncryptionKey KeyEncryptionKey { get; private set; }
+
+ ///
+ /// The encrypted value.
+ ///
+ public byte[] EncryptedValue { get; private set; }
+
+ ///
+ /// Returns a cached instance of the or, if not present, creates a new one
+ ///
+ /// The name by which the will be known.
+ /// Specifies the used for encrypting and decrypting the .
+ /// The encrypted value.
+ /// An object.
+ public static ProtectedDataEncryptionKey GetOrCreate(string name, KeyEncryptionKey keyEncryptionKey, byte[] encryptedKey)
+ {
+ name.ValidateNotNullOrWhitespace(nameof(name));
+ keyEncryptionKey.ValidateNotNull(nameof(keyEncryptionKey));
+ encryptedKey.ValidateNotNullOrEmpty(nameof(encryptedKey));
+
+ return encryptionKeyCache.GetOrCreate(
+ key: Tuple.Create(name, keyEncryptionKey, encryptedKey.ToHexString()),
+ createItem: () => new ProtectedDataEncryptionKey(name, keyEncryptionKey, encryptedKey)
+ );
+ }
+
+ ///
+ /// Initializes a new instance of the class derived from
+ /// generating an array of bytes with a cryptographically strong random sequence of values.
+ ///
+ /// The name by which the will be known.
+ /// Specifies the used for encrypting and decrypting the .
+ public ProtectedDataEncryptionKey(string name, KeyEncryptionKey keyEncryptionKey) : this(name, keyEncryptionKey, GenerateNewColumnEncryptionKey(keyEncryptionKey)) { }
+
+ ///
+ /// Initializes a new instance of the class derived from
+ /// decrypting the .
+ ///
+ /// The name by which the will be known.
+ /// Specifies the used for encrypting and decrypting the .
+ /// The encrypted value.
+ public ProtectedDataEncryptionKey(string name, KeyEncryptionKey keyEncryptionKey, byte[] encryptedKey) : base(name, keyEncryptionKey.DecryptEncryptionKey(encryptedKey))
+ {
+ name.ValidateNotNullOrWhitespace(nameof(name));
+ keyEncryptionKey.ValidateNotNull(nameof(keyEncryptionKey));
+
+ KeyEncryptionKey = keyEncryptionKey;
+ EncryptedValue = encryptedKey;
+ }
+
+ private static byte[] GenerateNewColumnEncryptionKey(KeyEncryptionKey masterKey)
+ {
+ byte[] plainTextColumnEncryptionKey = new byte[32];
+ RandomNumberGenerator rng = RandomNumberGenerator.Create();
+ rng.GetBytes(plainTextColumnEncryptionKey);
+
+ return masterKey.EncryptEncryptionKey(plainTextColumnEncryptionKey);
+ }
+
+ ///
+ /// Indicates whether the current object is equal to another object of the same type.
+ ///
+ /// An object to compare with this object.
+ /// true if the current object is equal to the other parameter; otherwise, false.
+ public override bool Equals(object obj)
+ {
+ if (!(obj is ProtectedDataEncryptionKey other))
+ {
+ return false;
+ }
+
+ if (KeyEncryptionKey.IsNull() && !other.KeyEncryptionKey.IsNull())
+ {
+ return false;
+ }
+
+ return Name.Equals(other.Name)
+ && KeyEncryptionKey.Equals(other.KeyEncryptionKey)
+ && RootKeyEquals(other);
+ }
+
+ ///
+ /// Generates a hash code for the current object.
+ ///
+ /// A hash code for the current object.
+ public override int GetHashCode() => Tuple.Create(Name, KeyEncryptionKey, rootKeyHexString).GetHashCode();
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/ISerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/ISerializer.cs
new file mode 100644
index 0000000000..0a4a99d253
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/ISerializer.cs
@@ -0,0 +1,65 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing data objects.
+ ///
+ internal interface ISerializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ string Identifier { get; }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ /// The serialized data as a byte array
+ byte[] Serialize(object value);
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ object Deserialize(byte[] bytes);
+ }
+
+
+ ///
+ /// Contains the methods for serializing and deserializing data objects.
+ ///
+ /// The type on which this will perform serialization operations.
+ internal abstract class Serializer : ISerializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public abstract string Identifier { get; }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ /// The serialized data as a byte array
+ public abstract byte[] Serialize(T value);
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ public abstract T Deserialize(byte[] bytes);
+
+ byte[] ISerializer.Serialize(object value) => Serialize((T)value);
+
+ object ISerializer.Deserialize(byte[] bytes) => Deserialize(bytes);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SerializerFactory.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SerializerFactory.cs
new file mode 100644
index 0000000000..2cd3b20895
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SerializerFactory.cs
@@ -0,0 +1,40 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Provides methods for getting serializer implementations, such as by type and ID.
+ ///
+ internal abstract class SerializerFactory
+ {
+ ///
+ /// Gets a registered serializer by its Identifier Property.
+ ///
+ /// The identifier uniquely identifies a particular Serializer implementation.
+ /// The ISerializer implementation
+ public abstract ISerializer GetSerializer(string identifier);
+
+ ///
+ /// Gets a default registered serializer for the type.
+ ///
+ /// The data type to be serialized.
+ /// A default registered serializer for the type.
+ public abstract Serializer GetDefaultSerializer();
+
+ ///
+ /// Registers a custom serializer.
+ ///
+ /// The data type on which the Serializer operates.
+ /// The Serializer to register.
+ /// Determines whether to override an existing default serializer for the same type.
+ public abstract void RegisterSerializer(Type type, ISerializer serializer, bool overrideDefault = false);
+
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializerFactory.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializerFactory.cs
new file mode 100644
index 0000000000..0796d29eb3
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializerFactory.cs
@@ -0,0 +1,222 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Collections.Generic;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Provides methods for getting serializer implementations, such as by type and ID.
+ ///
+ internal class SqlSerializerFactory : SerializerFactory
+ {
+ private readonly Dictionary serializerByType = new Dictionary();
+
+ private readonly Dictionary serializerByIdentifier = new Dictionary();
+
+ private static readonly Dictionary> createSerializerByType = new Dictionary>()
+ {
+ [typeof(SqlBitSerializer)] = (size, precision, scale, codepage) => new SqlBitSerializer(),
+ [typeof(SqlNullableBitSerializer)] = (size, precision, scale, codepage) => new SqlNullableBitSerializer(),
+ [typeof(SqlTinyIntSerializer)] = (size, precision, scale, codepage) => new SqlTinyIntSerializer(),
+ [typeof(SqlNullableTinyIntSerializer)] = (size, precision, scale, codepage) => new SqlNullableTinyIntSerializer(),
+ [typeof(SqlVarBinarySerializer)] = (size, precision, scale, codepage) => new SqlVarBinarySerializer(size),
+ [typeof(SqlDateTime2Serializer)] = (size, precision, scale, codepage) => new SqlDateTime2Serializer(precision),
+ [typeof(SqlNullableDateTime2Serializer)] = (size, precision, scale, codepage) => new SqlNullableDateTime2Serializer(precision),
+ [typeof(SqlDateTimeOffsetSerializer)] = (size, precision, scale, codepage) => new SqlDateTimeOffsetSerializer(scale),
+ [typeof(SqlNullableDateTimeOffsetSerializer)] = (size, precision, scale, codepage) => new SqlNullableDateTimeOffsetSerializer(scale),
+ [typeof(SqlDecimalSerializer)] = (size, precision, scale, codepage) => new SqlDecimalSerializer(precision, scale),
+ [typeof(SqlNullableDecimalSerializer)] = (size, precision, scale, codepage) => new SqlNullableDecimalSerializer(precision, scale),
+ [typeof(SqlFloatSerializer)] = (size, precision, scale, codepage) => new SqlFloatSerializer(),
+ [typeof(SqlNullableFloatSerializer)] = (size, precision, scale, codepage) => new SqlNullableFloatSerializer(),
+ [typeof(SqlRealSerializer)] = (size, precision, scale, codepage) => new SqlRealSerializer(),
+ [typeof(SqlNullableRealSerializer)] = (size, precision, scale, codepage) => new SqlNullableRealSerializer(),
+ [typeof(SqlUniqueIdentifierSerializer)] = (size, precision, scale, codepage) => new SqlUniqueIdentifierSerializer(),
+ [typeof(SqlNullableUniqueIdentifierSerializer)] = (size, precision, scale, codepage) => new SqlNullableUniqueIdentifierSerializer(),
+ [typeof(SqlIntSerializer)] = (size, precision, scale, codepage) => new SqlIntSerializer(),
+ [typeof(SqlNullableIntSerializer)] = (size, precision, scale, codepage) => new SqlNullableIntSerializer(),
+ [typeof(SqlBigIntSerializer)] = (size, precision, scale, codepage) => new SqlBigIntSerializer(),
+ [typeof(SqlNullableBigIntSerializer)] = (size, precision, scale, codepage) => new SqlNullableBigIntSerializer(),
+ [typeof(SqlSmallIntSerializer)] = (size, precision, scale, codepage) => new SqlSmallIntSerializer(),
+ [typeof(SqlNullableSmallIntSerializer)] = (size, precision, scale, codepage) => new SqlNullableSmallIntSerializer(),
+ [typeof(SqlNVarCharSerializer)] = (size, precision, scale, codepage) => new SqlNVarCharSerializer(size),
+ [typeof(SqlTimeSerializer)] = (size, precision, scale, codepage) => new SqlTimeSerializer(scale),
+ [typeof(SqlNullableTimeSerializer)] = (size, precision, scale, codepage) => new SqlNullableTimeSerializer(scale),
+ [typeof(SqlBinarySerializer)] = (size, precision, scale, codepage) => new SqlBinarySerializer(size),
+ [typeof(SqlDateSerializer)] = (size, precision, scale, codepage) => new SqlDateSerializer(),
+ [typeof(SqlNullableDateSerializer)] = (size, precision, scale, codepage) => new SqlNullableDateSerializer(),
+ [typeof(SqlDateTimeSerializer)] = (size, precision, scale, codepage) => new SqlDateTimeSerializer(),
+ [typeof(SqlNullableDateTimeSerializer)] = (size, precision, scale, codepage) => new SqlNullableDateTimeSerializer(),
+ [typeof(SqlSmallDateTimeSerializer)] = (size, precision, scale, codepage) => new SqlSmallDateTimeSerializer(),
+ [typeof(SqlNullableSmallDateTimeSerializer)] = (size, precision, scale, codepage) => new SqlNullableSmallDateTimeSerializer(),
+ [typeof(SqlMoneySerializer)] = (size, precision, scale, codepage) => new SqlMoneySerializer(),
+ [typeof(SqlNullableMoneySerializer)] = (size, precision, scale, codepage) => new SqlNullableMoneySerializer(),
+ [typeof(SqlNumericSerializer)] = (size, precision, scale, codepage) => new SqlNumericSerializer(precision, scale),
+ [typeof(SqlNullableNumericSerializer)] = (size, precision, scale, codepage) => new SqlNullableNumericSerializer(precision, scale),
+ [typeof(SqlSmallMoneySerializer)] = (size, precision, scale, codepage) => new SqlSmallMoneySerializer(),
+ [typeof(SqlNullableSmallMoneySerializer)] = (size, precision, scale, codepage) => new SqlNullableSmallMoneySerializer(),
+ [typeof(SqlNCharSerializer)] = (size, precision, scale, codepage) => new SqlNCharSerializer(size),
+ [typeof(SqlCharSerializer)] = (size, precision, scale, codepage) => new SqlCharSerializer(size, codepage),
+ [typeof(SqlVarCharSerializer)] = (size, precision, scale, codepage) => new SqlVarCharSerializer(size, codepage),
+ };
+
+ private static readonly LocalCache, ISerializer> serializerCache
+ = new LocalCache, ISerializer>();
+
+ ///
+ /// Returns a cached instance of the or, if not present, creates a new one.
+ ///
+ /// The type of serializer to get or create.
+ /// The maximum size of the data.
+ /// The maximum number of digits.
+ /// The number of decimal places.
+ /// The code page character encoding.
+ /// An object.
+ public static ISerializer GetOrCreate(Type serializerType, int size = 1, byte precision = 1, byte scale = 1, int codepage = 1)
+ {
+ serializerType.ValidateNotNull(nameof(serializerType));
+
+ return serializerCache.GetOrCreate(
+ key: Tuple.Create(serializerType, size, precision, scale, codepage),
+ createItem: () => createSerializerByType[serializerType].Invoke(size, precision, scale, codepage)
+ );
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public SqlSerializerFactory()
+ {
+ Initialize();
+ }
+
+ ///
+ /// Returns a default instance of the class.
+ ///
+ public static SqlSerializerFactory Default { get; } = new SqlSerializerFactory();
+
+ ///
+ /// Gets a registered serializer by its Identifier Property.
+ ///
+ /// The identifier uniquely identifies a particular Serializer implementation.
+ /// The ISerializer implementation
+ public override ISerializer GetSerializer(string identifier)
+ {
+ identifier.ValidateNotNull(nameof(identifier));
+
+ if (serializerByIdentifier.ContainsKey(identifier))
+ {
+ return serializerByIdentifier[identifier];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets a default registered serializer for the type.
+ ///
+ /// The data type to be serialized.
+ /// A default registered serializer for the type.
+ public override Serializer GetDefaultSerializer()
+ {
+ if (serializerByType.ContainsKey(typeof(T)))
+ {
+ return (Serializer)serializerByType[typeof(T)];
+ }
+
+ throw new MicrosoftDataEncryptionException(DefaultAESerializerNotFound.Format(typeof(T).Name, nameof(RegisterSerializer)));
+ }
+
+ ///
+ /// Registers a custom serializer.
+ ///
+ /// The data type on which the Serializer operates.
+ /// The Serializer to register.
+ /// Determines whether to override an existing default serializer for the same type.
+ public override void RegisterSerializer(Type type, ISerializer serializer, bool overrideDefault = false)
+ {
+ type.ValidateNotNull(nameof(type));
+ serializer.ValidateNotNull(nameof(serializer));
+
+ serializerByIdentifier[serializer.Identifier] = serializer;
+
+ if (overrideDefault || !HasDefaultSqlSerializer(type))
+ {
+ serializerByType[type] = serializer;
+ }
+ }
+
+ private bool HasDefaultSerializer(Type type)
+ {
+ return serializerByType.ContainsKey(type);
+ }
+
+ private bool HasDefaultSqlSerializer(Type type)
+ {
+ return serializerByType.ContainsKey(type);
+ }
+
+ private void Initialize()
+ {
+ RegisterDefaultSqlSerializers();
+ RegisterNonDefaultSqlSerializers();
+ }
+
+ private void RegisterDefaultSqlSerializers()
+ {
+ RegisterSerializer(typeof(bool), new SqlBitSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(bool?), new SqlNullableBitSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(byte), new SqlTinyIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(byte?), new SqlNullableTinyIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(byte[]), new SqlVarBinarySerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTime), new SqlDateTime2Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTime?), new SqlNullableDateTime2Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTimeOffset), new SqlDateTimeOffsetSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTimeOffset?), new SqlNullableDateTimeOffsetSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(decimal), new SqlDecimalSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(decimal?), new SqlNullableDecimalSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(double), new SqlFloatSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(double?), new SqlNullableFloatSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(float), new SqlRealSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(float?), new SqlNullableRealSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(Guid), new SqlUniqueIdentifierSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(Guid?), new SqlNullableUniqueIdentifierSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(int), new SqlIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(int?), new SqlNullableIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(long), new SqlBigIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(long?), new SqlNullableBigIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(short), new SqlSmallIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(short?), new SqlNullableSmallIntSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(string), new SqlNVarCharSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(TimeSpan), new SqlTimeSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(TimeSpan?), new SqlNullableTimeSerializer(), overrideDefault: true);
+ }
+
+ private void RegisterNonDefaultSqlSerializers()
+ {
+ RegisterSerializer(typeof(byte[]), new SqlBinarySerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(DateTime), new SqlDateSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(DateTime?), new SqlNullableDateSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(DateTime), new SqlDateTimeSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(DateTime?), new SqlNullableDateTimeSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(DateTime), new SqlSmallDateTimeSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(DateTime), new SqlNullableSmallDateTimeSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(decimal), new SqlMoneySerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(decimal?), new SqlNullableMoneySerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(decimal), new SqlNumericSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(decimal?), new SqlNullableNumericSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(decimal), new SqlSmallMoneySerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(decimal?), new SqlNullableSmallMoneySerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(string), new SqlNCharSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(string), new SqlCharSerializer(), overrideDefault: false);
+ RegisterSerializer(typeof(string), new SqlVarCharSerializer(), overrideDefault: false);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBigIntSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBigIntSerializer.cs
new file mode 100644
index 0000000000..6155939cb9
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBigIntSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlBigIntSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_BigInt";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override long Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(long), nameof(bytes));
+
+ return ToInt64(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(long value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBinarySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBinarySerializer.cs
new file mode 100644
index 0000000000..b80c74e2ec
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBinarySerializer.cs
@@ -0,0 +1,100 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.Linq.Enumerable;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing [] type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlBinarySerializer : Serializer
+ {
+ private const int DefaultSize = 30;
+ private const int MinSize = 1;
+ private const int MaxSize = 8000;
+ private static readonly byte Padding = 0;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Binary_Nullable";
+
+ private int size;
+
+ ///
+ /// Gets or sets the maximum length of the data.
+ ///
+ ///
+ /// If not explicitly set, the size is defaulted to 30.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 8000] for this setting.
+ ///
+ public int Size
+ {
+ get => size;
+ set
+ {
+ if (value < MinSize || value > MaxSize)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ size = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum length of the data
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 8000] for this setting.
+ ///
+ public SqlBinarySerializer(int size = DefaultSize)
+ {
+ Size = size;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// If the deserialized value is less than the size, then the value will be padded on the
+ /// left to match the size. Padding is achieved by using hexadecimal zeros.
+ ///
+ public override byte[] Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? null : PadToLength(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ /// The serialized data as a byte array
+ ///
+ /// If the value is greater than the size, then the value will be truncated on the left to match the size.
+ ///
+ public override byte[] Serialize(byte[] value)
+ {
+ return value.IsNull() ? null : TrimToLength(value);
+ }
+
+ private byte[] TrimToLength(byte[] value) => value.Length > Size ? value.Take(Size).ToArray() : value;
+
+ private byte[] PadToLength(byte[] value) => value.Length < Size ? value.Concat(Repeat(Padding, Size - value.Length)).ToArray() : value;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBitSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBitSerializer.cs
new file mode 100644
index 0000000000..30fa11b4aa
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlBitSerializer.cs
@@ -0,0 +1,55 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlBitSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Bit";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override bool Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(long), nameof(bytes));
+
+ return ToBoolean(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(bool value)
+ {
+ long longValue = value ? 1 : 0;
+ return GetBytes(longValue);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlCharSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlCharSerializer.cs
new file mode 100644
index 0000000000..54a305ed8d
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlCharSerializer.cs
@@ -0,0 +1,122 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+using System.Text;
+
+using static System.Text.Encoding;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlCharSerializer : SqlCodePageEncodingSerializer
+ {
+ private const int DefaultSize = 30;
+ private const int MinSize = 1;
+ private const int MaxSize = 8000;
+ private static readonly char Padding = ' ';
+
+ ///
+ /// The default character encoding Windows-1252. It is also referred to as "ANSI".
+ ///
+ private const int DefaultEncodingCodePoint = 1252;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Char_Nullable";
+
+ private int size;
+
+ ///
+ /// Gets or sets the maximum length of the data.
+ ///
+ ///
+ /// If not explicitly set, the size is defaulted to 30.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 8000] for this setting.
+ ///
+ public int Size
+ {
+ get => size;
+ set
+ {
+ if (value < MinSize || value > MaxSize)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ size = value;
+ }
+ }
+
+ private Encoding characterEncoding;
+
+ ///
+ /// Gets or sets the character encoding.
+ ///
+ ///
+ /// If not explicitly set, the encoding is defaulted to Windows-1252, which is also referred to as "ANSI".
+ ///
+ public int CodePageCharacterEncoding
+ {
+ get => characterEncoding.CodePage;
+ set => characterEncoding = GetEncoding(value);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum length of the data
+ /// The code page character encoding.
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 8000] for this setting.
+ ///
+ public SqlCharSerializer(int size = DefaultSize, int codePageCharacterEncoding = DefaultEncodingCodePoint)
+ {
+ Size = size;
+ characterEncoding = GetEncoding(codePageCharacterEncoding);
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// If the deserialized value's length is less than the size, then the value will be padded on the
+ /// left to match the size. Padding is achieved by using spaces.
+ ///
+ public override string Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? null : PadToLength(characterEncoding.GetString(bytes));
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ /// The serialized data as a byte array
+ ///
+ /// If the value's length is greater than the size, then the value will be truncated on the left to match the size.
+ ///
+ public override byte[] Serialize(string value)
+ {
+ return value.IsNull() ? null : characterEncoding.GetBytes(TrimToLength(value));
+ }
+
+ private string TrimToLength(string value) => value.Length > Size ? new string(value.Take(Size).ToArray()) : value;
+
+ private string PadToLength(string value) => value.Length < Size ? value.PadRight(Size, Padding) : value;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlCodePageEncodingSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlCodePageEncodingSerializer.cs
new file mode 100644
index 0000000000..b5e9b08d54
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlCodePageEncodingSerializer.cs
@@ -0,0 +1,31 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System.Text;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Provides the base class for an encoding provider serializer, which supplies encodings that may be unavailable on a particular platform.
+ ///
+ ///
+ /// For .NET Core, we need to register the before attempting to get an Encoding from a CodePage
+ /// For a default installation of SqlServer the encoding exchanged during Login is 1252. This encoding is not loaded by default.
+ /// See Remarks at https://msdn.microsoft.com/en-us/library/system.text.encodingprovider(v=vs.110).aspx.
+ ///
+ internal abstract class SqlCodePageEncodingSerializer : Serializer
+ {
+ ///
+ /// Static constructor is called at most one time, before any
+ /// instance constructor is invoked or member is accessed.
+ ///
+ static SqlCodePageEncodingSerializer()
+ {
+ Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDateSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDateSerializer.cs
new file mode 100644
index 0000000000..5fe72ec0e1
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDateSerializer.cs
@@ -0,0 +1,61 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlDateSerializer : Serializer
+ {
+ private const int SizeOfDate = 3;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Date";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 3.
+ ///
+ public override DateTime Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfDate, nameof(bytes));
+
+ byte[] padding = { 0 };
+ byte[] bytesWithPadding = bytes.Concat(padding).ToArray();
+ int days = ToInt32(bytesWithPadding, 0);
+ return DateTime.MinValue.AddDays(days);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 3.
+ ///
+ public override byte[] Serialize(DateTime value)
+ {
+ int days = value.Subtract(DateTime.MinValue).Days;
+ return GetBytes(days).Take(SizeOfDate).ToArray();
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetime2Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetime2Serializer.cs
new file mode 100644
index 0000000000..64d64d8054
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetime2Serializer.cs
@@ -0,0 +1,116 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Cryptography.Serializers.SqlTimeSerializer;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlDateTime2Serializer : Serializer
+ {
+ private const int MaxPrecision = 7;
+ private const int MinPrecision = 0;
+ private const int DefaultPrecision = 7;
+ private readonly SqlDateSerializer sqlDateSerializer = new SqlDateSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_DateTime2";
+
+ private int precision;
+
+ ///
+ /// Gets or sets the maximum number of digits used to represent the Value. The default is 7.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public int Precision
+ {
+ get { return precision; }
+ set
+ {
+ if (value < MinPrecision || value > MaxPrecision)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+ precision = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of decimal places to which Value is resolved
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public SqlDateTime2Serializer(int precision = DefaultPrecision)
+ {
+ Precision = precision;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override DateTime Deserialize(byte[] bytes)
+ {
+ const int SizeOfTimePart = 5;
+ const int SizeOfDatePart = 3;
+ const int SizeOfData = SizeOfTimePart + SizeOfDatePart;
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfData, nameof(bytes));
+
+ byte[] padding = { 0, 0, 0 };
+ byte[] timePart = bytes.Take(SizeOfTimePart).Concat(padding).ToArray();
+ byte[] datePart = bytes.Skip(SizeOfTimePart).Take(SizeOfDatePart).ToArray();
+
+ long timeTicks = ToInt64(timePart, 0);
+ DateTime dateTime = sqlDateSerializer.Deserialize(datePart);
+ return dateTime.AddTicks(timeTicks);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(DateTime value)
+ {
+ DateTime normalizedValue = NormalizeToScale(value, Precision);
+ long time = normalizedValue.TimeOfDay.Ticks;
+ byte[] timePart = GetBytes(time).Take(5).ToArray();
+ byte[] datePart = sqlDateSerializer.Serialize(value);
+ return timePart.Concat(datePart).ToArray();
+ }
+
+ private static DateTime NormalizeToScale(DateTime dateTime, int scale)
+ {
+ long normalizedTicksOffset = (dateTime.TimeOfDay.Ticks / precisionScale[scale] * precisionScale[scale]) - dateTime.TimeOfDay.Ticks;
+ return dateTime.AddTicks(normalizedTicksOffset);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetimeSerializer.cs
new file mode 100644
index 0000000000..3eaa3c96c2
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetimeSerializer.cs
@@ -0,0 +1,78 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Data.SqlTypes;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlDateTimeSerializer : Serializer
+ {
+ private static readonly DateTime MinValue = DateTime.Parse("1753-01-01 00:00:00");
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_DateTime";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override DateTime Deserialize(byte[] bytes)
+ {
+ const int SizeOfDate = 4;
+ const int SizeOfTime = 4;
+ const int SizeOfDateTime = SizeOfDate + SizeOfTime;
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfDateTime, nameof(bytes));
+
+ int dayTicks = ToInt32(bytes.Take(SizeOfDate).ToArray(), 0);
+ int timeTicks = ToInt32(bytes.Skip(SizeOfDate).Take(SizeOfTime).ToArray(), 0);
+ SqlDateTime sqlDateTime = new SqlDateTime(dayTicks, timeTicks);
+ return sqlDateTime.Value;
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(DateTime value)
+ {
+ if (value < MinValue)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ SqlDateTime sqlDateTime = new SqlDateTime(value);
+ byte[] dayTicks = GetBytes(sqlDateTime.DayTicks);
+ byte[] timeTicks = GetBytes(sqlDateTime.TimeTicks);
+ return dayTicks.Concat(timeTicks).ToArray();
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetimeoffsetSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetimeoffsetSerializer.cs
new file mode 100644
index 0000000000..6bf43db6df
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDatetimeoffsetSerializer.cs
@@ -0,0 +1,109 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL.
+ ///
+ internal sealed class SqlDateTimeOffsetSerializer : Serializer
+ {
+ private const int MaxScale = 7;
+ private const int MinScale = 0;
+ private const int DefaultScale = 7;
+ private readonly SqlDateTime2Serializer sqlDateTime2Serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_DateTimeOffset";
+
+ private int scale;
+
+ ///
+ /// Gets or sets the number of decimal places to which Value is resolved. The default is 7.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public int Scale
+ {
+ get => scale;
+ set
+ {
+ if (value < MinScale || value > MaxScale)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+ scale = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of decimal places to which Value is resolved.
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public SqlDateTimeOffsetSerializer(int scale = DefaultScale)
+ {
+ Scale = scale;
+ sqlDateTime2Serializer = new SqlDateTime2Serializer(scale);
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 10.
+ ///
+ public override DateTimeOffset Deserialize(byte[] bytes)
+ {
+ const int DateTimeIndex = 0;
+ const int TimeSpanIndex = sizeof(long);
+ const int DataSize = sizeof(long) + sizeof(short);
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(DataSize, nameof(bytes));
+
+ byte[] dateTimePart = bytes.Skip(DateTimeIndex).Take(sizeof(long)).ToArray();
+ byte[] offsetPart = bytes.Skip(TimeSpanIndex).Take(sizeof(short)).ToArray();
+
+ short minutes = ToInt16(offsetPart, 0);
+ DateTime dateTime = sqlDateTime2Serializer.Deserialize(dateTimePart).AddMinutes(minutes);
+ TimeSpan offset = new TimeSpan(0, minutes, 0);
+ return new DateTimeOffset(dateTime, offset);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 10.
+ ///
+ public override byte[] Serialize(DateTimeOffset value)
+ {
+ byte[] datetimePart = sqlDateTime2Serializer.Serialize(value.UtcDateTime);
+ short offsetMinutes = (short)value.Offset.TotalMinutes;
+ byte[] offsetPart = GetBytes(offsetMinutes);
+ return datetimePart.Concat(offsetPart).ToArray();
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDecimalSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDecimalSerializer.cs
new file mode 100644
index 0000000000..52e7f270b3
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlDecimalSerializer.cs
@@ -0,0 +1,159 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Data.SqlTypes;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal sealed class SqlDecimalSerializer : Serializer
+ {
+ private const int SignIndex = 3;
+ private const int MaxPrecision = 38;
+ private const int MinPrecision = 1;
+ private const int DefaultPrecision = 18;
+ private const int MinScale = 0;
+ private const int DefaultScale = 0;
+ private static readonly byte[] positiveSign = { 1 };
+ private static readonly byte[] negativeSign = { 0 };
+ private static readonly byte[] padding = { 0, 0, 0, 0 };
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Decimal";
+
+ private int precision;
+
+ ///
+ /// Gets or sets the maximum number of digits used to represent the value. The default precision is 18.
+ ///
+ ///
+ /// The represents the maximum total number of decimal digits to be stored.
+ /// This number includes both the left and the right sides of the decimal point.
+ /// The precision must be a value from 1 through the maximum precision of 38.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 38] for this setting.
+ ///
+ public int Precision
+ {
+ get => precision;
+ set
+ {
+ if (value < MinPrecision || value > MaxPrecision)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ precision = value;
+ }
+ }
+
+ private int scale;
+
+ ///
+ /// Gets or sets the number of decimal places to which Value is resolved.
+ ///
+ ///
+ /// The number of decimal digits that are stored to the right of the decimal point. This number is subtracted from the
+ /// to determine the maximum number of digits to the left of the decimal point. must be a value from 0 through .
+ /// The default scale is 0 and so 0 ≤ ≤ .
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public int Scale
+ {
+ get => scale;
+ set
+ {
+ if (value < MinScale || value > Precision)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ scale = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum number of digits used to represent the value. The default precision is 18.
+ /// The number of decimal places to which Value is resolved. The default scale is 0.
+ ///
+ /// Thrown when is set to a value that is out of the valid range [1 - 38] or when
+ /// is set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public SqlDecimalSerializer(int precision = DefaultPrecision, int scale = DefaultScale)
+ {
+ Precision = precision;
+ Scale = scale;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 17.
+ ///
+ public override decimal Deserialize(byte[] bytes)
+ {
+ const int SizeOfDecimal = 17;
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfDecimal, nameof(bytes));
+
+ int low = ToInt32(bytes.Skip(1).Take(4).ToArray(), 0);
+ int middle = ToInt32(bytes.Skip(5).Take(4).ToArray(), 0);
+ int high = ToInt32(bytes.Skip(9).Take(4).ToArray(), 0);
+ bool isNegative = bytes[0] == negativeSign[0];
+
+ return new decimal(low, middle, high, isNegative, (byte)Scale);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 17.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal value)
+ {
+ SqlDecimal sqlDecimal = new SqlDecimal(value);
+
+ if (sqlDecimal.Precision > Precision)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ int[] decimalBits = decimal.GetBits(value);
+ byte[] sign = IsPositive(decimalBits[SignIndex]) ? positiveSign : negativeSign;
+ byte[] integerPart = decimalBits.Take(3).SelectMany(GetBytes).ToArray();
+ return sign.Concat(integerPart).Concat(padding).ToArray();
+ }
+
+ private bool IsPositive(int i) => i > -1;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlFloatSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlFloatSerializer.cs
new file mode 100644
index 0000000000..3eb1bedabb
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlFloatSerializer.cs
@@ -0,0 +1,64 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal sealed class SqlFloatSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Float";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override double Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(double), nameof(bytes));
+
+ return ToDouble(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(double value)
+ {
+ if (double.IsInfinity(value) || double.IsNaN(value))
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ return GetBytes(value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlIntSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlIntSerializer.cs
new file mode 100644
index 0000000000..dc99e63f34
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlIntSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal sealed class SqlIntSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Int";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override int Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(long), nameof(bytes));
+
+ return ToInt32(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(int value) => GetBytes((long)value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlMoneySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlMoneySerializer.cs
new file mode 100644
index 0000000000..7d7aeab079
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlMoneySerializer.cs
@@ -0,0 +1,93 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Data.SqlTypes;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal sealed class SqlMoneySerializer : Serializer
+ {
+ private const byte Scale = 4;
+ private const decimal MinValue = -922337203685477.5808M;
+ private const decimal MaxValue = 922337203685477.5807M;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Money";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override decimal Deserialize(byte[] bytes)
+ {
+ const int SizeOfData = 8;
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfData, nameof(bytes));
+
+ uint low = ToUInt32(bytes, 4);
+ int middle = ToInt32(bytes, 0);
+ long longValue = ((long)middle << 32) + low;
+ bool isNegative = longValue < 0;
+ int sign = isNegative ? -1 : 1;
+ long signedLongValue = longValue * sign;
+ int signedLow = (int)(signedLongValue & uint.MaxValue);
+ int signedMiddle = (int)(signedLongValue >> 32);
+
+ return new decimal(signedLow, signedMiddle, 0, isNegative, Scale);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal value)
+ {
+ if (value < MinValue || value > MaxValue)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ value = Normalize(value);
+ int sign = value > -1 ? 1 : -1;
+ int[] decimalBits = decimal.GetBits(value);
+ long longValue = ((long)decimalBits[1] << 32) + (uint)decimalBits[0];
+ long signedLongValue = longValue * sign;
+ int low = (int)(signedLongValue >> 32);
+ int mid = (int)signedLongValue;
+ byte[] lowbytes = GetBytes(low);
+ byte[] midBytes = GetBytes(mid);
+
+ return lowbytes.Concat(midBytes).ToArray();
+ }
+
+ private decimal Normalize(decimal value) => new SqlMoney(value).Value;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNcharSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNcharSerializer.cs
new file mode 100644
index 0000000000..dd9b9e7682
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNcharSerializer.cs
@@ -0,0 +1,100 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System.Linq;
+
+using static System.Linq.Enumerable;
+using static System.Text.Encoding;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal sealed class SqlNCharSerializer : Serializer
+ {
+ private const int MinSize = 1;
+ private const int MaxSize = 4000;
+ private const int DefaultSize = 30;
+ private static readonly char Padding = ' ';
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_NChar_Nullable";
+
+ private int size;
+
+ ///
+ /// Gets or sets the maximum length of the data.
+ ///
+ ///
+ /// If not explicitly set, the size is defaulted to 30.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 4000] for this setting.
+ ///
+ public int Size
+ {
+ get => size;
+ set
+ {
+ if (value < MinSize || value > MaxSize)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ size = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum length of the data
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 4000] for this setting.
+ ///
+ public SqlNCharSerializer(int size = DefaultSize)
+ {
+ Size = size;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// If the deserialized value's length is less than the size, then the value will be padded on the
+ /// left to match the size. Padding is achieved by using spaces.
+ ///
+ public override string Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? null : PadToLength(Unicode.GetString(bytes));
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ /// The serialized data as a byte array
+ ///
+ /// If the value's length is greater than the size, then the value will be truncated on the left to match the size.
+ ///
+ public override byte[] Serialize(string value)
+ {
+ return value.IsNull() ? null : Unicode.GetBytes(TrimToLength(value));
+ }
+
+ private string TrimToLength(string value) => value.Length > Size ? new string(value.Take(Size).ToArray()) : value;
+
+ private string PadToLength(string value) => value.Length < Size ? value.PadRight(Size, Padding) : value;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableBigIntSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableBigIntSerializer.cs
new file mode 100644
index 0000000000..de11090f99
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableBigIntSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableBigIntSerializer : Serializer
+ {
+ private static readonly SqlBigIntSerializer serializer = new SqlBigIntSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_BigInt_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override long? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (long?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(long? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableBitSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableBitSerializer.cs
new file mode 100644
index 0000000000..81ade73ef9
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableBitSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableBitSerializer : Serializer
+ {
+ private static readonly SqlBitSerializer serializer = new SqlBitSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Bit_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override bool? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (bool?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(bool? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDateSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDateSerializer.cs
new file mode 100644
index 0000000000..fe10ff7d78
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDateSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableDateSerializer : Serializer
+ {
+ private static readonly SqlDateSerializer serializer = new SqlDateSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Date_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 3.
+ ///
+ public override DateTime? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTime?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 3.
+ ///
+ public override byte[] Serialize(DateTime? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetime2Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetime2Serializer.cs
new file mode 100644
index 0000000000..9415fee1f3
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetime2Serializer.cs
@@ -0,0 +1,76 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableDateTime2Serializer : Serializer
+ {
+ private const int DefaultPrecision = 7;
+
+ private readonly SqlDateTime2Serializer serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_DateTime2_Nullable";
+
+ ///
+ /// Gets or sets the maximum number of digits used to represent the Value. The default is 7.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public int Precision
+ {
+ get => serializer.Precision;
+ set => serializer.Precision = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of decimal places to which Value is resolved
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public SqlNullableDateTime2Serializer(int precision = DefaultPrecision)
+ {
+ serializer = new SqlDateTime2Serializer(precision);
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override DateTime? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTime?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(DateTime? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetimeSerializer.cs
new file mode 100644
index 0000000000..6320d62adf
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetimeSerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableDateTimeSerializer : Serializer
+ {
+ private static readonly SqlDateTimeSerializer serializer = new SqlDateTimeSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_DateTime_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override DateTime? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTime?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(DateTime? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetimeoffsetSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetimeoffsetSerializer.cs
new file mode 100644
index 0000000000..8e04d50972
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDatetimeoffsetSerializer.cs
@@ -0,0 +1,76 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableDateTimeOffsetSerializer : Serializer
+ {
+ private const int DefaultScale = 7;
+ private readonly SqlDateTimeOffsetSerializer serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_DateTimeOffset_Nullable";
+
+ ///
+ /// Gets or sets the number of decimal places to which Value is resolved. The default is 7.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public int Scale
+ {
+ get => serializer.Scale;
+ set => serializer.Scale = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of decimal places to which Value is resolved.
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public SqlNullableDateTimeOffsetSerializer(int scale = DefaultScale)
+ {
+ serializer = new SqlDateTimeOffsetSerializer(scale);
+ }
+
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 10.
+ ///
+ public override DateTimeOffset? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTimeOffset?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 10.
+ ///
+ public override byte[] Serialize(DateTimeOffset? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDecimalSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDecimalSerializer.cs
new file mode 100644
index 0000000000..7c3fb6a60d
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableDecimalSerializer.cs
@@ -0,0 +1,104 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableDecimalSerializer : Serializer
+ {
+ private const int DefaultPrecision = 18;
+ private const int DefaultScale = 0;
+ private readonly SqlDecimalSerializer serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Decimal_Nullable";
+
+ ///
+ /// Gets or sets the maximum number of digits used to represent the value. The default precision is 18.
+ ///
+ ///
+ /// The represents the maximum total number of decimal digits to be stored.
+ /// This number includes both the left and the right sides of the decimal point.
+ /// The precision must be a value from 1 through the maximum precision of 38.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 38] for this setting.
+ ///
+ public int Precision
+ {
+ get => serializer.Precision;
+ set => serializer.Precision = value;
+ }
+
+ ///
+ /// Gets or sets the number of decimal places to which Value is resolved.
+ ///
+ ///
+ /// The number of decimal digits that are stored to the right of the decimal point. This number is subtracted from the
+ /// to determine the maximum number of digits to the left of the decimal point. must be a value from 0 through .
+ /// The default scale is 0 and so 0 ≤ ≤ .
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public int Scale
+ {
+ get => serializer.Scale;
+ set => serializer.Scale = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum number of digits used to represent the value. The default precision is 18.
+ /// The number of decimal places to which Value is resolved. The default scale is 0.
+ ///
+ /// Thrown when is set to a value that is out of the valid range [1 - 38] or when
+ /// is set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public SqlNullableDecimalSerializer(int precision = DefaultPrecision, int scale = DefaultScale)
+ {
+ serializer = new SqlDecimalSerializer(precision, scale);
+ }
+
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 17.
+ ///
+ public override decimal? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (decimal?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 17.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableFloatSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableFloatSerializer.cs
new file mode 100644
index 0000000000..ecb6df7688
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableFloatSerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableFloatSerializer : Serializer
+ {
+ private static readonly SqlFloatSerializer serializer = new SqlFloatSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Float_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override double? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (double?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(double? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableIntSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableIntSerializer.cs
new file mode 100644
index 0000000000..05b51d80c6
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableIntSerializer.cs
@@ -0,0 +1,48 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableIntSerializer : Serializer
+ {
+ private static readonly SqlIntSerializer serializer = new SqlIntSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Int_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override int? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (int?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(int? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableMoneySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableMoneySerializer.cs
new file mode 100644
index 0000000000..4e6115f748
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableMoneySerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableMoneySerializer : Serializer
+ {
+ private static readonly SqlMoneySerializer serializer = new SqlMoneySerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Money_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override decimal? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (decimal?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableNumericSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableNumericSerializer.cs
new file mode 100644
index 0000000000..b98dd7fd0e
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableNumericSerializer.cs
@@ -0,0 +1,104 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableNumericSerializer : Serializer
+ {
+ private const int DefaultPrecision = 18;
+ private const int DefaultScale = 0;
+ private readonly SqlNumericSerializer serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Numeric_Nullable";
+
+ ///
+ /// Gets or sets the maximum number of digits used to represent the value. The default precision is 18.
+ ///
+ ///
+ /// The represents the maximum total number of decimal digits to be stored.
+ /// This number includes both the left and the right sides of the decimal point.
+ /// The precision must be a value from 1 through the maximum precision of 38.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 38] for this setting.
+ ///
+ public int Precision
+ {
+ get => serializer.Precision;
+ set => serializer.Precision = value;
+ }
+
+ ///
+ /// Gets or sets the number of decimal places to which Value is resolved.
+ ///
+ ///
+ /// The number of decimal digits that are stored to the right of the decimal point. This number is subtracted from the
+ /// to determine the maximum number of digits to the left of the decimal point. must be a value from 0 through .
+ /// The default scale is 0 and so 0 ≤ ≤ .
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public int Scale
+ {
+ get => serializer.Scale;
+ set => serializer.Scale = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum number of digits used to represent the value. The default precision is 18.
+ /// The number of decimal places to which Value is resolved. The default scale is 0.
+ ///
+ /// Thrown when is set to a value that is out of the valid range [1 - 38] or when
+ /// is set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public SqlNullableNumericSerializer(int precision = DefaultPrecision, int scale = DefaultScale)
+ {
+ serializer = new SqlNumericSerializer(precision, scale);
+ }
+
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 17.
+ ///
+ public override decimal? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (decimal?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 17.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableRealSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableRealSerializer.cs
new file mode 100644
index 0000000000..4d2c4d1e48
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableRealSerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableRealSerializer : Serializer
+ {
+ private static readonly SqlRealSerializer serializer = new SqlRealSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Real_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 4.
+ ///
+ public override float? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (float?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(float? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmalldatetimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmalldatetimeSerializer.cs
new file mode 100644
index 0000000000..d4a9f06371
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmalldatetimeSerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableSmallDateTimeSerializer : Serializer
+ {
+ private static readonly SqlSmallDateTimeSerializer serializer = new SqlSmallDateTimeSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_SmallDateTime_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 4.
+ ///
+ public override DateTime? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTime?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(DateTime? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmallintSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmallintSerializer.cs
new file mode 100644
index 0000000000..ce66882295
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmallintSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableSmallIntSerializer : Serializer
+ {
+ private static readonly SqlSmallIntSerializer serializer = new SqlSmallIntSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_SmallInt_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override short? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (short?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(short? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmallmoneySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmallmoneySerializer.cs
new file mode 100644
index 0000000000..bbe658ae88
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableSmallmoneySerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableSmallMoneySerializer : Serializer
+ {
+ private static readonly SqlSmallMoneySerializer serializer = new SqlSmallMoneySerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_SmallMoney_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override decimal? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (decimal?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableTimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableTimeSerializer.cs
new file mode 100644
index 0000000000..e4665adfc0
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableTimeSerializer.cs
@@ -0,0 +1,81 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableTimeSerializer : Serializer
+ {
+ private const int DefaultScale = 7;
+ private readonly SqlTimeSerializer serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Time_Nullable";
+
+ ///
+ /// Gets or sets the number of digits for the fractional part of the seconds.
+ ///
+ ///
+ /// This can be an integer from 0 to 7. The default fractional scale is 7 (100ns).
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public int Scale
+ {
+ get => serializer.Scale;
+ set => serializer.Scale = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of digits for the fractional part of the seconds.
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public SqlNullableTimeSerializer(int scale = DefaultScale)
+ {
+ serializer = new SqlTimeSerializer(scale);
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 5.
+ ///
+ public override TimeSpan? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (TimeSpan?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 5.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(TimeSpan? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableTinyintSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableTinyintSerializer.cs
new file mode 100644
index 0000000000..bbcab710d7
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableTinyintSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableTinyIntSerializer : Serializer
+ {
+ private static readonly SqlTinyIntSerializer serializer = new SqlTinyIntSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_TinyInt_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override byte? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (byte?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(byte? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableUniqueidentifierSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableUniqueidentifierSerializer.cs
new file mode 100644
index 0000000000..12b5440d38
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNullableUniqueidentifierSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+ internal class SqlNullableUniqueIdentifierSerializer : Serializer
+ {
+ private static readonly SqlUniqueIdentifierSerializer serializer = new SqlUniqueIdentifierSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_UniqueIdentifier_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 16.
+ ///
+ public override Guid? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (Guid?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(Guid? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNumericSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNumericSerializer.cs
new file mode 100644
index 0000000000..7f114d7a95
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNumericSerializer.cs
@@ -0,0 +1,100 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlNumericSerializer : Serializer
+ {
+ private const int DefaultPrecision = 18;
+ private const int DefaultScale = 0;
+ private readonly SqlDecimalSerializer serializer;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Numeric";
+
+ ///
+ /// Gets or sets the maximum number of digits used to represent the value. The default precision is 18.
+ ///
+ ///
+ /// The represents the maximum total number of decimal digits to be stored.
+ /// This number includes both the left and the right sides of the decimal point.
+ /// The precision must be a value from 1 through the maximum precision of 38.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [1 - 38] for this setting.
+ ///
+ public int Precision
+ {
+ get => serializer.Precision;
+ set => serializer.Precision = value;
+ }
+
+ ///
+ /// Gets or sets the number of decimal places to which Value is resolved.
+ ///
+ ///
+ /// The number of decimal digits that are stored to the right of the decimal point. This number is subtracted from the
+ /// to determine the maximum number of digits to the left of the decimal point. must be a value from 0 through .
+ /// The default scale is 0 and so 0 ≤ ≤ .
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public int Scale
+ {
+ get => serializer.Scale;
+ set => serializer.Scale = value;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum number of digits used to represent the value. The default precision is 18.
+ /// The number of decimal places to which Value is resolved. The default scale is 0.
+ ///
+ /// Thrown when is set to a value that is out of the valid range [1 - 38] or when
+ /// is set to a value that is out of the valid range [0 - ] for this setting.
+ ///
+ public SqlNumericSerializer(int precision = DefaultPrecision, int scale = DefaultScale)
+ {
+ serializer = new SqlDecimalSerializer(precision, scale);
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 17.
+ ///
+ public override decimal Deserialize(byte[] bytes) => serializer.Deserialize(bytes);
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 17.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal value) => serializer.Serialize(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNvarcharSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNvarcharSerializer.cs
new file mode 100644
index 0000000000..aeab485741
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlNvarcharSerializer.cs
@@ -0,0 +1,109 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.Linq.Enumerable;
+using static System.Text.Encoding;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlNVarCharSerializer : Serializer
+ {
+ private const int Max = -1;
+ private const int MinSize = 1;
+ private const int MaxSize = 4000;
+ private const int DefaultSize = 30;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_NVarChar_Nullable";
+
+ private int size;
+
+ ///
+ /// Gets or sets the maximum length of the data.
+ ///
+ ///
+ /// If not explicitly set, the size is defaulted to 30.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [-1, 1 - 4000] for this setting.
+ ///
+ public int Size
+ {
+ get => size;
+ set
+ {
+ if (value != Max && (value < MinSize || value > MaxSize))
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ size = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum length of the data
+ ///
+ /// Thrown when set to a value that is out of the valid range [-1, 1 - 4000] for this setting.
+ ///
+ public SqlNVarCharSerializer(int size = DefaultSize)
+ {
+ Size = size;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ public override string Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? null : Unicode.GetString(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// If the value's length is greater than the size, then the value will be truncated on the left to match the size.
+ ///
+ ///
+ /// The serialized data as a byte array.
+ ///
+ public override byte[] Serialize(string value)
+ {
+ if (value.IsNull())
+ {
+ return null;
+ }
+
+ if (size != Max)
+ {
+ string trimmedValue = TrimToLength(value);
+ return Unicode.GetBytes(trimmedValue);
+ }
+
+ return Unicode.GetBytes(value);
+ }
+
+ private string TrimToLength(string value) => value.Length > Size ? new string(value.Take(Size).ToArray()) : value;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlRealSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlRealSerializer.cs
new file mode 100644
index 0000000000..996257563b
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlRealSerializer.cs
@@ -0,0 +1,65 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlRealSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Real";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 4.
+ ///
+ public override float Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(float), nameof(bytes));
+
+ return ToSingle(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(float value)
+ {
+ if (float.IsInfinity(value) || float.IsNaN(value))
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ return GetBytes(value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmalldatetimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmalldatetimeSerializer.cs
new file mode 100644
index 0000000000..69e4d9b763
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmalldatetimeSerializer.cs
@@ -0,0 +1,80 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Data.SqlTypes;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlSmallDateTimeSerializer : Serializer
+ {
+ private static readonly DateTime MinValue = DateTime.Parse("1900-01-01 00:00:00");
+ private static readonly DateTime MaxValue = DateTime.Parse("2079-06-06 23:59:59");
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_SmallDateTime";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 4.
+ ///
+ public override DateTime Deserialize(byte[] bytes)
+ {
+ const int SizeOfDate = 2;
+ const int SizeOfTime = 2;
+ const int SizeOfDateTime = SizeOfDate + SizeOfTime;
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfDateTime, nameof(bytes));
+
+ int dayTicks = ToUInt16(bytes.Take(SizeOfDate).ToArray(), 0);
+ int timeTicks = ToUInt16(bytes.Skip(SizeOfDate).Take(SizeOfTime).ToArray(), 0) * SqlDateTime.SQLTicksPerMinute;
+ SqlDateTime sqlDateTime = new SqlDateTime(dayTicks, timeTicks);
+ return sqlDateTime.Value;
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(DateTime value)
+ {
+ if (value < MinValue || value > MaxValue)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ SqlDateTime sqlDateTime = new SqlDateTime(value.AddSeconds(30));
+ byte[] dayTicks = GetBytes((short)sqlDateTime.DayTicks);
+ byte[] timeTicks = GetBytes((short)(sqlDateTime.TimeTicks / SqlDateTime.SQLTicksPerMinute));
+ return dayTicks.Concat(timeTicks).ToArray();
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmallintSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmallintSerializer.cs
new file mode 100644
index 0000000000..ffc7f92920
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmallintSerializer.cs
@@ -0,0 +1,52 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlSmallIntSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_SmallInt";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override short Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(long), nameof(bytes));
+
+ return ToInt16(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(short value) => GetBytes((long)value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmallmoneySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmallmoneySerializer.cs
new file mode 100644
index 0000000000..a368ee1c2d
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlSmallmoneySerializer.cs
@@ -0,0 +1,65 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlSmallMoneySerializer : Serializer
+ {
+ private const decimal MinValue = -214748.3648M;
+ private const decimal MaxValue = 214748.3647M;
+ private static readonly SqlMoneySerializer sqlMoneySerializer = new SqlMoneySerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_SmallMoney";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override decimal Deserialize(byte[] bytes)
+ {
+ return sqlMoneySerializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(decimal value)
+ {
+ if (value < MinValue || value > MaxValue)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ return sqlMoneySerializer.Serialize(value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlTimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlTimeSerializer.cs
new file mode 100644
index 0000000000..a18c433db1
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlTimeSerializer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.BitConverter;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlTimeSerializer : Serializer
+ {
+ private const int MaxScale = 7;
+ private const int MinScale = 0;
+ private const int DefaultScale = 7;
+ private const int MaxTimeLength = 5;
+ private static readonly TimeSpan MinValue = TimeSpan.Parse("00:00:00.0000000");
+ private static readonly TimeSpan MaxValue = TimeSpan.Parse("23:59:59.9999999");
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_Time";
+
+ private int scale;
+
+ ///
+ /// Gets or sets the number of digits for the fractional part of the seconds.
+ ///
+ ///
+ /// This can be an integer from 0 to 7. The default fractional scale is 7 (100ns).
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public int Scale
+ {
+ get => scale;
+ set
+ {
+ if (value < MinScale || value > MaxScale)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+ scale = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The number of digits for the fractional part of the seconds.
+ ///
+ /// Thrown when set to a value that is out of the valid range [0 - 7] for this setting.
+ ///
+ public SqlTimeSerializer(int scale = DefaultScale)
+ {
+ Scale = scale;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 5.
+ ///
+ public override TimeSpan Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(MaxTimeLength, nameof(bytes));
+
+ byte[] padding = { 0, 0, 0 };
+ byte[] paddedBytes = bytes.Concat(padding).ToArray();
+ long timeTicks = ToInt64(paddedBytes, 0);
+
+ return new TimeSpan(timeTicks);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 5.
+ ///
+ ///
+ /// is out of range.
+ ///
+ public override byte[] Serialize(TimeSpan value)
+ {
+ if (value < MinValue || value > MaxValue)
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ long time = value.Ticks / precisionScale[scale] * precisionScale[scale];
+
+ return GetBytes(time).Take(MaxTimeLength).ToArray();
+ }
+
+ internal static readonly long[] precisionScale = {
+ 10000000,
+ 1000000,
+ 100000,
+ 10000,
+ 1000,
+ 100,
+ 10,
+ 1,
+ };
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlTinyintSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlTinyintSerializer.cs
new file mode 100644
index 0000000000..bbaee6df82
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlTinyintSerializer.cs
@@ -0,0 +1,52 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlTinyIntSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_TinyInt";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override byte Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(sizeof(long), nameof(bytes));
+
+ return bytes[0];
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(byte value) => GetBytes((long)value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlUniqueidentifierSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlUniqueidentifierSerializer.cs
new file mode 100644
index 0000000000..cb04efba0d
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlUniqueidentifierSerializer.cs
@@ -0,0 +1,53 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlUniqueIdentifierSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_UniqueIdentifier";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 16.
+ ///
+ public override Guid Deserialize(byte[] bytes)
+ {
+ const int SizeOfGuid = 16;
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateSize(SizeOfGuid, nameof(bytes));
+
+ return new Guid(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(Guid value) => value.ToByteArray();
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlVarbinarySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlVarbinarySerializer.cs
new file mode 100644
index 0000000000..6aa0d11fe0
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlVarbinarySerializer.cs
@@ -0,0 +1,102 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.Linq.Enumerable;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing [] type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlVarBinarySerializer : Serializer
+ {
+ private const int Max = -1;
+ private const int DefaultSize = 30;
+ private const int MinSize = 1;
+ private const int MaxSize = 8000;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_VarBinary";
+
+ private int size;
+
+ ///
+ /// Gets or sets the maximum length of the data.
+ ///
+ ///
+ /// If not explicitly set, the size is defaulted to 30.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [-1, 1 - 8000] for this setting.
+ ///
+ public int Size
+ {
+ get => size;
+ set
+ {
+ if (value != Max && (value < MinSize || value > MaxSize))
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ size = value;
+ }
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum length of the data
+ ///
+ /// Thrown when set to a value that is out of the valid range [-1, 1 - 8000] for this setting.
+ ///
+ public SqlVarBinarySerializer(int size = DefaultSize)
+ {
+ Size = size;
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ public override byte[] Deserialize(byte[] bytes) => bytes;
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// If the value's length is greater than the size, then the value will be truncated on the left to match the size.
+ ///
+ /// The serialized data as a byte array.
+ public override byte[] Serialize(byte[] value)
+ {
+ if (value.IsNull())
+ {
+ return null;
+ }
+
+ if (size != Max)
+ {
+ return TrimToLength(value);
+ }
+
+ return value;
+ }
+
+ private byte[] TrimToLength(byte[] value) => value.Length > Size ? value.Take(Size).ToArray() : value;
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlVarcharSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlVarcharSerializer.cs
new file mode 100644
index 0000000000..7411cece14
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/SqlSerializers/SqlVarcharSerializer.cs
@@ -0,0 +1,126 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+using System.Text;
+
+using static System.Text.Encoding;
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects
+ /// that is compatible with the Always Encrypted feature in SQL Server and Azure SQL Database.
+ ///
+
+ internal sealed class SqlVarCharSerializer : SqlCodePageEncodingSerializer
+ {
+ private const int Max = -1;
+ private const int DefaultSize = 30;
+ private const int MinSize = 1;
+ private const int MaxSize = 8000;
+
+ ///
+ /// The default character encoding Windows-1252. It is also referred to as "ANSI".
+ ///
+ private const int DefaultEncodingCodePoint = 1252;
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SQL_VarChar_Nullable";
+
+ private int size;
+
+ ///
+ /// Gets or sets the maximum length of the data.
+ ///
+ ///
+ /// If not explicitly set, the size is defaulted to 30.
+ ///
+ ///
+ /// Thrown when set to a value that is out of the valid range [-1, 1 - 8000] for this setting.
+ ///
+ public int Size
+ {
+ get => size;
+ set
+ {
+ if (value != Max && (value < MinSize || value > MaxSize))
+ {
+ throw new MicrosoftDataEncryptionException(ValueOutOfRange.Format(value));
+ }
+
+ size = value;
+ }
+ }
+
+ private Encoding characterEncoding;
+
+ ///
+ /// Gets or sets the character encoding.
+ ///
+ ///
+ /// If not explicitly set, the encoding is defaulted to Windows-1252, which is also referred to as "ANSI".
+ ///
+ public int CodePageCharacterEncoding {
+ get => characterEncoding.CodePage;
+ set => characterEncoding = GetEncoding(value);
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The maximum length of the data
+ /// The code page character encoding.
+ ///
+ /// Thrown when set to a value that is out of the valid range [-1, 1 - 8000] for this setting.
+ ///
+ public SqlVarCharSerializer(int size = DefaultSize, int codePageCharacterEncoding = DefaultEncodingCodePoint)
+ {
+ Size = size;
+ characterEncoding = GetEncoding(codePageCharacterEncoding);
+ }
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ public override string Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? null : characterEncoding.GetString(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// If the value's length is greater than the size, then the value will be truncated on the left to match the size.
+ ///
+ /// The serialized data as a byte array.
+ public override byte[] Serialize(string value)
+ {
+ if (value.IsNull())
+ {
+ return null;
+ }
+
+ if (Size != Max && value.Length > Size)
+ {
+ value = TrimToLength(value);
+ }
+
+ return characterEncoding.GetBytes(value);
+ }
+
+ private string TrimToLength(string value) => new string(value.Take(Size).ToArray());
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializerFactory.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializerFactory.cs
new file mode 100644
index 0000000000..905749e269
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializerFactory.cs
@@ -0,0 +1,133 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Collections.Generic;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Provides methods for getting serializer implementations, such as by type and ID.
+ ///
+ internal class StandardSerializerFactory : SerializerFactory
+ {
+ private readonly Dictionary serializerByType = new Dictionary();
+
+ private readonly Dictionary serializerByIdentifier = new Dictionary();
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public StandardSerializerFactory()
+ {
+ RegisterDefaultStandardSerializers();
+ }
+
+ ///
+ /// Returns a default instance of the class.
+ ///
+ public static StandardSerializerFactory Default { get; } = new StandardSerializerFactory();
+
+ ///
+ /// Gets a registered serializer by its Identifier Property.
+ ///
+ /// The identifier uniquely identifies a particular Serializer implementation.
+ /// The ISerializer implementation
+ public override ISerializer GetSerializer(string identifier)
+ {
+ identifier.ValidateNotNull(nameof(identifier));
+
+ if (serializerByIdentifier.ContainsKey(identifier))
+ {
+ return serializerByIdentifier[identifier];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Gets a default registered serializer for the type.
+ ///
+ /// The data type to be serialized.
+ /// A default registered serializer for the type.
+ public override Serializer GetDefaultSerializer()
+ {
+ if (serializerByType.ContainsKey(typeof(T)))
+ {
+ return (Serializer)serializerByType[typeof(T)];
+ }
+
+ throw new MicrosoftDataEncryptionException(DefaultSerializerNotFound.Format(typeof(T).Name, nameof(RegisterSerializer)));
+ }
+
+ ///
+ /// Registers a custom serializer.
+ ///
+ /// The data type on which the Serializer operates.
+ /// The Serializer to register.
+ /// Determines whether to override an existing default serializer for the same type.
+ public override void RegisterSerializer(Type type, ISerializer serializer, bool overrideDefault = false)
+ {
+ type.ValidateNotNull(nameof(type));
+ serializer.ValidateNotNull(nameof(serializer));
+
+ serializerByIdentifier[serializer.Identifier] = serializer;
+
+ if (overrideDefault || !HasDefaultSerializer(type))
+ {
+ serializerByType[type] = serializer;
+ }
+ }
+
+ private bool HasDefaultSerializer(Type type)
+ {
+ return serializerByType.ContainsKey(type);
+ }
+
+ private void RegisterDefaultStandardSerializers()
+ {
+ RegisterSerializer(typeof(bool), new BooleanSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(bool?), new NullableBooleanSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(byte), new ByteSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(byte?), new NullableByteSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(byte[]), new ByteArraySerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(char), new CharSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(char?), new NullableCharSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTime), new DateTimeSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTime?), new NullableDateTimeSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTimeOffset), new DateTimeOffsetSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(DateTimeOffset?), new NullableDateTimeOffsetSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(decimal), new DecimalSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(decimal?), new NullableDecimalSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(double), new DoubleSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(double?), new NullableDoubleSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(float), new SingleSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(float?), new NullableSingleSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(Guid), new GuidSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(Guid?), new NullableGuidSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(int), new Int32Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(int?), new NullableInt32Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(long), new Int64Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(long?), new NullableInt64Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(sbyte), new SByteSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(sbyte?), new NullableSByteSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(short), new Int16Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(short?), new NullableInt16Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(string), new StringSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(TimeSpan), new TimeSpanSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(TimeSpan?), new NullableTimeSpanSerializer(), overrideDefault: true);
+ RegisterSerializer(typeof(uint), new UInt32Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(uint?), new NullableUInt32Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(ulong), new UInt64Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(ulong?), new NullableUInt64Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(ushort), new UInt16Serializer(), overrideDefault: true);
+ RegisterSerializer(typeof(ushort?), new NullableUInt16Serializer(), overrideDefault: true);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/BooleanSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/BooleanSerializer.cs
new file mode 100644
index 0000000000..1db371cfaf
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/BooleanSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class BooleanSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Boolean";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 1.
+ ///
+ public override bool Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(bool), nameof(bytes));
+
+ return ToBoolean(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 1.
+ ///
+ public override byte[] Serialize(bool value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/ByteArraySerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/ByteArraySerializer.cs
new file mode 100644
index 0000000000..4cc7a4a480
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/ByteArraySerializer.cs
@@ -0,0 +1,40 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing [] type data objects.
+ ///
+ internal class ByteArraySerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "ByteArray";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ public override byte[] Deserialize(byte[] bytes)
+ {
+ return bytes;
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ /// The serialized data as a byte array.
+ public override byte[] Serialize(byte[] value)
+ {
+ return value;
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/ByteSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/ByteSerializer.cs
new file mode 100644
index 0000000000..234ea1d228
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/ByteSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class ByteSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Byte";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 1.
+ ///
+ public override byte Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(byte), nameof(bytes));
+
+ return bytes[0];
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 1.
+ ///
+ public override byte[] Serialize(byte value) => new byte[] { value };
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/CharSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/CharSerializer.cs
new file mode 100644
index 0000000000..bedef9a309
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/CharSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class CharSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Character";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 2.
+ ///
+ public override char Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(char), nameof(bytes));
+
+ return ToChar(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 2.
+ ///
+ public override byte[] Serialize(char value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DateTimeOffsetSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DateTimeOffsetSerializer.cs
new file mode 100644
index 0000000000..d762c62b56
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DateTimeOffsetSerializer.cs
@@ -0,0 +1,70 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class DateTimeOffsetSerializer : Serializer
+ {
+ private static readonly DateTimeSerializer DateTimeSerializer = new DateTimeSerializer();
+ private static readonly TimeSpanSerializer TimeSpanSerializer = new TimeSpanSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "DateTimeOffset";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 16.
+ ///
+ public override DateTimeOffset Deserialize(byte[] bytes)
+ {
+ const int DateTimeIndex = 0;
+ const int TimeSpanIndex = sizeof(long);
+ const int MinimumSize = sizeof(long) + sizeof(long);
+
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(MinimumSize, nameof(bytes));
+
+ byte[] dateTimePart = bytes.Skip(DateTimeIndex).Take(sizeof(long)).ToArray();
+ byte[] timeSpanPart = bytes.Skip(TimeSpanIndex).Take(sizeof(long)).ToArray();
+
+ DateTime dateTime = DateTimeSerializer.Deserialize(dateTimePart);
+ TimeSpan timeSpan = TimeSpanSerializer.Deserialize(timeSpanPart);
+
+ return new DateTimeOffset(dateTime, timeSpan);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(DateTimeOffset value)
+ {
+ IEnumerable dateTimePart = DateTimeSerializer.Serialize(value.DateTime);
+ IEnumerable timeSpanPart = TimeSpanSerializer.Serialize(value.Offset);
+
+ return dateTimePart.Concat(timeSpanPart).ToArray();
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DateTimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DateTimeSerializer.cs
new file mode 100644
index 0000000000..3265d6afff
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DateTimeSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class DateTimeSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "DateTime";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override DateTime Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(long), nameof(bytes));
+
+ return DateTime.FromBinary(ToInt64(bytes, 0));
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(DateTime value) => GetBytes(value.ToBinary());
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DecimalSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DecimalSerializer.cs
new file mode 100644
index 0000000000..ba0de733ae
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DecimalSerializer.cs
@@ -0,0 +1,56 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using System.Linq;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class DecimalSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Decimal";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 16.
+ ///
+ public override decimal Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(decimal), nameof(bytes));
+
+ int[] bits = Enumerable.Range(0, 4)
+ .Select(i => ToInt32(bytes, i * sizeof(int)))
+ .ToArray();
+
+ return new decimal(bits);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(decimal value) => decimal.GetBits(value).SelectMany(GetBytes).ToArray();
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DoubleSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DoubleSerializer.cs
new file mode 100644
index 0000000000..e740237695
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/DoubleSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class DoubleSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Float64";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override double Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(double), nameof(bytes));
+
+ return ToDouble(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(double value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/GuidSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/GuidSerializer.cs
new file mode 100644
index 0000000000..322ef81924
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/GuidSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class GuidSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UniqueIdentifier";
+
+ private const int SizeOfGuid = 16;
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 16.
+ ///
+ public override Guid Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(SizeOfGuid, nameof(bytes));
+
+ return new Guid(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(Guid value) => value.ToByteArray();
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int16Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int16Serializer.cs
new file mode 100644
index 0000000000..2c85165217
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int16Serializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class Int16Serializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Int16";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 2.
+ ///
+ public override short Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(short), nameof(bytes));
+
+ return ToInt16(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 2.
+ ///
+ public override byte[] Serialize(short value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int32Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int32Serializer.cs
new file mode 100644
index 0000000000..2fd33721df
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int32Serializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class Int32Serializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Int32";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 4.
+ ///
+ public override int Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(int), nameof(bytes));
+
+ return ToInt32(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ public override byte[] Serialize(int value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int64Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int64Serializer.cs
new file mode 100644
index 0000000000..956a02148b
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/Int64Serializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class Int64Serializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Int64";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override long Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(long), nameof(bytes));
+
+ return ToInt64(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(long value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableBooleanSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableBooleanSerializer.cs
new file mode 100644
index 0000000000..1c7e154fd5
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableBooleanSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableBooleanSerializer : Serializer
+ {
+ private static readonly BooleanSerializer serializer = new BooleanSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Boolean_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 1.
+ ///
+ public override bool? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (bool?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 1.
+ ///
+ public override byte[] Serialize(bool? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableByteSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableByteSerializer.cs
new file mode 100644
index 0000000000..042e8bd9f2
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableByteSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableByteSerializer : Serializer
+ {
+ private static readonly ByteSerializer serializer = new ByteSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Byte_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 1.
+ ///
+ public override byte? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (byte?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 1.
+ ///
+ public override byte[] Serialize(byte? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableCharSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableCharSerializer.cs
new file mode 100644
index 0000000000..8c3452b1a9
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableCharSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableCharSerializer : Serializer
+ {
+ private static readonly CharSerializer serializer = new CharSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Character_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 2.
+ ///
+ public override char? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (char?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 2.
+ ///
+ public override byte[] Serialize(char? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDateTImeOffsetSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDateTImeOffsetSerializer.cs
new file mode 100644
index 0000000000..b7cc39016f
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDateTImeOffsetSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableDateTimeOffsetSerializer : Serializer
+ {
+ private static readonly DateTimeOffsetSerializer serializer = new DateTimeOffsetSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "DateTimeOffset_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 16.
+ ///
+ public override DateTimeOffset? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTimeOffset?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(DateTimeOffset? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDateTimeSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDateTimeSerializer.cs
new file mode 100644
index 0000000000..7c25bddc99
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDateTimeSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableDateTimeSerializer : Serializer
+ {
+ private static readonly DateTimeSerializer serializer = new DateTimeSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "DateTime_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override DateTime? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (DateTime?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(DateTime? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDecimalSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDecimalSerializer.cs
new file mode 100644
index 0000000000..d664613261
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDecimalSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableDecimalSerializer : Serializer
+ {
+ private static readonly DecimalSerializer serializer = new DecimalSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Decimal_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 16.
+ ///
+ public override decimal? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (decimal?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(decimal? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDoubleSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDoubleSerializer.cs
new file mode 100644
index 0000000000..d0a435ace3
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableDoubleSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableDoubleSerializer : Serializer
+ {
+ private static readonly DoubleSerializer serializer = new DoubleSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Float64_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override double? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (double?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(double? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableGuidSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableGuidSerializer.cs
new file mode 100644
index 0000000000..bb6448cc60
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableGuidSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableGuidSerializer : Serializer
+ {
+ private static readonly GuidSerializer serializer = new GuidSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UniqueIdentifier_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 16.
+ ///
+ public override Guid? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (Guid?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 16.
+ ///
+ public override byte[] Serialize(Guid? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt16Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt16Serializer.cs
new file mode 100644
index 0000000000..a52c67a906
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt16Serializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableInt16Serializer : Serializer
+ {
+ private static readonly Int16Serializer serializer = new Int16Serializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Int16_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 2.
+ ///
+ public override short? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (short?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 2.
+ ///
+ public override byte[] Serialize(short? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt32Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt32Serializer.cs
new file mode 100644
index 0000000000..fd873caac2
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt32Serializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableInt32Serializer : Serializer
+ {
+ private static readonly Int32Serializer serializer = new Int32Serializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Int32_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 4.
+ ///
+ public override int? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (int?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ public override byte[] Serialize(int? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt64Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt64Serializer.cs
new file mode 100644
index 0000000000..f5c1389c66
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableInt64Serializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableInt64Serializer : Serializer
+ {
+ private static readonly Int64Serializer serializer = new Int64Serializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Int64_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override long? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (long?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(long? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableSByteSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableSByteSerializer.cs
new file mode 100644
index 0000000000..058f585b50
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableSByteSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class NullableSByteSerializer : Serializer
+ {
+ private static readonly SByteSerializer serializer = new SByteSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SByte_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 1.
+ ///
+ public override sbyte? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (sbyte?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 1.
+ ///
+ public override byte[] Serialize(sbyte? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableSingleSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableSingleSerializer.cs
new file mode 100644
index 0000000000..4c50e20365
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableSingleSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableSingleSerializer : Serializer
+ {
+ private static readonly SingleSerializer serializer = new SingleSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Single_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 4.
+ ///
+ public override float? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (float?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ public override byte[] Serialize(float? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableTimeSpanSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableTimeSpanSerializer.cs
new file mode 100644
index 0000000000..9103b5ce6a
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableTimeSpanSerializer.cs
@@ -0,0 +1,49 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ internal class NullableTimeSpanSerializer : Serializer
+ {
+ private static readonly TimeSpanSerializer serializer = new TimeSpanSerializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Time_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override TimeSpan? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (TimeSpan?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(TimeSpan? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt16Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt16Serializer.cs
new file mode 100644
index 0000000000..28b74244b4
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt16Serializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class NullableUInt16Serializer : Serializer
+ {
+ private static readonly UInt16Serializer serializer = new UInt16Serializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UInt16_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 2.
+ ///
+ public override ushort? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (ushort?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 2.
+ ///
+ public override byte[] Serialize(ushort? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt32Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt32Serializer.cs
new file mode 100644
index 0000000000..074db63944
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt32Serializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class NullableUInt32Serializer : Serializer
+ {
+ private static readonly UInt32Serializer serializer = new UInt32Serializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UInt32_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 4.
+ ///
+ public override uint? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (uint?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ public override byte[] Serialize(uint? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt64Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt64Serializer.cs
new file mode 100644
index 0000000000..ebd5fe709c
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/NullableUInt64Serializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing ? type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class NullableUInt64Serializer : Serializer
+ {
+ private static readonly UInt64Serializer serializer = new UInt64Serializer();
+
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UInt64_Nullable";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// The length of is less than 8.
+ ///
+ public override ulong? Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? (ulong?)null : serializer.Deserialize(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(ulong? value)
+ {
+ return value.IsNull() ? null : serializer.Serialize(value.Value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/SByteSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/SByteSerializer.cs
new file mode 100644
index 0000000000..14fe6dbf7a
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/SByteSerializer.cs
@@ -0,0 +1,50 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class SByteSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "SByte";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 1.
+ ///
+ public override sbyte Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(sbyte), nameof(bytes));
+
+ return (sbyte)bytes[0];
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 1.
+ ///
+ public override byte[] Serialize(sbyte value) => new byte[] { (byte)value };
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/SingleSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/SingleSerializer.cs
new file mode 100644
index 0000000000..b31d67d122
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/SingleSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class SingleSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Single";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 4.
+ ///
+ public override float Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(float), nameof(bytes));
+
+ return ToSingle(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ public override byte[] Serialize(float value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/StringSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/StringSerializer.cs
new file mode 100644
index 0000000000..7011f33c74
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/StringSerializer.cs
@@ -0,0 +1,42 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+using static System.Text.Encoding;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class StringSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "String";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ public override string Deserialize(byte[] bytes)
+ {
+ return bytes.IsNull() ? null : Unicode.GetString(bytes);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ public override byte[] Serialize(string value)
+ {
+ return value.IsNull() ? null : Unicode.GetBytes(value);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/TimeSpanSerializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/TimeSpanSerializer.cs
new file mode 100644
index 0000000000..265f25dce5
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/TimeSpanSerializer.cs
@@ -0,0 +1,51 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ internal class TimeSpanSerializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "Time";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override TimeSpan Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(long), nameof(bytes));
+
+ return new TimeSpan(ToInt64(bytes, 0));
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(TimeSpan value) => GetBytes(value.Ticks);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt16Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt16Serializer.cs
new file mode 100644
index 0000000000..d211a5b00b
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt16Serializer.cs
@@ -0,0 +1,52 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class UInt16Serializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UInt16";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 2.
+ ///
+ public override ushort Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(ushort), nameof(bytes));
+
+ return ToUInt16(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 2.
+ ///
+ public override byte[] Serialize(ushort value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt32Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt32Serializer.cs
new file mode 100644
index 0000000000..850b1a8941
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt32Serializer.cs
@@ -0,0 +1,52 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class UInt32Serializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UInt32";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 4.
+ ///
+ public override uint Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(uint), nameof(bytes));
+
+ return ToUInt32(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 4.
+ ///
+ public override byte[] Serialize(uint value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt64Serializer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt64Serializer.cs
new file mode 100644
index 0000000000..0e236be4f4
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Cryptography/Serializers/StandardSerializers/UInt64Serializer.cs
@@ -0,0 +1,52 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System;
+
+using static System.BitConverter;
+
+namespace Microsoft.Data.Encryption.Cryptography.Serializers
+{
+ ///
+ /// Contains the methods for serializing and deserializing type data objects.
+ ///
+ [CLSCompliant(false)]
+ internal class UInt64Serializer : Serializer
+ {
+ ///
+ /// The uniquely identifies a particular Serializer implementation.
+ ///
+ public override string Identifier => "UInt64";
+
+ ///
+ /// Deserializes the provided
+ ///
+ /// The data to be deserialized
+ /// The serialized data
+ ///
+ /// is null.
+ /// -or-
+ /// The length of is less than 8.
+ ///
+ public override ulong Deserialize(byte[] bytes)
+ {
+ bytes.ValidateNotNull(nameof(bytes));
+ bytes.ValidateGreaterThanSize(sizeof(ulong), nameof(bytes));
+
+ return ToUInt64(bytes, 0);
+ }
+
+ ///
+ /// Serializes the provided
+ ///
+ /// The value to be serialized
+ ///
+ /// An array of bytes with length 8.
+ ///
+ public override byte[] Serialize(ulong value) => GetBytes(value);
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Extensions/ArgumentValidationExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Extensions/ArgumentValidationExtensions.cs
new file mode 100644
index 0000000000..2e7e5c843a
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Extensions/ArgumentValidationExtensions.cs
@@ -0,0 +1,110 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using Microsoft.Data.Encryption.Cryptography;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+using static Microsoft.Data.Encryption.Resources.Strings;
+
+namespace Microsoft.Data.Encryption
+{
+ internal static class ArgumentValidationExtensions
+ {
+ internal static bool IsNull(this T parameter)
+ {
+ return null == parameter;
+ }
+
+ internal static void ValidateNotNull(this T parameter, string name)
+ {
+ if (parameter.IsNull())
+ {
+ throw new MicrosoftDataEncryptionException(ArgNotNull.FormatInvariant(name));
+ }
+ }
+
+ internal static void ValidateNotNullOrWhitespace(this string parameter, string name)
+ {
+ if (string.IsNullOrWhiteSpace(parameter))
+ {
+ throw new MicrosoftDataEncryptionException(ArgNotNullOrWhiteSpace.FormatInvariant(name));
+ }
+ }
+
+ internal static void ValidateNotNullForEach(this IEnumerable parameters, string name)
+ {
+ if (parameters.Any(t => t.IsNull()))
+ {
+ throw new MicrosoftDataEncryptionException(ArgNotNullForEach.FormatInvariant(name));
+ }
+ }
+
+ internal static void ValidateNotNullOrWhitespaceForEach(this IEnumerable parameters, string name)
+ {
+ if (parameters.Any(s => string.IsNullOrWhiteSpace(s)))
+ {
+ throw new MicrosoftDataEncryptionException(ArgNotNullOrWhitespaceForEach.FormatInvariant(name));
+ }
+ }
+
+ internal static void ValidateNotEmpty(this IEnumerable parameter, string name)
+ {
+ if (!parameter.Any())
+ {
+ throw new MicrosoftDataEncryptionException(ArgNotEmpty.FormatInvariant(name));
+ }
+ }
+
+ internal static void ValidateNotNullOrEmpty(this IEnumerable parameters, string name)
+ {
+ parameters.ValidateNotNull(name);
+ parameters.ValidateNotEmpty(name);
+ }
+
+ internal static void ValidateGreaterThanSize(this IEnumerable parameter, int size, string name)
+ {
+ if (parameter.Count() < size)
+ {
+ throw new MicrosoftDataEncryptionException(ArgGreaterThanSize.FormatInvariant(name, size));
+ }
+ }
+
+ internal static void ValidateSize(this IEnumerable parameter, int size, string name)
+ {
+ if (parameter.Count() != size)
+ {
+ throw new MicrosoftDataEncryptionException(ArgSize.FormatInvariant(name, size));
+ }
+ }
+
+ internal static void ValidateType(this object parameter, Type type, string name)
+ {
+ if (!(parameter.GetType().Equals(type)))
+ {
+ throw new MicrosoftDataEncryptionException(ArgType.FormatInvariant(name, type));
+ }
+ }
+
+ internal static void ValidatePositive(this int parameter, string name)
+ {
+ if (parameter <= 0)
+ {
+ throw new MicrosoftDataEncryptionException(ArgPositive.FormatInvariant(name));
+ }
+ }
+
+ internal static void ValidateNotPlaintext(this EncryptionSettings encryptionSettings, string name)
+ {
+ if (encryptionSettings.EncryptionType == EncryptionType.Plaintext)
+ {
+ throw new MicrosoftDataEncryptionException(EncryptionSettingsCannotBePlaintext.FormatInvariant(name, nameof(EncryptionType)));
+ }
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Extensions/StringFormattingExtensions.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Extensions/StringFormattingExtensions.cs
new file mode 100644
index 0000000000..8c75871bde
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Extensions/StringFormattingExtensions.cs
@@ -0,0 +1,24 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+using System.Globalization;
+
+namespace Microsoft.Data.Encryption
+{
+ internal static class StringFormattingExtensions
+ {
+ internal static string Format(this string format, params object[] args)
+ {
+ return string.Format(format, args);
+ }
+
+ internal static string FormatInvariant(this string format, params object[] args)
+ {
+ return string.Format(CultureInfo.InvariantCulture, format, args);
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/FixMdePublicInterfaces.ps1 b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/FixMdePublicInterfaces.ps1
new file mode 100644
index 0000000000..2038ead60b
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/FixMdePublicInterfaces.ps1
@@ -0,0 +1,39 @@
+$copyrightHeaderLine1 = "//------------------------------------------------------------"
+$copyrightHeaderLine2 = "// Copyright (c) Microsoft Corporation. All rights reserved."
+$copyrightHeaderLine3 = "//------------------------------------------------------------"
+$copyrightHeaderLine4 = ""
+$headerLine1 = "// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis."
+$headerLine2 = "// "
+$headerLine3 = ""
+
+Get-ChildItem -Filter *.cs -File -Recurse | Foreach-Object {
+
+$currentFileContent = ($_ | Get-Content)
+
+If (-Not ($currentFileContent | Select-String -Pattern 'Microsoft Corporation. All rights reserved.'))
+{
+ Write-Output ""
+ Write-Output "Appending header in file " $_.FullName
+ Set-Content $_.FullName -value $copyrightHeaderLine1, $copyrightHeaderLine2, $copyrightHeaderLine3, $copyrightHeaderLine4, $headerLine1, $headerLine2, $headerLine3, $currentFileContent
+ $currentFileContent = ($_ | Get-Content)
+}
+
+If ($currentFileContent | Select-String -Pattern 'public\s*(enum|interface|sealed class|abstract class|static class|class)')
+{
+ Write-Output ""
+ Write-Output "- Modifying, marking public classes as internal in file " $_.FullName
+
+ $listToModify = ($currentFileContent | Select-String -Pattern 'public\s*(enum|interface|sealed class|abstract class|static class|class)') -split '\n'
+
+ $listOfChanges = $listToModify -creplace 'public','internal' -split '\n'
+
+ for ($counter=0; $counter -lt $listToModify.Length; $counter++)
+ {
+ Write-Output ""
+ Write-Output "Class modified from " $listToModify[$counter] " to " $listOfChanges[$counter]
+ $currentFileContent = $currentFileContent -creplace [Regex]::Escape($listToModify[$counter]) , $listOfChanges[$counter]
+ }
+
+ [IO.File]::WriteAllText($_.FullName, ($currentFileContent -join "`r`n"))
+}
+}
\ No newline at end of file
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Resources/Strings.Designer.cs b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Resources/Strings.Designer.cs
new file mode 100644
index 0000000000..0805a3450e
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Resources/Strings.Designer.cs
@@ -0,0 +1,493 @@
+//------------------------------------------------------------
+// Copyright (c) Microsoft Corporation. All rights reserved.
+//------------------------------------------------------------
+
+// This file isn't generated, but this comment is necessary to exclude it from StyleCop analysis.
+//
+
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.42000
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Microsoft.Data.Encryption.Resources {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Strings {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Strings() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Data.Encryption.Cryptography.Strings", typeof(Strings).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ public static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} must contain at least {1} elements..
+ ///
+ public static string ArgGreaterThanSize {
+ get {
+ return ResourceManager.GetString("ArgGreaterThanSize", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} cannot be empty..
+ ///
+ public static string ArgNotEmpty {
+ get {
+ return ResourceManager.GetString("ArgNotEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} cannot be null..
+ ///
+ public static string ArgNotNull {
+ get {
+ return ResourceManager.GetString("ArgNotNull", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to One of more of the elements in {0} is null..
+ ///
+ public static string ArgNotNullForEach {
+ get {
+ return ResourceManager.GetString("ArgNotNullForEach", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} cannot be null or empty or consist of only whitespace..
+ ///
+ public static string ArgNotNullOrWhiteSpace {
+ get {
+ return ResourceManager.GetString("ArgNotNullOrWhiteSpace", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to One or more of the elements in {0} are null or empty or consist of only whitespace..
+ ///
+ public static string ArgNotNullOrWhitespaceForEach {
+ get {
+ return ResourceManager.GetString("ArgNotNullOrWhitespaceForEach", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} {1} cannot be Plaintext in this context..
+ ///
+ public static string ArgNotPlainText {
+ get {
+ return ResourceManager.GetString("ArgNotPlainText", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} must be a positive integer..
+ ///
+ public static string ArgPositive {
+ get {
+ return ResourceManager.GetString("ArgPositive", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0} must contain {1} elements..
+ ///
+ public static string ArgSize {
+ get {
+ return ResourceManager.GetString("ArgSize", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Expected {0} to be of type {1}.
+ ///
+ public static string ArgType {
+ get {
+ return ResourceManager.GetString("ArgType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The key with identifier {0} was not found..
+ ///
+ public static string AzureKeyVaultKeyNotFound {
+ get {
+ return ResourceManager.GetString("AzureKeyVaultKeyNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Base type was not found.
+ ///
+ public static string BaseTypeNotFound {
+ get {
+ return ResourceManager.GetString("BaseTypeNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to CipherText length does not match the RSA key size..
+ ///
+ public static string CipherTextLengthMismatch {
+ get {
+ return ResourceManager.GetString("CipherTextLengthMismatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to {0}.Count does not equal {1}.Count.
+ ///
+ public static string ColumnCountNotEqual {
+ get {
+ return ResourceManager.GetString("ColumnCountNotEqual", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Empty data encryption key specified..
+ ///
+ public static string DataEncryptionKeyEmpty {
+ get {
+ return ResourceManager.GetString("DataEncryptionKeyEmpty", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Data encryption key cannot be null..
+ ///
+ public static string DataEncryptionKeyNull {
+ get {
+ return ResourceManager.GetString("DataEncryptionKeyNull", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Decryption failed. The last 10 bytes of the encrypted data encryption key are: '{0}'. The first 10 bytes of ciphertext are: '{1}'. {2}.
+ ///
+ public static string DecryptionFailed {
+ get {
+ return ResourceManager.GetString("DecryptionFailed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A default Always Encrypted compatible serializer cannot be found for type {0}. A serializer can be registered for this type with the {1} method..
+ ///
+ public static string DefaultAESerializerNotFound {
+ get {
+ return ResourceManager.GetString("DefaultAESerializerNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to A default serializer cannot be found for type {0}. A serializer can be registered for this type with the {1} method..
+ ///
+ public static string DefaultSerializerNotFound {
+ get {
+ return ResourceManager.GetString("DefaultSerializerNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Internal error. Empty {0} specified..
+ ///
+ public static string EmptyArgumentInternal {
+ get {
+ return ResourceManager.GetString("EmptyArgumentInternal", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Empty data encryption key specified..
+ ///
+ public static string EmptyDataEncryptionKey {
+ get {
+ return ResourceManager.GetString("EmptyDataEncryptionKey", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Encryption failed. The last 10 bytes of the encrypted data encryption key are: '{0}'. {1}.
+ ///
+ public static string EncryptionFailed {
+ get {
+ return ResourceManager.GetString("EncryptionFailed", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The {0} {1} cannot be Plaintext in this context..
+ ///
+ public static string EncryptionSettingsCannotBePlaintext {
+ get {
+ return ResourceManager.GetString("EncryptionSettingsCannotBePlaintext", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Signed hash length does not match the RSA key size..
+ ///
+ public static string HashLengthMismatch {
+ get {
+ return ResourceManager.GetString("HashLengthMismatch", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid Azure Key Vault key path specified: '{0}'. Valid trusted endpoints: {1}..
+ ///
+ public static string InvalidAkvKeyPathTrustedTemplate {
+ get {
+ return ResourceManager.GetString("InvalidAkvKeyPathTrustedTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid Azure Key Vault key path specified: '{0}'..
+ ///
+ public static string InvalidAkvPathTemplate {
+ get {
+ return ResourceManager.GetString("InvalidAkvPathTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid url specified: '{0}'..
+ ///
+ public static string InvalidAkvUrlTemplate {
+ get {
+ return ResourceManager.GetString("InvalidAkvUrlTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified ciphertext's encryption algorithm version '{0}' does not match the expected encryption algorithm version '{1}'..
+ ///
+ public static string InvalidAlgorithmVersion {
+ get {
+ return ResourceManager.GetString("InvalidAlgorithmVersion", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specified encrypted data encryption key contains an invalid encryption algorithm version '{0}'. Expected version is '{1}'..
+ ///
+ public static string InvalidAlgorithmVersionTemplate {
+ get {
+ return ResourceManager.GetString("InvalidAlgorithmVersionTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specified ciphertext has an invalid authentication tag..
+ ///
+ public static string InvalidAuthenticationTag {
+ get {
+ return ResourceManager.GetString("InvalidAuthenticationTag", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified encrypted data encryption key's ciphertext length: {0} does not match the ciphertext length: {1} when using key encryption key (Azure Key Vault key) in '{2}'. The encrypted data encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect..
+ ///
+ public static string InvalidCiphertextLengthTemplate {
+ get {
+ return ResourceManager.GetString("InvalidCiphertextLengthTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Specified ciphertext has an invalid size of {0} bytes, which is below the minimum {1} bytes required for decryption..
+ ///
+ public static string InvalidCipherTextSize {
+ get {
+ return ResourceManager.GetString("InvalidCipherTextSize", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The data encryption key has been successfully decrypted but its length: {0} does not match the length: 32 for algorithm 'AEAD_AES_256_CBC_HMAC_SHA256'. Verify the encrypted value of the data encryption key..
+ ///
+ public static string InvalidDataEncryptionKeySize {
+ get {
+ return ResourceManager.GetString("InvalidDataEncryptionKeySize", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Encryption type '{0}' specified for the column is either invalid or corrupted. Valid encryption types for algorithm 'AEAD_AES_256_CBC_HMAC_SHA256' are: 'Plaintext', 'Deterministic', 'Randomized'..
+ ///
+ public static string InvalidEncryptionType {
+ get {
+ return ResourceManager.GetString("InvalidEncryptionType", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The input is not a valid Hexadecimal string as it contains a non hexadecimal character, is not a multiple of 2 characters, or does not begin with '0x'..
+ ///
+ public static string InvalidHexString {
+ get {
+ return ResourceManager.GetString("InvalidHexString", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid key encryption algorithm specified: '{0}'. Expected value: '{1}'..
+ ///
+ public static string InvalidKeyAlgorithm {
+ get {
+ return ResourceManager.GetString("InvalidKeyAlgorithm", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid signature of the encrypted data encryption key computed..
+ ///
+ public static string InvalidSignature {
+ get {
+ return ResourceManager.GetString("InvalidSignature", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified encrypted data encryption key's signature length: {0} does not match the signature length: {1} when using key encryption key (Azure Key Vault key) in '{2}'. The encrypted data encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect..
+ ///
+ public static string InvalidSignatureLengthTemplate {
+ get {
+ return ResourceManager.GetString("InvalidSignatureLengthTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to The specified encrypted data encryption key signature does not match the signature computed with the key encryption key (Asymmetric key in Azure Key Vault) in '{0}'. The encrypted data encryption key may be corrupt, or the specified path may be incorrect..
+ ///
+ public static string InvalidSignatureTemplate {
+ get {
+ return ResourceManager.GetString("InvalidSignatureTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Invalid trusted endpoint specified: '{0}'; a trusted endpoint must have a value..
+ ///
+ public static string InvalidTrustedEndpointTemplate {
+ get {
+ return ResourceManager.GetString("InvalidTrustedEndpointTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Cannot use a non-RSA key: '{0}'..
+ ///
+ public static string NonRsaKeyTemplate {
+ get {
+ return ResourceManager.GetString("NonRsaKeyTemplate", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Azure Key Vault key path cannot be null..
+ ///
+ public static string NullAkvPath {
+ get {
+ return ResourceManager.GetString("NullAkvPath", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Hash should not be null while decrypting encrypted data encryption key..
+ ///
+ public static string NullHash {
+ get {
+ return ResourceManager.GetString("NullHash", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to This reader's registered encryption key store providers does not contain a provider named {0}..
+ ///
+ public static string ReaderKeyStoreProviderNotFound {
+ get {
+ return ResourceManager.GetString("ReaderKeyStoreProviderNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to No serializer found for {0}.
+ ///
+ public static string SerializerNotFound {
+ get {
+ return ResourceManager.GetString("SerializerNotFound", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Use default serialization..
+ ///
+ public static string UseDefaultSerialization {
+ get {
+ return ResourceManager.GetString("UseDefaultSerialization", resourceCulture);
+ }
+ }
+
+ ///
+ /// Looks up a localized string similar to Parameter value {0} is out of range..
+ ///
+ public static string ValueOutOfRange {
+ get {
+ return ResourceManager.GetString("ValueOutOfRange", resourceCulture);
+ }
+ }
+ }
+}
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Resources/Strings.resx b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Resources/Strings.resx
new file mode 100644
index 0000000000..6bfe8bbc6c
--- /dev/null
+++ b/Microsoft.Azure.Cosmos.Encryption/src/MdeSrc/Resources/Strings.resx
@@ -0,0 +1,261 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ {0} must contain at least {1} elements.
+
+
+ {0} cannot be empty.
+
+
+ {0} cannot be null.
+
+
+ One of more of the elements in {0} is null.
+
+
+ {0} cannot be null or empty or consist of only whitespace.
+
+
+ One or more of the elements in {0} are null or empty or consist of only whitespace.
+
+
+ The {0} {1} cannot be Plaintext in this context.
+
+
+ {0} must be a positive integer.
+
+
+ {0} must contain {1} elements.
+
+
+ Expected {0} to be of type {1}
+
+
+ The key with identifier {0} was not found.
+
+
+ Base type was not found
+
+
+ CipherText length does not match the RSA key size.
+
+
+ {0}.Count does not equal {1}.Count
+
+
+ Empty data encryption key specified.
+
+
+ Data encryption key cannot be null.
+
+
+ Decryption failed. The last 10 bytes of the encrypted data encryption key are: '{0}'. The first 10 bytes of ciphertext are: '{1}'. {2}
+
+
+ A default Always Encrypted compatible serializer cannot be found for type {0}. A serializer can be registered for this type with the {1} method.
+
+
+ A default serializer cannot be found for type {0}. A serializer can be registered for this type with the {1} method.
+
+
+ Internal error. Empty {0} specified.
+
+
+ Empty data encryption key specified.
+
+
+ Encryption failed. The last 10 bytes of the encrypted data encryption key are: '{0}'. {1}
+
+
+ The {0} {1} cannot be Plaintext in this context.
+
+
+ Signed hash length does not match the RSA key size.
+
+
+ Invalid Azure Key Vault key path specified: '{0}'. Valid trusted endpoints: {1}.
+
+
+ Invalid Azure Key Vault key path specified: '{0}'.
+
+
+ Invalid url specified: '{0}'.
+
+
+ The specified ciphertext's encryption algorithm version '{0}' does not match the expected encryption algorithm version '{1}'.
+
+
+ Specified encrypted data encryption key contains an invalid encryption algorithm version '{0}'. Expected version is '{1}'.
+
+
+ Specified ciphertext has an invalid authentication tag.
+
+
+ The specified encrypted data encryption key's ciphertext length: {0} does not match the ciphertext length: {1} when using key encryption key (Azure Key Vault key) in '{2}'. The encrypted data encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect.
+
+
+ Specified ciphertext has an invalid size of {0} bytes, which is below the minimum {1} bytes required for decryption.
+
+
+ The data encryption key has been successfully decrypted but its length: {0} does not match the length: 32 for algorithm 'AEAD_AES_256_CBC_HMAC_SHA256'. Verify the encrypted value of the data encryption key.
+
+
+ Encryption type '{0}' specified for the column is either invalid or corrupted. Valid encryption types for algorithm 'AEAD_AES_256_CBC_HMAC_SHA256' are: 'Plaintext', 'Deterministic', 'Randomized'.
+
+
+ The input is not a valid Hexadecimal string as it contains a non hexadecimal character, is not a multiple of 2 characters, or does not begin with '0x'.
+
+
+ Invalid key encryption algorithm specified: '{0}'. Expected value: '{1}'.
+
+
+ Invalid signature of the encrypted data encryption key computed.
+
+
+ The specified encrypted data encryption key's signature length: {0} does not match the signature length: {1} when using key encryption key (Azure Key Vault key) in '{2}'. The encrypted data encryption key may be corrupt, or the specified Azure Key Vault key path may be incorrect.
+
+
+ The specified encrypted data encryption key signature does not match the signature computed with the key encryption key (Asymmetric key in Azure Key Vault) in '{0}'. The encrypted data encryption key may be corrupt, or the specified path may be incorrect.
+
+
+ Invalid trusted endpoint specified: '{0}'; a trusted endpoint must have a value.
+
+
+ Cannot use a non-RSA key: '{0}'.
+
+
+ Azure Key Vault key path cannot be null.
+
+
+ Hash should not be null while decrypting encrypted data encryption key.
+
+
+ This reader's registered encryption key store providers does not contain a provider named {0}.
+
+
+ No serializer found for {0}
+
+
+ Use default serialization.
+
+
+ Parameter value {0} is out of range.
+
+
\ No newline at end of file
diff --git a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj
index b0a6d4465a..5e7141f9f9 100644
--- a/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj
+++ b/Microsoft.Azure.Cosmos.Encryption/src/Microsoft.Azure.Cosmos.Encryption.csproj
@@ -34,9 +34,7 @@
-
-
-
+