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); } } }
private static string GetEncryptedValue(SqlColumnEncryptionAzureKeyVaultProvider sqlColumnEncryptionAzureKeyVaultProvider) { byte[] plainTextColumnEncryptionKey = new byte[32]; RandomNumberGenerator rng = RandomNumberGenerator.Create(); rng.GetBytes(plainTextColumnEncryptionKey); byte[] encryptedColumnEncryptionKey = sqlColumnEncryptionAzureKeyVaultProvider.EncryptColumnEncryptionKey(s_akvUrl, s_algorithm, plainTextColumnEncryptionKey); string EncryptedValue = string.Concat("0x", BitConverter.ToString(encryptedColumnEncryptionKey).Replace("-", string.Empty)); return EncryptedValue; }
public static void TokenCredentialTest() { ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); byte[] encryptedCek = akvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCek = akvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCek); Assert.Equal(s_columnEncryptionKey, decryptedCek); }
public static void LegacyAuthenticationCallbackTest() { // SqlClientCustomTokenCredential implements legacy authentication callback to request access token at client-side. SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); byte[] encryptedCek = akvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCek = akvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCek); Assert.Equal(s_columnEncryptionKey, decryptedCek); }
public static void ThrowWhenUrlHasLessThanThreeSegments() { SqlColumnEncryptionAzureKeyVaultProvider azureKeyProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); string invalidKeyPath = "https://my-key-vault.vault.azure.net/keys"; Exception ex1 = Assert.Throws <ArgumentException>(() => azureKeyProvider.EncryptColumnEncryptionKey(invalidKeyPath, EncryptionAlgorithm, s_columnEncryptionKey)); Assert.Contains($"Invalid url specified: '{invalidKeyPath}'", ex1.Message); Exception ex2 = Assert.Throws <ArgumentException>(() => azureKeyProvider.DecryptColumnEncryptionKey(invalidKeyPath, EncryptionAlgorithm, s_columnEncryptionKey)); Assert.Contains($"Invalid url specified: '{invalidKeyPath}'", ex2.Message); }
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); }
public void IsCompatibleWithProviderUsingLegacyClient() { AzureKeyVaultKeyStoreProvider newAkvProvider = new AzureKeyVaultKeyStoreProvider(new ClientSecretCredential(tenantId, clientId, clientSecret)); SqlColumnEncryptionAzureKeyVaultProvider oldAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(AzureActiveDirectoryAuthenticationCallback); byte[] encryptedCekWithNewProvider = newAkvProvider.WrapKey(keyEncryptionKeyPath, EncryptionAlgorithm, ColumnEncryptionKey); byte[] decryptedCekWithOldProvider = oldAkvProvider.DecryptColumnEncryptionKey(keyEncryptionKeyPath, EncryptionAlgorithm.ToString(), encryptedCekWithNewProvider); Assert.Equal(ColumnEncryptionKey, decryptedCekWithOldProvider); byte[] encryptedCekWithOldProvider = oldAkvProvider.EncryptColumnEncryptionKey(keyEncryptionKeyPath, EncryptionAlgorithm.ToString(), ColumnEncryptionKey); byte[] decryptedCekWithNewProvider = newAkvProvider.UnwrapKey(keyEncryptionKeyPath, EncryptionAlgorithm, encryptedCekWithOldProvider); Assert.Equal(ColumnEncryptionKey, decryptedCekWithNewProvider); }
public static void TokenCredentialTest() { Guid activityId = Trace.CorrelationManager.ActivityId = Guid.NewGuid(); using DataTestUtility.AKVEventListener AKVListener = new(); ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); byte[] encryptedCek = akvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCek = akvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCek); Assert.Equal(s_columnEncryptionKey, decryptedCek); ValidateAKVTraces(AKVListener.EventData, activityId); }
public static void LegacyAuthenticationCallbackTest() { Guid activityId = Trace.CorrelationManager.ActivityId = Guid.NewGuid(); using DataTestUtility.AKVEventListener AKVListener = new(); // SqlClientCustomTokenCredential implements legacy authentication callback to request access token at client-side. SqlColumnEncryptionAzureKeyVaultProvider akvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); byte[] encryptedCek = akvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCek = akvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCek); Assert.Equal(s_columnEncryptionKey, decryptedCek); ValidateAKVTraces(AKVListener.EventData, activityId); }
public static void TokenCredentialRotationTest() { // SqlClientCustomTokenCredential implements a legacy authentication callback to request the access token from the client-side. SqlColumnEncryptionAzureKeyVaultProvider oldAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); SqlColumnEncryptionAzureKeyVaultProvider newAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); byte[] encryptedCekWithNewProvider = newAkvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCekWithOldProvider = oldAkvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCekWithNewProvider); Assert.Equal(s_columnEncryptionKey, decryptedCekWithOldProvider); byte[] encryptedCekWithOldProvider = oldAkvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCekWithNewProvider = newAkvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCekWithOldProvider); Assert.Equal(s_columnEncryptionKey, decryptedCekWithNewProvider); }
static void CreateColumnEncryptionKey(SqlConnection connection, string cekName, string cmkName, string keyId, ref SqlColumnEncryptionAzureKeyVaultProvider akvprov) { // Generate the raw bytes that will be used as a key by using a CSPRNG byte[] cekRawValue = new byte[32]; var provider = new RNGCryptoServiceProvider(); provider.GetBytes(cekRawValue); // Encrypt the newly created random key using the AKV provider var cekEncryptedValue = akvprov.EncryptColumnEncryptionKey(keyId, @"RSA_OAEP", cekRawValue); var cmd = connection.CreateCommand(); // Prevent SQL injections by escaping the user-defined tokens cmd.CommandText = string.Format(CreateColumnEncryptionKeyTemplate, cekName.Replace("]", "]]"), cmkName.Replace("]", "]]"), BytesToHex(cekEncryptedValue)); cmd.ExecuteNonQuery(); }
public static void CekCacheShouldBeDisabledWhenCustomProviderIsRegisteredGlobally() { if (SQLSetupStrategyAzureKeyVault.IsAKVProviderRegistered) { SqlConnection conn = new(); FieldInfo globalCacheField = conn.GetType().GetField( "s_globalCustomColumnEncryptionKeyStoreProviders", BindingFlags.Static | BindingFlags.NonPublic); IReadOnlyDictionary <string, SqlColumnEncryptionKeyStoreProvider> globalProviders = globalCacheField.GetValue(conn) as IReadOnlyDictionary <string, SqlColumnEncryptionKeyStoreProvider>; SqlColumnEncryptionAzureKeyVaultProvider akvProviderInGlobalCache = globalProviders["AZURE_KEY_VAULT"] as SqlColumnEncryptionAzureKeyVaultProvider; byte[] plaintextKey = { 1, 2, 3 }; byte[] encryptedKey = akvProviderInGlobalCache.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, "RSA_OAEP", plaintextKey); akvProviderInGlobalCache.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, "RSA_OAEP", encryptedKey); Assert.Equal(0, GetCacheCount(cekCacheName, akvProviderInGlobalCache)); } }
public static void TokenCredentialRotationTest() { Guid activityId = Trace.CorrelationManager.ActivityId = Guid.NewGuid(); using DataTestUtility.AKVEventListener AKVListener = new(); // SqlClientCustomTokenCredential implements a legacy authentication callback to request the access token from the client-side. SqlColumnEncryptionAzureKeyVaultProvider oldAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(new SqlClientCustomTokenCredential()); ClientSecretCredential clientSecretCredential = new ClientSecretCredential(DataTestUtility.AKVTenantId, DataTestUtility.AKVClientId, DataTestUtility.AKVClientSecret); SqlColumnEncryptionAzureKeyVaultProvider newAkvProvider = new SqlColumnEncryptionAzureKeyVaultProvider(clientSecretCredential); byte[] encryptedCekWithNewProvider = newAkvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCekWithOldProvider = oldAkvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCekWithNewProvider); Assert.Equal(s_columnEncryptionKey, decryptedCekWithOldProvider); byte[] encryptedCekWithOldProvider = oldAkvProvider.EncryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, s_columnEncryptionKey); byte[] decryptedCekWithNewProvider = newAkvProvider.DecryptColumnEncryptionKey(DataTestUtility.AKVUrl, EncryptionAlgorithm, encryptedCekWithOldProvider); Assert.Equal(s_columnEncryptionKey, decryptedCekWithNewProvider); ValidateAKVTraces(AKVListener.EventData, activityId); }