Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -219,12 +219,21 @@
<Compile Include="$(CommonSourceRoot)Microsoft\Data\ProviderBase\TimeoutTimer.cs">
<Link>Microsoft\Data\ProviderBase\TimeoutTimer.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\AeadAes256CbcHmac256Factory.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\AeadAes256CbcHmac256Factory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\ColumnMasterKeyMetadata.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\ColumnMasterKeyMetadata.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptedColumnEncryptionKeyParameters.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptedColumnEncryptionKeyParameters.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactory.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactoryList.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactoryList.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\Sql\SqlDataSourceEnumerator.cs">
<Link>Microsoft\Data\Sql\SqlDataSourceEnumerator.cs</Link>
</Compile>
Expand Down Expand Up @@ -639,9 +648,6 @@
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256EncryptionKey.cs">
<Link>Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256EncryptionKey.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs">
<Link>Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlAppContextSwitchManager.netcore.cs">
<Link>Microsoft\Data\SqlClient\SqlAppContextSwitchManager.netcore.cs</Link>
</Compile>
Expand Down Expand Up @@ -690,12 +696,6 @@
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithm.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithm.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactory.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactoryList.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactoryList.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionType.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionType.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -304,12 +304,21 @@
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs">
<Link>Microsoft\Data\SqlClient\ActiveDirectoryAuthenticationTimeoutRetryHelper.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\AeadAes256CbcHmac256Factory.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\AeadAes256CbcHmac256Factory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\ColumnMasterKeyMetadata.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\ColumnMasterKeyMetadata.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptedColumnEncryptionKeyParameters.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptedColumnEncryptionKeyParameters.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactory.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactoryList.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncrypted\EncryptionAlgorithmFactoryList.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs</Link>
</Compile>
Expand Down Expand Up @@ -634,9 +643,6 @@
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256EncryptionKey.cs">
<Link>Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256EncryptionKey.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs">
<Link>Microsoft\Data\SqlClient\SqlAeadAes256CbcHmac256Factory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlAuthenticationParametersBuilder.cs">
<Link>Microsoft\Data\SqlClient\SqlAuthenticationParametersBuilder.cs</Link>
</Compile>
Expand Down Expand Up @@ -673,12 +679,6 @@
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithm.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithm.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactory.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactory.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactoryList.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionAlgorithmFactoryList.cs</Link>
</Compile>
<Compile Include="$(CommonSourceRoot)Microsoft\Data\SqlClient\SqlClientEncryptionType.cs">
<Link>Microsoft\Data\SqlClient\SqlClientEncryptionType.cs</Link>
</Compile>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand All @@ -7,68 +7,61 @@
using System.Diagnostics;
using System.Text;

namespace Microsoft.Data.SqlClient
#nullable enable

