Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync Crypto api usage #1022

Merged
merged 11 commits into from
Apr 28, 2021
Merged
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,12 @@
<Compile Include="Microsoft.Data.SqlClient.TypeForwards.cs" />
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard' AND '$(TargetFramework)' == 'netstandard2.0'">
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.NetStandard.cs" />
<Compile Include="..\..\src\Microsoft\Data\SqlClient\EnclaveDelegate.NotSupported.cs">
<Link>Microsoft\Data\SqlClient\EnclaveDelegate.NotSupported.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NotSupported.cs">
<Link>Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NotSupported.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetGroup)' == 'netstandard'">
<Compile Include="Microsoft\Data\SqlClient\SqlAuthenticationProviderManager.NetStandard.cs" />
Expand All @@ -335,23 +340,29 @@
<Compile Include="..\..\src\Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncryptedEnclaveProviderUtils.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\AlwaysEncryptedKeyConverter.cs">
<Link>Microsoft\Data\SqlClient\AlwaysEncryptedKeyConverter.cs</Link>
</Compile>
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedKeyConverter.CrossPlatform.cs" />
<Compile Include="..\..\src\Microsoft\Data\SqlClient\EnclaveProviderBase.cs">
<Link>Microsoft\Data\SqlClient\EnclaveProviderBase.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\EnclaveSessionCache.cs">
<Link>Microsoft\Data\SqlClient\EnclaveSessionCache.cs</Link>
</Compile>
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.NetCoreApp.cs" />
<Compile Include="Microsoft\Data\SqlClient\EnclaveDelegate.CrossPlatformCrypto.cs" />
<Compile Include="Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs" />
<Compile Include="..\..\src\Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.Crypto.cs">
<Link>Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.Crypto.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\EnclaveDelegate.Crypto.cs">
<Link>Microsoft\Data\SqlClient\EnclaveDelegate.Crypto.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs">
<Link>Microsoft\Data\SqlClient\AzureAttestationBasedEnclaveProvider.cs</Link>
</Compile>
<Compile Include="..\..\src\Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs">
<Link>Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProvider.cs</Link>
</Compile>
<Compile Include="Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs" />
<Compile Include="..\..\src\Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs">
<Link>Microsoft\Data\SqlClient\VirtualSecureModeEnclaveProviderBase.cs</Link>
</Compile>
</ItemGroup>
<!-- netcoreapp 3.1 & netstandard 2.1 and above -->
<ItemGroup Condition="'$(OSGroup)' != 'AnyOS' AND '$(TargetFramework)' != 'netcoreapp2.1' AND '$(TargetFramework)' != 'netstandard2.0'">
Expand Down Expand Up @@ -523,7 +534,6 @@
<Compile Include="Microsoft\Data\SqlClient\AlwaysEncryptedHelperClasses.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlQueryMetadataCache.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlColumnEncryptionEnclaveProvider.cs" />
<Compile Include="Microsoft\Data\SqlClient\SqlEnclaveAttestationParameters.cs" />
</ItemGroup>
<!-- Windows only -->
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,56 @@
using System;
using System.Diagnostics;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

