Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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 @@ -31,9 +31,6 @@ internal static partial class NCrypt
[LibraryImport(Interop.Libraries.NCrypt, StringMarshalling = StringMarshalling.Utf16)]
internal static partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, ref byte pbOutput, int cbOutput, out int pcbResult, int dwFlags);

[LibraryImport(Interop.Libraries.NCrypt, StringMarshalling = StringMarshalling.Utf16)]
internal static partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, IntPtr pParameterList, Span<byte> pbOutput, int cbOutput, out int pcbResult, int dwFlags);

[LibraryImport(Interop.Libraries.NCrypt, StringMarshalling = StringMarshalling.Utf16)]
internal static partial ErrorCode NCryptExportKey(SafeNCryptKeyHandle hKey, IntPtr hExportKey, string pszBlobType, ref NCryptBufferDesc pParameterList, ref byte pbOutput, int cbOutput, out int pcbResult, int dwFlags);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,8 +99,7 @@ private static void CopySignatureField(ReadOnlySpan<byte> signatureField, Span<b
}

// If the field is too short then it needs to be prepended
// with zeroes in the response. Since the array was already
// zeroed out, just figure out where we need to start copying.
// with zeroes in the response.
int writeOffset = response.Length - signatureField.Length;
response.Slice(0, writeOffset).Clear();
signatureField.CopyTo(response.Slice(writeOffset));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,17 +153,25 @@ internal static void ExportKeyBlob(
if (errorCode != ErrorCode.ERROR_SUCCESS)
throw errorCode.ToCryptographicException();

byte[] buffer = new byte[numBytesNeeded];
byte[] buffer = CryptoPool.Rent(numBytesNeeded);

using (PinAndClear.Track(buffer))
try
{
errorCode = Interop.NCrypt.NCryptExportKey(handle, IntPtr.Zero, blobType, IntPtr.Zero, buffer, buffer.Length, out numBytesNeeded, 0);
if (errorCode != ErrorCode.ERROR_SUCCESS)
throw errorCode.ToCryptographicException();
using (PinAndClear.Track(buffer))
{
errorCode = Interop.NCrypt.NCryptExportKey(handle, IntPtr.Zero, blobType, IntPtr.Zero, buffer, buffer.Length, out numBytesNeeded, 0);
if (errorCode != ErrorCode.ERROR_SUCCESS)
throw errorCode.ToCryptographicException();

// The second call to NCryptExportKey should always return the same number of bytes as the first call,
// but we will slice the buffer just in case.
callback(buffer.AsSpan(0, numBytesNeeded));
// The second call to NCryptExportKey should always return the same number of bytes as the first call,
// but we will slice the buffer just in case.
callback(buffer.AsSpan(0, numBytesNeeded));
}
}
finally
{
// Already cleared by PinAndClear.Track above
CryptoPool.Return(buffer, clearSize: 0);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ public static unsafe ECDsaComponent ImportPrivateKey(ECDsaAlgorithm algorithm, R
y = zero;
}

ValidateNamedCurve(x, y, d);

return new ECDsaComponent(
ECCng.EncodeEccKeyBlob(
algorithm.PrivateKeyBlobMagicNumber,
Expand Down Expand Up @@ -250,7 +252,10 @@ internal override bool TryExportPrivateKey(Span<byte> destination, out int bytes
throw new CryptographicException();
}

ValidateNamedCurve(x, y, d);

WriteKey(d, x, y, _algorithm.CurveOidValue, writer);
return true;
});
});

Expand Down Expand Up @@ -331,8 +336,11 @@ internal override bool TryExportPublicKey(Span<byte> destination, out int bytesW
throw new CryptographicException();
}

ValidateNamedCurve(localX, localY, null);

x = localX;
y = localY;
return true;
});
});
#endif
Expand Down Expand Up @@ -456,6 +464,25 @@ private static ECDsaCng CreateKey(string curveName)
return new ECDsaCng(key);
}
}

