Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 774cc01

Browse files
committed
Merge pull request #2231 from bartonjs/rsaSigning
Implement RSA Sign/Verify on Unix
2 parents 9b16041 + 72fa257 commit 774cc01

File tree

7 files changed

+391
-28
lines changed

7 files changed

+391
-28
lines changed

src/Common/src/Interop/Unix/libcrypto/Interop.Rsa.cs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ internal static partial class libcrypto
3636
[DllImport(Libraries.LibCrypto)]
3737
internal static extern int RSA_generate_key_ex(SafeRsaHandle rsa, int bits, SafeBignumHandle e, IntPtr zero);
3838

39+
[DllImport(Libraries.LibCrypto)]
40+
[return: MarshalAs(UnmanagedType.Bool)]
41+
internal static extern bool RSA_sign(int type, byte[] m, int m_len, byte[] sigret, out int siglen, SafeRsaHandle rsa);
42+
43+
[DllImport(Libraries.LibCrypto)]
44+
[return: MarshalAs(UnmanagedType.Bool)]
45+
internal static extern bool RSA_verify(int type, byte[] m, int m_len, byte[] sigbuf, int siglen, SafeRsaHandle rsa);
46+
3947
internal static unsafe RSAParameters ExportRsaParameters(SafeRsaHandle key, bool includePrivateParameters)
4048
{
4149
Debug.Assert(
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Copyright (c) Microsoft. All rights reserved.
2+
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3+
4+
namespace Internal.Cryptography
5+
{
6+
// Temporarily defining HashAlgorithmName here until it comes online officially with the contract refresh.
7+
// (If the contract refresh is happening and this file is causing problems, just delete it)
8+
internal struct HashAlgorithmName
9+
{
10+
public static HashAlgorithmName MD5 { get { return new HashAlgorithmName("MD5"); } }
11+
public static HashAlgorithmName SHA1 { get { return new HashAlgorithmName("SHA1"); } }
12+
public static HashAlgorithmName SHA256 { get { return new HashAlgorithmName("SHA256"); } }
13+
public static HashAlgorithmName SHA384 { get { return new HashAlgorithmName("SHA384"); } }
14+
public static HashAlgorithmName SHA512 { get { return new HashAlgorithmName("SHA512"); } }
15+
16+
private readonly string _name;
17+
18+
public HashAlgorithmName(string name)
19+
{
20+
_name = name;
21+
}
22+
23+
public string Name
24+
{
25+
get { return _name; }
26+
}
27+
28+
public override string ToString()
29+
{
30+
return _name ?? string.Empty;
31+
}
32+
33+
public override bool Equals(object obj)
34+
{
35+
return obj is HashAlgorithmName && Equals((HashAlgorithmName)obj);
36+
}
37+
38+
public bool Equals(HashAlgorithmName other)
39+
{
40+
return _name == other._name;
41+
}
42+
43+
public override int GetHashCode()
44+
{
45+
return _name == null ? 0 : _name.GetHashCode();
46+
}
47+
48+
public static bool operator ==(HashAlgorithmName left, HashAlgorithmName right)
49+
{
50+
return left.Equals(right);
51+
}
52+
53+
public static bool operator !=(HashAlgorithmName left, HashAlgorithmName right)
54+
{
55+
return !(left == right);
56+
}
57+
}
58+
}

src/System.Security.Cryptography.RSA/src/Internal/Cryptography/RsaOpenSsl.cs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
33

44
using System;
5+
using System.Diagnostics;
6+
using System.IO;
57
using System.Security.Cryptography;
68
using System.Threading;
79

@@ -313,5 +315,113 @@ private static Exception CreateOpenSslException()
313315
{
314316
return new CryptographicException(Interop.libcrypto.GetOpenSslErrorString());
315317
}
318+
319+
internal byte[] HashData(byte[] buffer, int offset, int count, HashAlgorithmName hashAlgorithmName)
320+
{
321+
using (HashAlgorithm hasher = GetHashAlgorithm(hashAlgorithmName))
322+
{
323+
return hasher.ComputeHash(buffer, offset, count);
324+
}
325+
}
326+
327+
internal byte[] HashData(Stream stream, HashAlgorithmName hashAlgorithmName)
328+
{
329+
using (HashAlgorithm hasher = GetHashAlgorithm(hashAlgorithmName))
330+
{
331+
return hasher.ComputeHash(stream);
332+
}
333+
}
334+
335+
internal byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithmName)
336+
{
337+
int algorithmNid = GetAlgorithmNid(hashAlgorithmName);
338+
SafeRsaHandle rsa = _key.Value;
339+
byte[] signature = new byte[Interop.libcrypto.RSA_size(rsa)];
340+
int signatureSize;
341+
342+
bool success = Interop.libcrypto.RSA_sign(
343+
algorithmNid,
344+
hash,
345+
hash.Length,
346+
signature,
347+
out signatureSize,
348+
rsa);
349+
350+
if (!success)
351+
{
352+
throw CreateOpenSslException();
353+
}
354+
355+
Debug.Assert(
356+
signatureSize == signature.Length,
357+
"RSA_sign reported an unexpected signature size",
358+
"RSA_sign reported signatureSize was {0}, when {1} was expected",
359+
signatureSize,
360+
signature.Length);
361+
362+
return signature;
363+
}
364+
365+
internal bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithmName)
366+
{
367+
int algorithmNid = GetAlgorithmNid(hashAlgorithmName);
368+
SafeRsaHandle rsa = _key.Value;
369+
370+
return Interop.libcrypto.RSA_verify(
371+
algorithmNid,
372+
hash,
373+
hash.Length,
374+
signature,
375+
signature.Length,
376+
rsa);
377+
}
378+
379+
private static int GetAlgorithmNid(HashAlgorithmName hashAlgorithmName)
380+
{
381+
// All of the current HashAlgorithmName values correspond to the SN values in OpenSSL 0.9.8.
382+
// If there's ever a new one that doesn't, translate it here.
383+
string sn = hashAlgorithmName.Name;
384+
385+
int nid = Interop.libcrypto.OBJ_sn2nid(sn);
386+
387+
if (nid == Interop.libcrypto.NID_undef)
388+
{
389+
throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName.Name);
390+
}
391+
392+
return nid;
393+
}
394+
395+
private static HashAlgorithm GetHashAlgorithm(HashAlgorithmName hashAlgorithmName)
396+
{
397+
HashAlgorithm hasher;
398+
399+
if (hashAlgorithmName == HashAlgorithmName.MD5)
400+
{
401+
hasher = MD5.Create();
402+
}
403+
else if (hashAlgorithmName == HashAlgorithmName.SHA1)
404+
{
405+
hasher = SHA1.Create();
406+
}
407+
else if (hashAlgorithmName == HashAlgorithmName.SHA256)
408+
{
409+
hasher = SHA256.Create();
410+
}
411+
else if (hashAlgorithmName == HashAlgorithmName.SHA384)
412+
{
413+
hasher = SHA384.Create();
414+
}
415+
else if (hashAlgorithmName == HashAlgorithmName.SHA512)
416+
{
417+
hasher = SHA512.Create();
418+
}
419+
else
420+
{
421+
throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithmName.Name);
422+
}
423+
424+
return hasher;
425+
}
316426
}
317427
}

