1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
4 using Internal.Cryptography;
6 using System.Runtime.Versioning;
8 namespace System.Security.Cryptography
10 public sealed partial class RSACryptoServiceProvider : RSA, ICspAsymmetricAlgorithm, IRuntimeAlgorithm
12 private const int DefaultKeySize = 1024;
14 private readonly RSA _impl;
15 private bool _publicOnly;
17 [UnsupportedOSPlatform("browser")]
18 public RSACryptoServiceProvider()
19 : this(DefaultKeySize) { }
21 [UnsupportedOSPlatform("browser")]
22 public RSACryptoServiceProvider(int dwKeySize)
24 ArgumentOutOfRangeException.ThrowIfNegative(dwKeySize);
26 // This class wraps RSA
27 _impl = RSA.Create(dwKeySize);
30 [SupportedOSPlatform("windows")]
31 public RSACryptoServiceProvider(int dwKeySize, CspParameters parameters) =>
32 throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CAPI_Required, nameof(CspParameters)));
34 [SupportedOSPlatform("windows")]
35 public RSACryptoServiceProvider(CspParameters parameters) =>
36 throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CAPI_Required, nameof(CspParameters)));
38 [SupportedOSPlatform("windows")]
39 public CspKeyContainerInfo CspKeyContainerInfo =>
40 throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CAPI_Required, nameof(CspKeyContainerInfo)));
42 public byte[] Decrypt(byte[] rgb, bool fOAEP)
44 ArgumentNullException.ThrowIfNull(rgb);
46 // size check -- must be exactly the modulus size
47 if (rgb.Length != (KeySize / 8))
48 throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize);
50 return _impl.Decrypt(rgb, fOAEP ? RSAEncryptionPadding.OaepSHA1 : RSAEncryptionPadding.Pkcs1);
53 public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding)
55 ArgumentNullException.ThrowIfNull(data);
56 ArgumentNullException.ThrowIfNull(padding);
59 padding == RSAEncryptionPadding.Pkcs1 ? Decrypt(data, fOAEP: false) :
60 padding == RSAEncryptionPadding.OaepSHA1 ? Decrypt(data, fOAEP: true) : // For compat, this prevents OaepSHA2 options as fOAEP==true will cause Decrypt to use OaepSHA1
61 throw PaddingModeNotSupported();
64 public override bool TryDecrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
66 ArgumentNullException.ThrowIfNull(padding);
68 if (data.Length != (KeySize / 8))
69 throw new CryptographicException(SR.Cryptography_RSA_DecryptWrongSize);
70 if (padding != RSAEncryptionPadding.Pkcs1 && padding != RSAEncryptionPadding.OaepSHA1)
71 throw PaddingModeNotSupported();
73 return _impl.TryDecrypt(data, destination, padding, out bytesWritten);
76 protected override void Dispose(bool disposing)
81 base.Dispose(disposing);
85 public byte[] Encrypt(byte[] rgb, bool fOAEP)
87 ArgumentNullException.ThrowIfNull(rgb);
89 return _impl.Encrypt(rgb, fOAEP ? RSAEncryptionPadding.OaepSHA1 : RSAEncryptionPadding.Pkcs1);
92 public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding)
94 ArgumentNullException.ThrowIfNull(data);
95 ArgumentNullException.ThrowIfNull(padding);
98 padding == RSAEncryptionPadding.Pkcs1 ? Encrypt(data, fOAEP: false) :
99 padding == RSAEncryptionPadding.OaepSHA1 ? Encrypt(data, fOAEP: true) : // For compat, this prevents OaepSHA2 options as fOAEP==true will cause Decrypt to use OaepSHA1
100 throw PaddingModeNotSupported();
103 public override bool TryEncrypt(ReadOnlySpan<byte> data, Span<byte> destination, RSAEncryptionPadding padding, out int bytesWritten)
105 ArgumentNullException.ThrowIfNull(padding);
107 if (padding != RSAEncryptionPadding.Pkcs1 && padding != RSAEncryptionPadding.OaepSHA1)
108 throw PaddingModeNotSupported();
110 return _impl.TryEncrypt(data, destination, padding, out bytesWritten);
113 public byte[] ExportCspBlob(bool includePrivateParameters)
115 RSAParameters parameters = ExportParameters(includePrivateParameters);
116 return parameters.ToKeyBlob();
119 public override RSAParameters ExportParameters(bool includePrivateParameters) =>
120 _impl.ExportParameters(includePrivateParameters);
122 public override void FromXmlString(string xmlString) => _impl.FromXmlString(xmlString);
124 public void ImportCspBlob(byte[] keyBlob)
126 RSAParameters parameters = CapiHelper.ToRSAParameters(keyBlob, !IsPublic(keyBlob));
127 ImportParameters(parameters);
130 public override void ImportParameters(RSAParameters parameters)
132 // Although _impl supports larger Exponent, limit here for compat.
133 if (parameters.Exponent == null || parameters.Exponent.Length > 4)
134 throw new CryptographicException(SR.Argument_InvalidValue);
136 _impl.ImportParameters(parameters);
138 // P was verified in ImportParameters
139 _publicOnly = (parameters.P == null || parameters.P.Length == 0);
142 public override void ImportEncryptedPkcs8PrivateKey(
143 ReadOnlySpan<byte> passwordBytes,
144 ReadOnlySpan<byte> source,
147 _impl.ImportEncryptedPkcs8PrivateKey(passwordBytes, source, out bytesRead);
150 public override void ImportEncryptedPkcs8PrivateKey(
151 ReadOnlySpan<char> password,
152 ReadOnlySpan<byte> source,
155 _impl.ImportEncryptedPkcs8PrivateKey(password, source, out bytesRead);
158 public override string? KeyExchangeAlgorithm => _impl.KeyExchangeAlgorithm;
160 public override int KeySize
162 get { return _impl.KeySize; }
163 set { _impl.KeySize = value; }
166 // RSAOpenSsl is (512, 16384, 8), RSASecurityTransforms is (1024, 16384, 8)
167 // Either way the minimum is lifted off of CAPI's 384, due to platform constraints.
168 public override KeySizes[] LegalKeySizes => _impl.LegalKeySizes;
170 // PersistKeyInCsp has no effect in Unix
171 public bool PersistKeyInCsp { get; set; }
173 public bool PublicOnly => _publicOnly;
175 public override string SignatureAlgorithm => "http://www.w3.org/2000/09/xmldsig#rsa-sha1";
177 public override byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
179 ArgumentNullException.ThrowIfNull(padding);
181 if (padding != RSASignaturePadding.Pkcs1)
183 throw PaddingModeNotSupported();
186 return _impl.SignData(data, hashAlgorithm, padding);
189 public override byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
191 ArgumentNullException.ThrowIfNull(padding);
193 if (padding != RSASignaturePadding.Pkcs1)
195 throw PaddingModeNotSupported();
198 return _impl.SignData(data, offset, count, hashAlgorithm, padding);
201 public override bool TrySignData(ReadOnlySpan<byte> data, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
203 ArgumentNullException.ThrowIfNull(padding);
205 if (padding != RSASignaturePadding.Pkcs1)
207 throw PaddingModeNotSupported();
210 return _impl.TrySignData(data, destination, hashAlgorithm, padding, out bytesWritten);
213 public byte[] SignData(byte[] buffer, int offset, int count, object halg) =>
214 _impl.SignData(buffer, offset, count, CapiHelper.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
216 public byte[] SignData(byte[] buffer, object halg) =>
217 _impl.SignData(buffer, CapiHelper.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
219 public byte[] SignData(Stream inputStream, object halg) =>
220 _impl.SignData(inputStream, CapiHelper.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
222 public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
224 ArgumentNullException.ThrowIfNull(padding);
226 if (padding != RSASignaturePadding.Pkcs1)
228 throw PaddingModeNotSupported();
231 return _impl.SignHash(hash, hashAlgorithm, padding);
234 public override bool TrySignHash(ReadOnlySpan<byte> hash, Span<byte> destination, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding, out int bytesWritten)
236 ArgumentNullException.ThrowIfNull(padding);
238 if (padding != RSASignaturePadding.Pkcs1)
240 throw PaddingModeNotSupported();
243 return _impl.TrySignHash(hash, destination, hashAlgorithm, padding, out bytesWritten);
246 public byte[] SignHash(byte[] rgbHash, string str)
248 ArgumentNullException.ThrowIfNull(rgbHash);
251 throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
253 HashAlgorithmName algName = CapiHelper.NameOrOidToHashAlgorithmName(str);
254 return _impl.SignHash(rgbHash, algName, RSASignaturePadding.Pkcs1);
257 public override string ToXmlString(bool includePrivateParameters) => _impl.ToXmlString(includePrivateParameters);
259 public bool VerifyData(byte[] buffer, object halg, byte[] signature) =>
260 _impl.VerifyData(buffer, signature, CapiHelper.ObjToHashAlgorithmName(halg), RSASignaturePadding.Pkcs1);
262 public override bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
264 ArgumentNullException.ThrowIfNull(padding);
266 if (padding != RSASignaturePadding.Pkcs1)
268 throw PaddingModeNotSupported();
271 return _impl.VerifyData(data, offset, count, signature, hashAlgorithm, padding);
274 public override bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
276 ArgumentNullException.ThrowIfNull(padding);
278 if (padding != RSASignaturePadding.Pkcs1)
280 throw PaddingModeNotSupported();
283 return _impl.VerifyData(data, signature, hashAlgorithm, padding);
286 public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
288 ArgumentNullException.ThrowIfNull(hash);
289 ArgumentNullException.ThrowIfNull(signature);
291 return VerifyHash((ReadOnlySpan<byte>)hash, (ReadOnlySpan<byte>)signature, hashAlgorithm, padding);
294 public override bool VerifyHash(ReadOnlySpan<byte> hash, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding)
296 ArgumentNullException.ThrowIfNull(padding);
298 if (padding != RSASignaturePadding.Pkcs1)
300 throw PaddingModeNotSupported();
303 return _impl.VerifyHash(hash, signature, hashAlgorithm, padding);
306 public bool VerifyHash(byte[] rgbHash, string str, byte[] rgbSignature)
308 ArgumentNullException.ThrowIfNull(rgbHash);
309 ArgumentNullException.ThrowIfNull(rgbSignature);
312 (ReadOnlySpan<byte>)rgbHash, (ReadOnlySpan<byte>)rgbSignature,
313 CapiHelper.NameOrOidToHashAlgorithmName(str), RSASignaturePadding.Pkcs1);
316 // UseMachineKeyStore has no effect in Unix
317 public static bool UseMachineKeyStore { get; set; }
319 private static Exception PaddingModeNotSupported()
321 return new CryptographicException(SR.Cryptography_InvalidPaddingMode);
325 /// find whether an RSA key blob is public.
327 private static bool IsPublic(byte[] keyBlob)
329 ArgumentNullException.ThrowIfNull(keyBlob);
331 // The CAPI RSA public key representation consists of the following sequence:
335 // The first should be PUBLICKEYBLOB and magic should be RSA_PUB_MAGIC "RSA1"
336 if (keyBlob[0] != CapiHelper.PUBLICKEYBLOB)
341 if (keyBlob[11] != 0x31 || keyBlob[10] != 0x41 || keyBlob[9] != 0x53 || keyBlob[8] != 0x52)