namespace Microsoft.Data.SqlClient
{
// Contains methods to convert cryptography keys between different formats.
internal sealed class KeyConverter
{
internal sealed partial class KeyConverter
{
// Magic numbers identifying blob types
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/cba27df5-4880-4f95-a879-783f8657e53b
private readonly struct KeyBlobMagicNumber
{
internal static readonly byte[] ECDHPublicP384 = new byte[] { 0x45, 0x43, 0x4b, 0x33 };
}

// The ECC public key blob is structured as follows:
// BCRYPT_ECCKEY_BLOB header
// byte[KeySize] X
// byte[KeySize] Y
private readonly struct ECCPublicKeyBlob
{
// Size of an ECC public key blob
internal const int Size = 104;
// Size of the BCRYPT_ECCKEY_BLOB header
internal const int HeaderSize = 8;
// Size of each coordinate
internal const int KeySize = (Size - HeaderSize) / 2;
}

// Serializes an ECDiffieHellmanPublicKey to an ECC public key blob
// "ECDiffieHellmanPublicKey.ToByteArray() doesn't have a (standards-)defined export
// format. The version used by ECDiffieHellmanPublicKeyCng is Windows-specific"
// from https://github.com/dotnet/runtime/issues/27276
// => ECDiffieHellmanPublicKey.ToByteArray() is not supported in Unix
internal static byte[] GetECDiffieHellmanPublicKeyBlob(ECDiffieHellman ecDiffieHellman)
{
byte[] keyBlob = new byte[ECCPublicKeyBlob.Size];

// Set magic number
Buffer.BlockCopy(KeyBlobMagicNumber.ECDHPublicP384, 0, keyBlob, 0, 4);
// Set key size
keyBlob[4] = (byte)ECCPublicKeyBlob.KeySize;

ECPoint ecPoint = ecDiffieHellman.PublicKey.ExportParameters().Q;
Debug.Assert(ecPoint.X.Length == ECCPublicKeyBlob.KeySize && ecPoint.Y.Length == ECCPublicKeyBlob.KeySize,
$"ECDH public key was not the expected length. Actual (X): {ecPoint.X.Length}. Actual (Y): {ecPoint.Y.Length} Expected: {ECCPublicKeyBlob.Size}");
// Copy x and y coordinates to key blob
Buffer.BlockCopy(ecPoint.X, 0, keyBlob, ECCPublicKeyBlob.HeaderSize, ECCPublicKeyBlob.KeySize);
Buffer.BlockCopy(ecPoint.Y, 0, keyBlob, ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize, ECCPublicKeyBlob.KeySize);
return keyBlob;
}

// The RSA public key blob is structured as follows:
// BCRYPT_RSAKEY_BLOB header
// byte[ExponentSize] publicExponent
Expand All @@ -29,59 +73,32 @@ private readonly struct RSAPublicKeyBlob
internal const int ModulusOffset = HeaderSize;
}

// Extracts the public key's modulus and exponent from an RSA public key blob
// and returns an RSAParameters object
internal static RSAParameters RSAPublicKeyBlobToParams(byte[] keyBlob)
internal static RSA CreateRSAFromPublicKeyBlob(byte[] keyBlob)
{
Debug.Assert(keyBlob.Length == RSAPublicKeyBlob.Size,
$"RSA public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {RSAPublicKeyBlob.Size}");
Debug.Assert(keyBlob.Length == RSAPublicKeyBlob.Size, $"RSA public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {RSAPublicKeyBlob.Size}");

byte[] exponent = new byte[RSAPublicKeyBlob.ExponentSize];
byte[] modulus = new byte[RSAPublicKeyBlob.ModulusSize];
Buffer.BlockCopy(keyBlob, RSAPublicKeyBlob.ExponentOffset, exponent, 0, RSAPublicKeyBlob.ExponentSize);
Buffer.BlockCopy(keyBlob, RSAPublicKeyBlob.ModulusOffset, modulus, 0, RSAPublicKeyBlob.ModulusSize);

return new RSAParameters()
var rsaParameters = new RSAParameters()
{
Exponent = exponent,
Modulus = modulus
};
return RSA.Create(rsaParameters);
}

// The ECC public key blob is structured as follows:
// BCRYPT_ECCKEY_BLOB header
// byte[KeySize] X
// byte[KeySize] Y
private readonly struct ECCPublicKeyBlob
{
// Size of an ECC public key blob
internal const int Size = 104;
// Size of the BCRYPT_ECCKEY_BLOB header
internal const int HeaderSize = 8;
// Size of each coordinate
internal const int KeySize = (Size - HeaderSize) / 2;
}

// Magic numbers identifying blob types
// https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-wcce/cba27df5-4880-4f95-a879-783f8657e53b
private readonly struct KeyBlobMagicNumber
{
internal static readonly byte[] ECDHPublicP384 = new byte[] { 0x45, 0x43, 0x4b, 0x33 };
}

// Extracts the public key's X and Y coordinates from an ECC public key blob
// and returns an ECParameters object
internal static ECParameters ECCPublicKeyBlobToParams(byte[] keyBlob)
internal static ECDiffieHellman CreateECDiffieHellmanFromPublicKeyBlob(byte[] keyBlob)
{
Debug.Assert(keyBlob.Length == ECCPublicKeyBlob.Size,
$"ECC public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {ECCPublicKeyBlob.Size}");
Debug.Assert(keyBlob.Length == ECCPublicKeyBlob.Size, $"ECC public key blob was not the expected length. Actual: {keyBlob.Length}. Expected: {ECCPublicKeyBlob.Size}");

byte[] x = new byte[ECCPublicKeyBlob.KeySize];
byte[] y = new byte[ECCPublicKeyBlob.KeySize];
Buffer.BlockCopy(keyBlob, ECCPublicKeyBlob.HeaderSize, x, 0, ECCPublicKeyBlob.KeySize);
Buffer.BlockCopy(keyBlob, ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize, y, 0, ECCPublicKeyBlob.KeySize);

return new ECParameters
var parameters = new ECParameters
{
Curve = ECCurve.NamedCurves.nistP384,
Q = new ECPoint
Expand All @@ -90,29 +107,29 @@ internal static ECParameters ECCPublicKeyBlobToParams(byte[] keyBlob)
Y = y
},
};

return ECDiffieHellman.Create(parameters);
}

// Serializes an ECDiffieHellmanPublicKey to an ECC public key blob
// "ECDiffieHellmanPublicKey.ToByteArray() doesn't have a (standards-)defined export
// format. The version used by ECDiffieHellmanPublicKeyCng is Windows-specific"
// from https://github.com/dotnet/runtime/issues/27276
// => ECDiffieHellmanPublicKey.ToByteArray() is not supported in Unix
internal static byte[] ECDHPublicKeyToECCKeyBlob(ECDiffieHellmanPublicKey publicKey)
internal static ECDiffieHellman CreateECDiffieHellman(int keySize)
{
byte[] keyBlob = new byte[ECCPublicKeyBlob.Size];
// platform agnostic creates a key of the correct size but does not
// set the key derivation type or algorithm, these must be set by calling
// DeriveKeyFromHash later in DeriveKey
ECDiffieHellman clientDHKey = ECDiffieHellman.Create();
clientDHKey.KeySize = keySize;
return clientDHKey;
}

// Set magic number
Buffer.BlockCopy(KeyBlobMagicNumber.ECDHPublicP384, 0, keyBlob, 0, 4);
// Set key size
keyBlob[4] = (byte)ECCPublicKeyBlob.KeySize;
internal static byte[] DeriveKey(ECDiffieHellman ecd, ECDiffieHellmanPublicKey publicKey)
{
// see notes in CreateECDDiffieHellman
return ecd.DeriveKeyFromHash(publicKey, HashAlgorithmName.SHA256);
}

ECPoint ecPoint = publicKey.ExportParameters().Q;
Debug.Assert(ecPoint.X.Length == ECCPublicKeyBlob.KeySize && ecPoint.Y.Length == ECCPublicKeyBlob.KeySize,
$"ECDH public key was not the expected length. Actual (X): {ecPoint.X.Length}. Actual (Y): {ecPoint.Y.Length} Expected: {ECCPublicKeyBlob.Size}");
// Copy x and y coordinates to key blob
Buffer.BlockCopy(ecPoint.X, 0, keyBlob, ECCPublicKeyBlob.HeaderSize, ECCPublicKeyBlob.KeySize);
Buffer.BlockCopy(ecPoint.Y, 0, keyBlob, ECCPublicKeyBlob.HeaderSize + ECCPublicKeyBlob.KeySize, ECCPublicKeyBlob.KeySize);
return keyBlob;
internal static RSA GetRSAFromCertificate(X509Certificate2 certificate)
{
return certificate.GetRSAPublicKey();
}
}
}

This file was deleted.

This file was deleted.

Loading