src/System.Security.Cryptography.RSA/src/Resources/Strings.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,4 +216,7 @@
216216
<data name="OpenCSP_Failed" xml:space="preserve">
217217
<value>OpenCSP failed with Error code </value>
218218
</data>
219+
<data name="Cryptography_UnknownHashAlgorithm" xml:space="preserve">
220+
<value>'{0}' is not a known hash algorithm.</value>
221+
</data>
219222
</root>

src/System.Security.Cryptography.RSA/src/System.Security.Cryptography.RSA.csproj

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
<Reference Include="System.Threading" />
3232
</ItemGroup>-->
3333
<ItemGroup>
34+
<Compile Include="Internal\Cryptography\HashAlgorithmName.cs" />
3435
<Compile Include="System\Security\Cryptography\CspProviderFlags.cs" />
3536
<Compile Include="System\Security\Cryptography\ICspAsymmetricAlgorithm.cs" />
3637
<Compile Include="System\Security\Cryptography\KeyNumber.cs" />
@@ -56,6 +57,9 @@
5657
<Compile Include="$(CommonPath)\Interop\Unix\libcoreclr\Interop.EnsureOpenSslInitialized.cs">
5758
<Link>Common\Interop\Unix\libcoreclr\Interop.EnsureOpenSslInitialized.cs</Link>
5859
</Compile>
60+
<Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.ASN1.cs">
61+
<Link>Common\Interop\Unix\libcrypto\Interop.ASN1.cs</Link>
62+
</Compile>
5963
<Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.Bignum.cs">
6064
<Link>Common\Interop\Unix\libcrypto\Interop.Bignum.cs</Link>
6165
</Compile>
@@ -68,6 +72,9 @@
6872
<Compile Include="$(CommonPath)\Interop\Unix\libcrypto\Interop.Rsa.cs">
6973
<Link>Common\Interop\Unix\libcrypto\Interop.Rsa.cs</Link>
7074
</Compile>
75+
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs">
76+
<Link>Common\Microsoft\Win32\SafeHandles\Asn1SafeHandles.Unix.cs</Link>
77+
</Compile>
7178
<Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeBignumHandle.Unix.cs">
7279
<Link>Common\Microsoft\Win32\SafeHandles\SafeBignumHandle.Unix.cs</Link>
7380
</Compile>

0 commit comments

Comments
 (0)