namespace Microsoft.Data.SqlClient.AlwaysEncrypted
{
/// <summary>
/// This is a factory class for AEAD_AES_256_CBC_HMAC_SHA256
/// This is a factory class for AEAD_AES_256_CBC_HMAC_SHA256.
/// </summary>
internal class SqlAeadAes256CbcHmac256Factory : SqlClientEncryptionAlgorithmFactory
internal sealed class AeadAes256CbcHmac256Factory : EncryptionAlgorithmFactory
{
/// <summary>
/// Factory classes caches the SqlAeadAes256CbcHmac256EncryptionKey objects to avoid computation of the derived keys
/// Factory classes cache the <see cref="SqlAeadAes256CbcHmac256EncryptionKey" /> objects to avoid recomputation of the derived keys.
/// </summary>
private readonly ConcurrentDictionary<string, SqlAeadAes256CbcHmac256Algorithm> _encryptionAlgorithms =
new ConcurrentDictionary<string, SqlAeadAes256CbcHmac256Algorithm>(concurrencyLevel: 4 * Environment.ProcessorCount /* default value in ConcurrentDictionary*/, capacity: 2);
new(concurrencyLevel: 4 * Environment.ProcessorCount /* default value in ConcurrentDictionary */, capacity: 2);

public static AeadAes256CbcHmac256Factory Instance => field ??= new();

/// <summary>
/// Creates an instance of AeadAes256CbcHmac256Algorithm class with a given key
/// Creates an instance of the <see cref="SqlAeadAes256CbcHmac256Algorithm" /> class with a given root key.
/// </summary>
/// <param name="encryptionKey">Root key</param>
/// <param name="encryptionType">Encryption Type. Expected values are either Deterministic or Randomized.</param>
/// <param name="encryptionAlgorithm">Encryption Algorithm.</param>
/// <returns></returns>
/// <param name="encryptionKey">Root key.</param>
/// <param name="encryptionType">Encryption type. Expected values are either Deterministic or Randomized.</param>
/// <param name="encryptionAlgorithm">Cryptographic algorithm.</param>
/// <returns>An implementation of the AEAD_AES_256_CBC_HMAC_SHA256 cryptographic algorithm.</returns>
internal override SqlClientEncryptionAlgorithm Create(SqlClientSymmetricKey encryptionKey, SqlClientEncryptionType encryptionType, string encryptionAlgorithm)
{
// Callers should have validated the encryption algorithm and the encryption key
Debug.Assert(encryptionKey != null);
Debug.Assert(string.Equals(encryptionAlgorithm, SqlAeadAes256CbcHmac256Algorithm.AlgorithmName, StringComparison.OrdinalIgnoreCase) == true);
Debug.Assert(string.Equals(encryptionAlgorithm, SqlAeadAes256CbcHmac256Algorithm.AlgorithmName, StringComparison.OrdinalIgnoreCase));

// Validate encryption type
if (!((encryptionType == SqlClientEncryptionType.Deterministic) || (encryptionType == SqlClientEncryptionType.Randomized)))
if (encryptionType is not SqlClientEncryptionType.Deterministic and not SqlClientEncryptionType.Randomized)
{
throw SQL.InvalidEncryptionType(SqlAeadAes256CbcHmac256Algorithm.AlgorithmName,
encryptionType,
SqlClientEncryptionType.Deterministic,
SqlClientEncryptionType.Randomized);
}

// Get the cached encryption algorithm if one exists or create a new one, add it to cache and use it
//
// For now, we only have one version. In future, we may need to parse the algorithm names to derive the version byte.
const byte algorithmVersion = 0x1;

StringBuilder algorithmKeyBuilder = new StringBuilder(Convert.ToBase64String(encryptionKey.RootKey), SqlSecurityUtility.GetBase64LengthFromByteLength(encryptionKey.RootKey.Length) + 4/*separators, type and version*/);

#if DEBUG
int capacity = algorithmKeyBuilder.Capacity;
#endif //DEBUG
// Get the cached cryptographic algorithm if one exists or create a new one, add it to cache and use it
int capacity = SqlSecurityUtility.GetBase64LengthFromByteLength(encryptionKey.RootKey.Length) + 4 /* Separators, type and version */;
StringBuilder algorithmKeyBuilder = new(Convert.ToBase64String(encryptionKey.RootKey), capacity);

algorithmKeyBuilder.Append(":");
algorithmKeyBuilder.Append(':');
algorithmKeyBuilder.Append((int)encryptionType);
algorithmKeyBuilder.Append(":");
algorithmKeyBuilder.Append(algorithmVersion);
algorithmKeyBuilder.Append(':');
algorithmKeyBuilder.Append(SqlAeadAes256CbcHmac256Algorithm.CurrentVersion);

string algorithmKey = algorithmKeyBuilder.ToString();

#if DEBUG
Debug.Assert(algorithmKey.Length <= capacity, "We needed to allocate a larger array");
#endif //DEBUG

SqlAeadAes256CbcHmac256Algorithm aesAlgorithm;
if (!_encryptionAlgorithms.TryGetValue(algorithmKey, out aesAlgorithm))
if (!_encryptionAlgorithms.TryGetValue(algorithmKey, out SqlAeadAes256CbcHmac256Algorithm? aesAlgorithm))
{
SqlAeadAes256CbcHmac256EncryptionKey encryptedKey = new SqlAeadAes256CbcHmac256EncryptionKey(encryptionKey.RootKey, SqlAeadAes256CbcHmac256Algorithm.AlgorithmName);
aesAlgorithm = new SqlAeadAes256CbcHmac256Algorithm(encryptedKey, encryptionType, algorithmVersion);
SqlAeadAes256CbcHmac256EncryptionKey encryptedKey = new(encryptionKey.RootKey, SqlAeadAes256CbcHmac256Algorithm.AlgorithmName);
aesAlgorithm = new SqlAeadAes256CbcHmac256Algorithm(encryptedKey, encryptionType, SqlAeadAes256CbcHmac256Algorithm.CurrentVersion);

// In case multiple threads reach here at the same time, the first one adds the value
// the second one will be a no-op, the allocated memory will be claimed by Garbage Collector.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable

namespace Microsoft.Data.SqlClient.AlwaysEncrypted;

/// <summary>
/// Abstract base class for all TCE cryptographic algorithm factory classes. Factory classes create instances of a cryptographic algorithm
/// with a given key. At runtime when we determine a particular column is marked for TCE, based on the cryptographic algorithm we invoke
/// the corresponding factory class and retrieve an implementation of an cryptographic algorithm.
/// </summary>
internal abstract class EncryptionAlgorithmFactory
{
/// <summary>
/// Creates a cryptographic algorithm with a given key.
/// </summary>
/// <param name="encryptionKey">Root key that should be passed to the cryptographic algorithm to be created</param>
/// <param name="encryptionType">Encryption Type, some algorithms will need this</param>
/// <param name="encryptionAlgorithm">Cryptographic algorithm name. Needed for extracting version bits</param>
/// <returns>Return a newly created SqlClientEncryptionAlgorithm instance</returns>
internal abstract SqlClientEncryptionAlgorithm Create(SqlClientSymmetricKey encryptionKey, SqlClientEncryptionType encryptionType, string encryptionAlgorithm);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

#nullable enable

namespace Microsoft.Data.SqlClient.AlwaysEncrypted;

/// <summary>
/// Implements a global mapping from a SQL Server cryptographic algorithm's name to its implementation.
/// </summary>
internal static class EncryptionAlgorithmFactoryList
{
/// <summary>
/// Get the available list of algorithms as a comma separated list with algorithm names
/// wrapped in single quotes.
/// </summary>
public const string RegisteredCipherAlgorithmNames = $"'{SqlAeadAes256CbcHmac256Algorithm.AlgorithmName}'";

/// <summary>
/// Gets the implementation for a given algorithm and instantiates it using the provided root key and the encryption type.
/// </summary>
/// <param name="key">The root key to use.</param>
/// <param name="type">Encryption type (read from SQL Server.)</param>
/// <param name="algorithmName">Name of the cryptographic algorithm.</param>
/// <param name="encryptionAlgorithm">Specified cryptographic algorithm's implementation.</param>
public static void GetAlgorithm(SqlClientSymmetricKey key, byte type, string algorithmName, out SqlClientEncryptionAlgorithm encryptionAlgorithm)
{
EncryptionAlgorithmFactory factory = algorithmName switch
{
SqlAeadAes256CbcHmac256Algorithm.AlgorithmName => AeadAes256CbcHmac256Factory.Instance,
_ => throw SQL.UnknownColumnEncryptionAlgorithm(algorithmName, RegisteredCipherAlgorithmNames)
};

encryptionAlgorithm = factory.Create(key, (SqlClientEncryptionType)type, algorithmName);
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using Microsoft.Data.SqlClient.AlwaysEncrypted;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
Expand All @@ -16,7 +17,7 @@ namespace Microsoft.Data.SqlClient
// @TODO: This isn't a delegate... it's a utility class
internal sealed partial class EnclaveDelegate
{
private static readonly SqlAeadAes256CbcHmac256Factory s_sqlAeadAes256CbcHmac256Factory = new SqlAeadAes256CbcHmac256Factory();
private static readonly AeadAes256CbcHmac256Factory s_aeadAes256CbcHmac256Factory = new AeadAes256CbcHmac256Factory();
private static readonly EnclaveDelegate s_enclaveDelegate = new EnclaveDelegate();

private readonly object _lock;
Expand Down Expand Up @@ -152,7 +153,7 @@ private byte[] EncryptBytePackage(byte[] bytePackage, byte[] sessionKey, string
try
{
SqlClientSymmetricKey symmetricKey = new SqlClientSymmetricKey(sessionKey);
SqlClientEncryptionAlgorithm sqlClientEncryptionAlgorithm = s_sqlAeadAes256CbcHmac256Factory.Create(
SqlClientEncryptionAlgorithm sqlClientEncryptionAlgorithm = s_aeadAes256CbcHmac256Factory.Create(
symmetricKey,
SqlClientEncryptionType.Randomized,
SqlAeadAes256CbcHmac256Algorithm.AlgorithmName
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

Expand All @@ -22,6 +22,14 @@ internal class SqlAeadAes256CbcHmac256Algorithm : SqlClientEncryptionAlgorithm
/// </summary>
internal const string AlgorithmName = @"AEAD_AES_256_CBC_HMAC_SHA256";

/// <summary>
/// Algorithm version
/// </summary>
/// <remarks>
/// For now, only one version exists. In future, this may be derived from the algorithm name.
/// </remarks>
public const byte CurrentVersion = 0x01;

/// <summary>
/// Key size in bytes
/// </summary>
Expand Down Expand Up @@ -77,7 +85,7 @@ internal class SqlAeadAes256CbcHmac256Algorithm : SqlClientEncryptionAlgorithm
/// <summary>
/// Byte array with algorithm version used for authentication tag computation.
/// </summary>
private static readonly byte[] _version = new byte[] { 0x01 };
private static readonly byte[] _version = [ CurrentVersion ];

/// <summary>
/// Byte array with algorithm version size used for authentication tag computation.
Expand Down

This file was deleted.

Loading
Loading