Skip to content

Commit

Permalink
Sync Crypto api usage (#1022)
Browse files Browse the repository at this point in the history
  • Loading branch information
Wraith2 authored Apr 28, 2021
1 parent 9b4cf94 commit 37f7fbd
Show file tree
Hide file tree
Showing 21 changed files with 275 additions and 1,381 deletions.
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

0 comments on commit 37f7fbd

Please sign in to comment.