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());