private static void ValidateNamedCurve(byte[]? x, byte[]? y, byte[]? d)
{
bool hasErrors = true;

if (d is not null && y is null && x is null)
{
hasErrors = false;
}
else if (y is not null && x is not null && y.Length == x.Length)
{
hasErrors = (d is not null && (d.Length != x.Length));
}

if (hasErrors)
{
throw new CryptographicException(SR.Cryptography_InvalidCurveKeyParameters);
}
}
#endif
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,19 @@ internal static T EncodeEccKeyBlob<T>(KeyBlobMagicNumber magic, byte[] x, byte[]
// -- Only if "includePrivateParameters" is true --
// byte[cbKey] D

int blobSize = sizeof(BCRYPT_ECCKEY_BLOB) +
x.Length +
y.Length;
if (includePrivateParameters)
Debug.Assert(x.Length == y.Length);

int blobSize;

checked
{
blobSize += d!.Length;
blobSize = sizeof(BCRYPT_ECCKEY_BLOB) +
x.Length +
y.Length;
if (includePrivateParameters)
{
blobSize += d!.Length;
}
}

blob = new byte[blobSize];
Expand All @@ -53,6 +60,7 @@ internal static T EncodeEccKeyBlob<T>(KeyBlobMagicNumber magic, byte[] x, byte[]

if (includePrivateParameters)
{
Debug.Assert(x.Length == d?.Length);
Interop.BCrypt.Emit(blob, ref offset, d!);
}

Expand All @@ -71,10 +79,10 @@ internal static T EncodeEccKeyBlob<T>(KeyBlobMagicNumber magic, byte[] x, byte[]
}
}

internal delegate void DecodeBlobFunc(KeyBlobMagicNumber magic, byte[] x, byte[] y, byte[]? d);
internal delegate T DecodeBlobFunc<T>(KeyBlobMagicNumber magic, byte[] x, byte[] y, byte[]? d);

// When possible, operate on the private key inside the callback since the array will be pinned during its execution.
internal static void DecodeEccKeyBlob(ReadOnlySpan<byte> ecBlob, DecodeBlobFunc decodeCallback, bool clearPrivateKey = true)
internal static T DecodeEccKeyBlob<T>(ReadOnlySpan<byte> ecBlob, DecodeBlobFunc<T> decodeCallback, bool clearPrivateKey = true)
{
// We now have a buffer laid out as follows:
// BCRYPT_ECCKEY_BLOB header
Expand Down Expand Up @@ -112,7 +120,7 @@ internal static void DecodeEccKeyBlob(ReadOnlySpan<byte> ecBlob, DecodeBlobFunc

Debug.Assert(offset == ecBlob.Length);

decodeCallback(magic, x, y, d);
return decodeCallback(magic, x, y, d);
}
finally
{
Expand All @@ -127,7 +135,7 @@ internal static void DecodeEccKeyBlob(ReadOnlySpan<byte> ecBlob, DecodeBlobFunc
{
Debug.Assert(offset == ecBlob.Length);

decodeCallback(magic, x, y, null);
return decodeCallback(magic, x, y, null);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ internal static byte[] GetNamedCurveBlob(ref ECParameters parameters, bool ecdh)
parameters.Q.X!,
parameters.Q.Y!,
parameters.D,
blob => blob,
static blob => blob,
clearBlob: false); // Returning blob to caller, so don't clear it.
}

Expand Down Expand Up @@ -118,27 +118,44 @@ internal static byte[] GetPrimeCurveBlob(ref ECParameters parameters, bool ecdh)

internal static void ExportNamedCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters)
{
ECParameters temp = default;

DecodeEccKeyBlob(
ecBlob,
(KeyBlobMagicNumber magic, byte[] x, byte[] y, byte[]? d) =>
{
CheckMagicValueOfKey(magic, includePrivateParameters);

temp = new ECParameters
if (includePrivateParameters)
{
ecParams = DecodeEccKeyBlob(
ecBlob,
static (KeyBlobMagicNumber magic, byte[] x, byte[] y, byte[]? d) =>
{
Q = new ECPoint
CheckMagicValueOfKey(magic, includePrivateParameters: true);

return new ECParameters
{
X = x,
Y = y,
},
D = d,
};
},
clearPrivateKey: false); // Returning key to caller, so don't clear it.
Q = new ECPoint
{
X = x,
Y = y,
},
D = d,
};
},
clearPrivateKey: false); // Returning key to caller, so don't clear it.
}
else
{
ecParams = DecodeEccKeyBlob(
ecBlob,
static (KeyBlobMagicNumber magic, byte[] x, byte[] y, byte[]? d) =>
{
CheckMagicValueOfKey(magic, includePrivateParameters: false);

ecParams = temp;
return new ECParameters
{
Q = new ECPoint
{
X = x,
Y = y,
},
};
});
}
}

internal static void ExportPrimeCurveParameters(ref ECParameters ecParams, byte[] ecBlob, bool includePrivateParameters)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@
<data name="Cryptography_IncorrectTagLength" xml:space="preserve">
<value>The size of the specified tag does not match the expected size of {0}.</value>
</data>
<data name="Cryptography_InvalidCurveKeyParameters" xml:space="preserve">
<value>The specified key parameters are not valid. Q.X and Q.Y, or D, must be specified. Q.X, Q.Y must be the same length. If D is specified it must be the same length as Q.X and Q.Y if also specified for named curves or the same length as Order for explicit curves.</value>
</data>
<data name="Cryptography_InvalidKeySize" xml:space="preserve">
<value>Specified key is not a valid size for this algorithm.</value>
</data>
Expand Down
Loading