From 65d46969268886e34cd3789ab0665b2ff1cd39fd Mon Sep 17 00:00:00 2001 From: Johnny Pham <23270162+johnnypham@users.noreply.github.com> Date: Tue, 2 Feb 2021 14:13:59 -0800 Subject: [PATCH 1/2] fix key version bug --- .../AzureSqlKeyCryptographer.cs | 18 ++++--- ...qlColumnEncryptionAzureKeyVaultProvider.cs | 3 +- .../AlwaysEncrypted/AKVUnitTests.cs | 51 +++++++++++++++++++ .../ManualTests/DataCommon/DataTestUtility.cs | 9 ++-- 4 files changed, 69 insertions(+), 12 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/AzureSqlKeyCryptographer.cs b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/AzureSqlKeyCryptographer.cs index fa99c44350..a10e65c1cd 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/AzureSqlKeyCryptographer.cs +++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/AzureSqlKeyCryptographer.cs @@ -61,9 +61,9 @@ internal void AddKey(string keyIdentifierUri) { if (TheKeyHasNotBeenCached(keyIdentifierUri)) { - ParseAKVPath(keyIdentifierUri, out Uri vaultUri, out string keyName); + ParseAKVPath(keyIdentifierUri, out Uri vaultUri, out string keyName, out string keyVersion); CreateKeyClient(vaultUri); - FetchKey(vaultUri, keyName, keyIdentifierUri); + FetchKey(vaultUri, keyName, keyVersion, keyIdentifierUri); } bool TheKeyHasNotBeenCached(string k) => !_keyDictionary.ContainsKey(k) && !_keyFetchTaskDictionary.ContainsKey(k); @@ -151,10 +151,11 @@ private CryptographyClient GetCryptographyClient(string keyIdentifierUri) /// /// 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 keyResourceUri) + private void FetchKey(Uri vaultUri, string keyName, string keyVersion, string keyResourceUri) { - Task> fetchKeyTask = FetchKeyFromKeyVault(vaultUri, keyName); + Task> fetchKeyTask = FetchKeyFromKeyVault(vaultUri, keyName, keyVersion); _keyFetchTaskDictionary.AddOrUpdate(keyResourceUri, fetchKeyTask, (k, v) => fetchKeyTask); fetchKeyTask @@ -169,11 +170,12 @@ private void FetchKey(Uri vaultUri, string keyName, string keyResourceUri) /// /// The Azure Key Vault URI /// Then name of the key + /// Then version of the key /// - private Task> FetchKeyFromKeyVault(Uri vaultUri, string keyName) + private Task> FetchKeyFromKeyVault(Uri vaultUri, string keyName, string keyVersion) { _keyClientDictionary.TryGetValue(vaultUri, out KeyClient keyClient); - return keyClient.GetKeyAsync(keyName); + return keyClient.GetKeyAsync(keyName, keyVersion); } /// @@ -209,11 +211,13 @@ private void CreateKeyClient(Uri vaultUri) /// The Azure Key Vault key identifier /// The Azure Key Vault URI /// The name of the key - private void ParseAKVPath(string masterKeyPath, out Uri vaultUri, out string masterKeyName) + /// The version of the key + private void ParseAKVPath(string masterKeyPath, out Uri vaultUri, out string masterKeyName, out string masterKeyVersion) { Uri masterKeyPathUri = new Uri(masterKeyPath); vaultUri = new Uri(masterKeyPathUri.GetLeftPart(UriPartial.Authority)); masterKeyName = masterKeyPathUri.Segments[2]; + masterKeyVersion = masterKeyPathUri.Segments.Length > 3 ? masterKeyPathUri.Segments[3] : null; } } } diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs index 013c8e9cb0..1a02edf163 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs +++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs @@ -310,8 +310,7 @@ internal void ValidateNonEmptyAKVPath(string masterKeyPath, bool isSystemOp) throw new ArgumentException(errorMessage, Constants.AeParamMasterKeyPath); } - - if (!Uri.TryCreate(masterKeyPath, UriKind.Absolute, out Uri parsedUri)) + if (!Uri.TryCreate(masterKeyPath, UriKind.Absolute, out Uri parsedUri) || parsedUri.Segments.Length < 3) { // Return an error indicating that the AKV url is invalid. throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, Strings.InvalidAkvUrlTemplate, masterKeyPath), Constants.AeParamMasterKeyPath); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs index d58ee69281..c042339dc2 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/AlwaysEncrypted/AKVUnitTests.cs @@ -5,6 +5,10 @@ using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; using Azure.Identity; using Xunit; +using Azure.Security.KeyVault.Keys; +using Azure.Core; +using System.Reflection; +using System; namespace Microsoft.Data.SqlClient.ManualTesting.Tests.AlwaysEncrypted { @@ -52,5 +56,52 @@ public static void TokenCredentialRotationTest() byte[] decryptedCekWithNewProvider = newAkvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCekWithOldProvider); Assert.Equal(s_columnEncryptionKey, decryptedCekWithNewProvider); } + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))] + public static void ReturnSpecifiedVersionOfKeyWhenItIsNotTheMostRecentVersion() + { + Uri keyPathUri = new Uri(DataTestUtility.AKVOriginalUrl); + Uri vaultUri = new Uri(keyPathUri.GetLeftPart(UriPartial.Authority)); + + //If key version is not specified then we cannot test. + if (KeyIsVersioned(keyPathUri)) + { + string keyName = keyPathUri.Segments[2]; + string keyVersion = keyPathUri.Segments[3]; + ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); + KeyClient keyClient = new KeyClient(vaultUri, clientSecretCredential); + KeyVaultKey currentVersionKey = keyClient.GetKey(keyName); + KeyVaultKey specifiedVersionKey = keyClient.GetKey(keyName, keyVersion); + + //If specified versioned key is the most recent version of the key then we cannot test. + if (!KeyIsLatestVersion(specifiedVersionKey, currentVersionKey)) + { + SqlColumnEncryptionAzureKeyVaultProvider azureKeyProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); + // Perform an operation to initialize the internal caches + azureKeyProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVOriginalUrl, EncryptionAlgorithm, s_columnEncryptionKey); + + PropertyInfo keyCryptographerProperty = azureKeyProvider.GetType().GetProperty("KeyCryptographer", BindingFlags.NonPublic | BindingFlags.Instance); + var keyCryptographer = keyCryptographerProperty.GetValue(azureKeyProvider); + MethodInfo getKeyMethod = keyCryptographer.GetType().GetMethod("GetKey", BindingFlags.NonPublic | BindingFlags.Instance); + KeyVaultKey key = (KeyVaultKey)getKeyMethod.Invoke(keyCryptographer, new[] { DataTestUtility.AKVOriginalUrl }); + + Assert.Equal(keyVersion, key.Properties.Version); + } + } + } + + static bool KeyIsVersioned(Uri keyPath) => keyPath.Segments.Length > 3; + static bool KeyIsLatestVersion(KeyVaultKey specifiedVersionKey, KeyVaultKey currentVersionKey) => currentVersionKey.Properties.Version == specifiedVersionKey.Properties.Version; + + [ConditionalFact(typeof(DataTestUtility), nameof(DataTestUtility.IsAKVSetupAvailable))] + public static void ThrowWhenUrlHasLessThanThreeSegments() + { + SqlColumnEncryptionAzureKeyVaultProvider azureKeyProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); + string invalidKeyPath = "https://my-key-vault.vault.azure.net/keys"; + Exception ex1 = Assert.Throws(() => azureKeyProvider.EncryptColumnEncryptionKey(invalidKeyPath, EncryptionAlgorithm, s_columnEncryptionKey)); + Assert.Contains($"Invalid url specified: '{invalidKeyPath}'", ex1.Message); + Exception ex2 = Assert.Throws(() => azureKeyProvider.DecryptColumnEncryptionKey(invalidKeyPath, EncryptionAlgorithm, s_columnEncryptionKey)); + Assert.Contains($"Invalid url specified: '{invalidKeyPath}'", ex2.Message); + } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs index 0f9211ee3a..617f905ff7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/DataTestUtility.cs @@ -15,6 +15,8 @@ using Microsoft.Identity.Client; using Microsoft.Data.SqlClient.TestUtilities; using Xunit; +using Azure.Security.KeyVault.Keys; +using Azure.Identity; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { @@ -32,6 +34,7 @@ public static class DataTestUtility public static readonly string AADAccessToken = null; public static readonly string AKVBaseUrl = null; public static readonly string AKVUrl = null; + public static readonly string AKVOriginalUrl = null; public static readonly string AKVTenantId = null; public static readonly string AKVClientId = null; public static readonly string AKVClientSecret = null; @@ -103,14 +106,14 @@ static DataTestUtility() AADAccessToken = GenerateAccessToken(AADAuthorityURL, username, password); } - string url = c.AzureKeyVaultURL; - if (!string.IsNullOrEmpty(url) && Uri.TryCreate(url, UriKind.Absolute, out Uri AKVBaseUri)) + AKVOriginalUrl = c.AzureKeyVaultURL; + if (!string.IsNullOrEmpty(AKVOriginalUrl) && Uri.TryCreate(AKVOriginalUrl, UriKind.Absolute, out Uri AKVBaseUri)) { AKVBaseUri = new Uri(AKVBaseUri, "/"); AKVBaseUrl = AKVBaseUri.AbsoluteUri; AKVUrl = (new Uri(AKVBaseUri, $"/keys/{AKVKeyName}")).AbsoluteUri; } - + AKVTenantId = c.AzureKeyVaultTenantId; AKVClientId = c.AzureKeyVaultClientId; AKVClientSecret = c.AzureKeyVaultClientSecret; From 0c6c2f5c9f910320fc1cb9c84a9d013fc4a1808b Mon Sep 17 00:00:00 2001 From: Johnny Pham <23270162+johnnypham@users.noreply.github.com> Date: Thu, 4 Feb 2021 18:15:19 -0800 Subject: [PATCH 2/2] add enclave example using new akv. update public api comments --- ...oviderLegacyWithEnclaveProviderExample.cs} | 0 ...tProviderWithEnclaveProviderExample_2_0.cs | 253 ++++++++++++++++++ ...qlColumnEncryptionAzureKeyVaultProvider.cs | 14 +- 3 files changed, 260 insertions(+), 7 deletions(-) rename doc/samples/{AzureKeyVaultProviderWithEnclaveProviderExample.cs => AzureKeyVaultProviderLegacyWithEnclaveProviderExample.cs} (100%) create mode 100644 doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample_2_0.cs diff --git a/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample.cs b/doc/samples/AzureKeyVaultProviderLegacyWithEnclaveProviderExample.cs similarity index 100% rename from doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample.cs rename to doc/samples/AzureKeyVaultProviderLegacyWithEnclaveProviderExample.cs diff --git a/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample_2_0.cs b/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample_2_0.cs new file mode 100644 index 0000000000..a4e288a1d9 --- /dev/null +++ b/doc/samples/AzureKeyVaultProviderWithEnclaveProviderExample_2_0.cs @@ -0,0 +1,253 @@ +using System; +// +using System.Collections.Generic; +using System.Security.Cryptography; +using System.Threading.Tasks; +using Azure.Identity; +using Microsoft.Data.SqlClient; +using Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider; + +namespace AKVEnclaveExample +{ + class Program + { + static readonly string s_algorithm = "RSA_OAEP"; + + // ********* Provide details here *********** + static readonly string s_akvUrl = "https://{KeyVaultName}.vault.azure.net/keys/{Key}/{KeyIdentifier}"; + static readonly string s_clientId = "{Application_Client_ID}"; + static readonly string s_clientSecret = "{Application_Client_Secret}"; + static readonly string s_tenantId = "{Azure_Key_Vault_Active_Directory_Tenant_Id}"; + static readonly string s_connectionString = "Server={Server}; Database={database}; Integrated Security=true; Column Encryption Setting=Enabled; Attestation Protocol=HGS; Enclave Attestation Url = {attestation_url_for_HGS};"; + // ****************************************** + + static void Main(string[] args) + { + // Initialize AKV provider + ClientSecretCredential clientSecretCredential = new ClientSecretCredential(s_tenantId, s_clientId, s_clientSecret); + SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); + + // Register AKV provider + SqlConnection.RegisterColumnEncryptionKeyStoreProviders(customProviders: new Dictionary(capacity: 1, comparer: StringComparer.OrdinalIgnoreCase) + { + { SqlColumnEncryptionAzureKeyVaultProvider.ProviderName, akvProvider} + }); + Console.WriteLine("AKV provider Registered"); + + // Create connection to database + using (SqlConnection sqlConnection = new SqlConnection(s_connectionString)) + { + string cmkName = "CMK_WITH_AKV"; + string cekName = "CEK_WITH_AKV"; + string tblName = "AKV_TEST_TABLE"; + + CustomerRecord customer = new CustomerRecord(1, @"Microsoft", @"Corporation"); + + try + { + sqlConnection.Open(); + + // Drop Objects if exists + dropObjects(sqlConnection, cmkName, cekName, tblName); + + // Create Column Master Key with AKV Url + createCMK(sqlConnection, cmkName, akvProvider); + Console.WriteLine("Column Master Key created."); + + // Create Column Encryption Key + createCEK(sqlConnection, cmkName, cekName, akvProvider); + Console.WriteLine("Column Encryption Key created."); + + // Create Table with Encrypted Columns + createTbl(sqlConnection, cekName, tblName); + Console.WriteLine("Table created with Encrypted columns."); + + // Insert Customer Record in table + insertData(sqlConnection, tblName, customer); + Console.WriteLine("Encryted data inserted."); + + // Read data from table + verifyData(sqlConnection, tblName, customer); + Console.WriteLine("Data validated successfully."); + } + finally + { + // Drop table and keys + dropObjects(sqlConnection, cmkName, cekName, tblName); + Console.WriteLine("Dropped Table, CEK and CMK"); + } + + Console.WriteLine("Completed AKV provider Sample."); + + Console.ReadKey(); + } + } + + private static void createCMK(SqlConnection sqlConnection, string cmkName, SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider) + { + string KeyStoreProviderName = SqlColumnEncryptionAzureKeyVaultProvider.ProviderName; + + byte[] cmkSign = sqlColumnEncryptionAzureKeyVaultProvider.SignColumnMasterKeyMetadata(s_akvUrl, true); + string cmkSignStr = string.Concat("0x", BitConverter.ToString(cmkSign).Replace("-", string.Empty)); + + string sql = + $@"CREATE COLUMN MASTER KEY [{cmkName}] + WITH ( + KEY_STORE_PROVIDER_NAME = N'{KeyStoreProviderName}', + KEY_PATH = N'{s_akvUrl}', + ENCLAVE_COMPUTATIONS (SIGNATURE = {cmkSignStr}) + );"; + + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = sql; + command.ExecuteNonQuery(); + } + } + + private static void createCEK(SqlConnection sqlConnection, string cmkName, string cekName, SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider) + { + string sql = + $@"CREATE COLUMN ENCRYPTION KEY [{cekName}] + WITH VALUES ( + COLUMN_MASTER_KEY = [{cmkName}], + ALGORITHM = '{s_algorithm}', + ENCRYPTED_VALUE = {GetEncryptedValue(sqlColumnEncryptionAzureKeyVaultProvider)} + )"; + + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = sql; + command.ExecuteNonQuery(); + } + } + + private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider) + { + byte[] plainTextColumnEncryptionKey = new byte[32]; + RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider(); + rngCsp.GetBytes(plainTextColumnEncryptionKey); + + byte[] encryptedColumnEncryptionKey = sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm, plainTextColumnEncryptionKey); + string EncryptedValue = string.Concat("0x", BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty)); + return EncryptedValue; + } + + private static void createTbl(SqlConnection sqlConnection, string cekName, string tblName) + { + string ColumnEncryptionAlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA_256"; + + string sql = + $@"CREATE TABLE [dbo].[{tblName}] + ( + [CustomerId] [int] ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}'), + [FirstName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}'), + [LastName] [nvarchar](50) COLLATE Latin1_General_BIN2 ENCRYPTED WITH (COLUMN_ENCRYPTION_KEY = [{cekName}], ENCRYPTION_TYPE = RANDOMIZED, ALGORITHM = '{ColumnEncryptionAlgorithmName}') + )"; + + using (SqlCommand command = sqlConnection.CreateCommand()) + { + command.CommandText = sql; + command.ExecuteNonQuery(); + } + } + + private static void insertData(SqlConnection sqlConnection, string tblName, CustomerRecord customer) + { + string insertSql = $"INSERT INTO [{tblName}] (CustomerId, FirstName, LastName) VALUES (@CustomerId, @FirstName, @LastName);"; + + using (SqlTransaction sqlTransaction = sqlConnection.BeginTransaction()) + using (SqlCommand sqlCommand = new SqlCommand(insertSql, + connection: sqlConnection, transaction: sqlTransaction, + columnEncryptionSetting: SqlCommandColumnEncryptionSetting.Enabled)) + { + sqlCommand.Parameters.AddWithValue(@"CustomerId", customer.Id); + sqlCommand.Parameters.AddWithValue(@"FirstName", customer.FirstName); + sqlCommand.Parameters.AddWithValue(@"LastName", customer.LastName); + + sqlCommand.ExecuteNonQuery(); + sqlTransaction.Commit(); + } + } + + private static void verifyData(SqlConnection sqlConnection, string tblName, CustomerRecord customer) + { + // Test INPUT parameter on an encrypted parameter + using (SqlCommand sqlCommand = new SqlCommand($"SELECT CustomerId, FirstName, LastName FROM [{tblName}] WHERE FirstName = @firstName", + sqlConnection)) + { + SqlParameter customerFirstParam = sqlCommand.Parameters.AddWithValue(@"firstName", @"Microsoft"); + customerFirstParam.Direction = System.Data.ParameterDirection.Input; + customerFirstParam.ForceColumnEncryption = true; + + using (SqlDataReader sqlDataReader = sqlCommand.ExecuteReader()) + { + ValidateResultSet(sqlDataReader); + } + } + } + + private static void ValidateResultSet(SqlDataReader sqlDataReader) + { + Console.WriteLine(" * Row available: " + sqlDataReader.HasRows); + + while (sqlDataReader.Read()) + { + if (sqlDataReader.GetInt32(0) == 1) + { + Console.WriteLine(" * Employee Id received as sent: " + sqlDataReader.GetInt32(0)); + } + else + { + Console.WriteLine("Employee Id didn't match"); + } + + if (sqlDataReader.GetString(1) == @"Microsoft") + { + Console.WriteLine(" * Employee Firstname received as sent: " + sqlDataReader.GetString(1)); + } + else + { + Console.WriteLine("Employee FirstName didn't match."); + } + + if (sqlDataReader.GetString(2) == @"Corporation") + { + Console.WriteLine(" * Employee LastName received as sent: " + sqlDataReader.GetString(2)); + } + else + { + Console.WriteLine("Employee LastName didn't match."); + } + } + } + + private static void dropObjects(SqlConnection sqlConnection, string cmkName, string cekName, string tblName) + { + using (SqlCommand cmd = sqlConnection.CreateCommand()) + { + cmd.CommandText = $@"IF EXISTS (select * from sys.objects where name = '{tblName}') BEGIN DROP TABLE [{tblName}] END"; + cmd.ExecuteNonQuery(); + cmd.CommandText = $@"IF EXISTS (select * from sys.column_encryption_keys where name = '{cekName}') BEGIN DROP COLUMN ENCRYPTION KEY [{cekName}] END"; + cmd.ExecuteNonQuery(); + cmd.CommandText = $@"IF EXISTS (select * from sys.column_master_keys where name = '{cmkName}') BEGIN DROP COLUMN MASTER KEY [{cmkName}] END"; + cmd.ExecuteNonQuery(); + } + } + + private class CustomerRecord + { + internal int Id { get; set; } + internal string FirstName { get; set; } + internal string LastName { get; set; } + + public CustomerRecord(int id, string fName, string lName) + { + Id = id; + FirstName = fName; + LastName = lName; + } + } + } +} +// diff --git a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs index 1a02edf163..4c3c56cee2 100644 --- a/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs +++ b/src/Microsoft.Data.SqlClient/add-ons/AzureKeyVaultProvider/SqlColumnEncryptionAzureKeyVaultProvider.cs @@ -35,7 +35,7 @@ namespace Microsoft.Data.SqlClient.AlwaysEncrypted.AzureKeyVaultProvider /// API only once in the lifetime of driver to register this custom provider by implementing a custom Authentication Callback mechanism. /// @@ -117,10 +117,10 @@ public SqlColumnEncryptionAzureKeyVaultProvider(TokenCredential tokenCredential, #region Public methods /// - /// Uses an asymmetric key identified by the key path to sign the masterkey metadata consisting of (masterKeyPath, allowEnclaveComputations bit, providerName). + /// Uses an asymmetric key identified by the key path to sign the master key metadata consisting of (masterKeyPath, allowEnclaveComputations bit, providerName). /// /// Complete path of an asymmetric key. Path format is specific to a key store provider. - /// Boolean indicating whether this key can be sent to trusted enclave + /// Boolean indicating whether this key can be sent to a trusted enclave /// Encrypted column encryption key public override byte[] SignColumnMasterKeyMetadata(string masterKeyPath, bool allowEnclaveComputations) { @@ -133,7 +133,7 @@ public override byte[] SignColumnMasterKeyMetadata(string masterKeyPath, bool al } /// - /// Uses an asymmetric key identified by the key path to verify the masterkey metadata consisting of (masterKeyPath, allowEnclaveComputations bit, providerName). + /// Uses an asymmetric key identified by the key path to verify the master key metadata consisting of (masterKeyPath, allowEnclaveComputations bit, providerName). /// /// Complete path of an asymmetric key. Path format is specific to a key store provider. /// Boolean indicating whether this key can be sent to trusted enclave @@ -153,7 +153,7 @@ public override bool VerifyColumnMasterKeyMetadata(string masterKeyPath, bool al /// This function uses the asymmetric key specified by the key path /// and decrypts an encrypted CEK with RSA encryption algorithm. /// - /// Complete path of an asymmetric key in AKV + /// Complete path of an asymmetric key in Azure Key Vault /// Asymmetric Key Encryption Algorithm /// Encrypted Column Encryption Key /// Plain text column encryption key @@ -234,7 +234,7 @@ public override byte[] DecryptColumnEncryptionKey(string masterKeyPath, string e /// This function uses the asymmetric key specified by the key path /// and encrypts CEK with RSA encryption algorithm. /// - /// Complete path of an asymmetric key in AKV + /// Complete path of an asymmetric key in Azure Key Vault /// Asymmetric Key Encryption Algorithm /// Plain text column encryption key /// Encrypted column encryption key @@ -253,7 +253,7 @@ public override byte[] EncryptColumnEncryptionKey(string masterKeyPath, string e // Construct the encryptedColumnEncryptionKey // Format is - // s_firstVersion + keyPathLength + ciphertextLength + ciphertext + keyPath + signature + // s_firstVersion + keyPathLength + ciphertextLength + keyPath + ciphertext + signature // Get the Unicode encoded bytes of cultureinvariant lower case masterKeyPath byte[] masterKeyPathBytes = Encoding.Unicode.GetBytes(masterKeyPath.ToLowerInvariant());