-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[AndroidCrypto] Implement DSA import/export and signing/verification. (…
…#49153) Co-authored-by: Jeremy Barton <[email protected]>
- Loading branch information
1 parent
50494e0
commit 17799a5
Showing
16 changed files
with
1,211 additions
and
199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
184 changes: 184 additions & 0 deletions
184
...ies/Common/src/Interop/Android/System.Security.Cryptography.Native.Android/Interop.Dsa.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,184 @@ | ||
// Licensed to the .NET Foundation under one or more agreements. | ||
// The .NET Foundation licenses this file to you under the MIT license. | ||
|
||
using System; | ||
using System.Diagnostics; | ||
using System.Runtime.InteropServices; | ||
using System.Security.Cryptography; | ||
using Microsoft.Win32.SafeHandles; | ||
|
||
internal static partial class Interop | ||
{ | ||
internal static partial class AndroidCrypto | ||
{ | ||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaGenerateKey")] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
internal static extern bool DsaGenerateKey(out SafeDsaHandle dsa, int bits); | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaSizeSignature")] | ||
private static extern int DsaSizeSignature(SafeDsaHandle dsa); | ||
|
||
/// <summary> | ||
/// Return the maximum size of the DER-encoded key in bytes. | ||
/// </summary> | ||
internal static int DsaEncodedSignatureSize(SafeDsaHandle dsa) | ||
{ | ||
int size = DsaSizeSignature(dsa); | ||
return size; | ||
} | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaSignatureFieldSize")] | ||
private static extern int AndroidCryptoNative_DsaSignatureFieldSize(SafeDsaHandle dsa); | ||
|
||
/// <summary> | ||
/// Return the size of the 'r' or 's' signature fields in bytes. | ||
/// </summary> | ||
internal static int DsaSignatureFieldSize(SafeDsaHandle dsa) | ||
{ | ||
// Add another byte for the leading zero byte. | ||
int size = AndroidCryptoNative_DsaSignatureFieldSize(dsa); | ||
Debug.Assert(size * 2 < DsaEncodedSignatureSize(dsa)); | ||
return size; | ||
} | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaSizeP")] | ||
private static extern int DsaSizeP(SafeDsaHandle dsa); | ||
|
||
/// <summary> | ||
/// Return the size of the key in bytes. | ||
/// </summary> | ||
internal static int DsaKeySize(SafeDsaHandle dsa) | ||
{ | ||
int keySize = DsaSizeP(dsa); | ||
|
||
// Assume an even multiple of 8 bytes \ 64 bits | ||
keySize = (keySize + 7) / 8 * 8; | ||
return keySize; | ||
} | ||
|
||
internal static bool DsaSign(SafeDsaHandle dsa, ReadOnlySpan<byte> hash, Span<byte> refSignature, out int outSignatureLength) => | ||
DsaSign(dsa, ref MemoryMarshal.GetReference(hash), hash.Length, ref MemoryMarshal.GetReference(refSignature), out outSignatureLength); | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaSign")] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
private static extern bool DsaSign(SafeDsaHandle dsa, ref byte hash, int hashLength, ref byte refSignature, out int outSignatureLength); | ||
|
||
internal static bool DsaVerify(SafeDsaHandle dsa, ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature) | ||
{ | ||
int ret = DsaVerify( | ||
dsa, | ||
ref MemoryMarshal.GetReference(hash), | ||
hash.Length, | ||
ref MemoryMarshal.GetReference(signature), | ||
signature.Length); | ||
|
||
if (ret == -1) | ||
{ | ||
throw new CryptographicException(); | ||
} | ||
|
||
return ret == 1; | ||
} | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaVerify")] | ||
private static extern int DsaVerify(SafeDsaHandle dsa, ref byte hash, int hashLength, ref byte signature, int signatureLength); | ||
|
||
internal static DSAParameters ExportDsaParameters(SafeDsaHandle key, bool includePrivateParameters) | ||
{ | ||
Debug.Assert( | ||
key != null && !key.IsInvalid, | ||
"Callers should check the key is invalid and throw an exception with a message"); | ||
|
||
if (key == null || key.IsInvalid) | ||
{ | ||
throw new CryptographicException(); | ||
} | ||
|
||
SafeBignumHandle p_bn, q_bn, g_bn, y_bn, x_bn; | ||
int p_cb, q_cb, g_cb, y_cb, x_cb; | ||
|
||
if (!GetDsaParameters(key, | ||
out p_bn, out p_cb, | ||
out q_bn, out q_cb, | ||
out g_bn, out g_cb, | ||
out y_bn, out y_cb, | ||
out x_bn, out x_cb)) | ||
{ | ||
p_bn.Dispose(); | ||
q_bn.Dispose(); | ||
g_bn.Dispose(); | ||
y_bn.Dispose(); | ||
x_bn.Dispose(); | ||
throw new CryptographicException(); | ||
} | ||
|
||
using (p_bn) | ||
using (q_bn) | ||
using (g_bn) | ||
using (y_bn) | ||
using (x_bn) | ||
{ | ||
// Match Windows semantics where p, g and y have same length | ||
int pgy_cb = GetMax(p_cb, g_cb, y_cb); | ||
|
||
// Match Windows semantics where q and x have same length | ||
int qx_cb = GetMax(q_cb, x_cb); | ||
|
||
DSAParameters dsaParameters = new DSAParameters | ||
{ | ||
P = Crypto.ExtractBignum(p_bn, pgy_cb)!, | ||
Q = Crypto.ExtractBignum(q_bn, qx_cb)!, | ||
G = Crypto.ExtractBignum(g_bn, pgy_cb)!, | ||
Y = Crypto.ExtractBignum(y_bn, pgy_cb)!, | ||
}; | ||
|
||
if (includePrivateParameters) | ||
{ | ||
dsaParameters.X = Crypto.ExtractBignum(x_bn, qx_cb); | ||
} | ||
|
||
return dsaParameters; | ||
} | ||
} | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_GetDsaParameters")] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
private static extern bool GetDsaParameters( | ||
SafeDsaHandle key, | ||
out SafeBignumHandle p, out int p_cb, | ||
out SafeBignumHandle q, out int q_cb, | ||
out SafeBignumHandle g, out int g_cb, | ||
out SafeBignumHandle y, out int y_cb, | ||
out SafeBignumHandle x, out int x_cb); | ||
|
||
[DllImport(Libraries.CryptoNative, EntryPoint = "AndroidCryptoNative_DsaKeyCreateByExplicitParameters")] | ||
[return: MarshalAs(UnmanagedType.Bool)] | ||
internal static extern bool DsaKeyCreateByExplicitParameters( | ||
out SafeDsaHandle dsa, | ||
byte[] p, | ||
int pLength, | ||
byte[] q, | ||
int qLength, | ||
byte[] g, | ||
int gLength, | ||
byte[] y, | ||
int yLength, | ||
byte[]? x, | ||
int xLength); | ||
} | ||
} | ||
|
||
namespace System.Security.Cryptography | ||
{ | ||
internal sealed class SafeDsaHandle : Interop.JObjectLifetime.SafeJObjectHandle | ||
{ | ||
public SafeDsaHandle() | ||
{ | ||
} | ||
|
||
internal SafeDsaHandle(IntPtr ptr) | ||
: base(ptr) | ||
{ | ||
} | ||
} | ||
} |
Oops, something went wrong.