• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

jstedfast / MimeKit / 4.12.0.1618

30 Apr 2025 11:13PM UTC coverage: 94.77% (-0.07%) from 94.835%
4.12.0.1618

push

coveralls.net

jstedfast
Fixed up xml doc formatting

32163 of 33938 relevant lines covered (94.77%)

0.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.9
/MimeKit/Cryptography/AsymmetricAlgorithmExtensions.cs
1
//
2
// AsymmetricAlgorithmExtensions.cs
3
//
4
// Author: Jeffrey Stedfast <jestedfa@microsoft.com>
5
//
6
// Copyright (c) 2013-2025 .NET Foundation and Contributors
7
//
8
// Permission is hereby granted, free of charge, to any person obtaining a copy
9
// of this software and associated documentation files (the "Software"), to deal
10
// in the Software without restriction, including without limitation the rights
11
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12
// copies of the Software, and to permit persons to whom the Software is
13
// furnished to do so, subject to the following conditions:
14
//
15
// The above copyright notice and this permission notice shall be included in
16
// all copies or substantial portions of the Software.
17
//
18
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
24
// THE SOFTWARE.
25
//
26

27
using System;
28
using System.Security.Cryptography;
29

30
using Org.BouncyCastle.Math;
31
using Org.BouncyCastle.Crypto;
32
using Org.BouncyCastle.Crypto.Parameters;
33

34
namespace MimeKit.Cryptography {
35
        /// <summary>
36
        /// Extension methods for System.Security.Cryptography.AsymmetricAlgorithm.
37
        /// </summary>
38
        /// <remarks>
39
        /// Extension methods for System.Security.Cryptography.AsymmetricAlgorithm.
40
        /// </remarks>
41
        public static class AsymmetricAlgorithmExtensions
42
        {
43
                const int MinDsaKeySize = 2048;
44
                const int MinRsaKeySize = 2048;
45

46
                static void GetAsymmetricKeyParameters (DSA dsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key)
47
                {
1✔
48
                        var dp = dsa.ExportParameters (!publicOnly);
1✔
49
                        var validationParameters = dp.Seed != null ? new DsaValidationParameters (dp.Seed, dp.Counter) : null;
1✔
50
                        var parameters = new DsaParameters (
1✔
51
                                new BigInteger (1, dp.P),
52
                                new BigInteger (1, dp.Q),
53
                                new BigInteger (1, dp.G),
54
                                validationParameters);
55

56
                        pub = new DsaPublicKeyParameters (new BigInteger (1, dp.Y), parameters);
1✔
57
                        key = publicOnly ? null : new DsaPrivateKeyParameters (new BigInteger (1, dp.X), parameters);
1✔
58
                }
1✔
59

60
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (DSACryptoServiceProvider dsa)
61
                {
1✔
62
                        GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out var pub, out var key);
1✔
63

64
                        return dsa.PublicOnly ? pub : key;
1✔
65
                }
1✔
66

67
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (DSACryptoServiceProvider dsa)
68
                {
×
69
                        if (dsa.PublicOnly)
×
70
                                throw new ArgumentException ("DSA key is not a private key.", "key");
×
71

72
                        GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out var pub, out var key);
×
73

74
                        return new AsymmetricCipherKeyPair (pub, key);
×
75
                }
×
76

77
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (DSA dsa)
78
                {
1✔
79
                        GetAsymmetricKeyParameters (dsa, false, out _, out var key);
1✔
80

81
                        return key;
1✔
82
                }
1✔
83

84
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (DSA dsa)
85
                {
×
86
                        GetAsymmetricKeyParameters (dsa, false, out var pub, out var key);
×
87

88
                        return new AsymmetricCipherKeyPair (pub, key);
×
89
                }
×
90

91
                static void GetAsymmetricKeyParameters (RSA rsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key)
92
                {
1✔
93
                        var rp = rsa.ExportParameters (!publicOnly);
1✔
94
                        var modulus = new BigInteger (1, rp.Modulus);
1✔
95
                        var exponent = new BigInteger (1, rp.Exponent);
1✔
96

97
                        pub = new RsaKeyParameters (false, modulus, exponent);
1✔
98
                        key = publicOnly ? null : new RsaPrivateCrtKeyParameters (
1✔
99
                                modulus,
100
                                exponent,
101
                                new BigInteger (1, rp.D),
102
                                new BigInteger (1, rp.P),
103
                                new BigInteger (1, rp.Q),
104
                                new BigInteger (1, rp.DP),
105
                                new BigInteger (1, rp.DQ),
106
                                new BigInteger (1, rp.InverseQ)
107
                        );
108
                }
1✔
109

110
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (RSACryptoServiceProvider rsa)
111
                {
1✔
112
                        GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out var pub, out var key);
1✔
113

114
                        return rsa.PublicOnly ? pub : key;
1✔
115
                }
1✔
116

117
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (RSACryptoServiceProvider rsa)
118
                {
1✔
119
                        if (rsa.PublicOnly)
1✔
120
                                throw new ArgumentException ("RSA key is not a private key.", "key");
×
121

122
                        GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out var pub, out var key);
1✔
123

124
                        return new AsymmetricCipherKeyPair (pub, key);
1✔
125
                }
1✔
126

127
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (RSA rsa)
128
                {
1✔
129
                        GetAsymmetricKeyParameters (rsa, false, out _, out var key);
1✔
130

131
                        return key;
1✔
132
                }
1✔
133

134
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (RSA rsa)
135
                {
1✔
136
                        GetAsymmetricKeyParameters (rsa, false, out var pub, out var key);
1✔
137

138
                        return new AsymmetricCipherKeyPair (pub, key);
1✔
139
                }
1✔
140

141
                /// <summary>
142
                /// Convert an AsymmetricAlgorithm into a BouncyCastle AsymmetricKeyParameter.
143
                /// </summary>
144
                /// <remarks>
145
                /// <para>Converts an AsymmetricAlgorithm into a BouncyCastle AsymmetricKeyParameter.</para>
146
                /// <note type="note">Currently, only RSA and DSA keys are supported.</note>
147
                /// </remarks>
148
                /// <returns>The Bouncy Castle AsymmetricKeyParameter.</returns>
149
                /// <param name="key">The key.</param>
150
                /// <exception cref="System.ArgumentNullException">
151
                /// <paramref name="key"/> is <see langword="null"/>.
152
                /// </exception>
153
                /// <exception cref="System.NotSupportedException">
154
                /// <paramref name="key"/> is an unsupported asymmetric algorithm.
155
                /// </exception>
156
                public static AsymmetricKeyParameter AsAsymmetricKeyParameter (this AsymmetricAlgorithm key)
157
                {
1✔
158
                        if (key == null)
1✔
159
                                throw new ArgumentNullException (nameof (key));
1✔
160

161
                        if (key is RSACryptoServiceProvider rsaKey)
1✔
162
                                return GetAsymmetricKeyParameter (rsaKey);
1✔
163

164
                        if (key is RSA rsa)
1✔
165
                                return GetAsymmetricKeyParameter (rsa);
1✔
166

167
                        if (key is DSACryptoServiceProvider dsaKey)
1✔
168
                                return GetAsymmetricKeyParameter (dsaKey);
1✔
169

170
                        if (key is DSA dsa)
1✔
171
                                return GetAsymmetricKeyParameter (dsa);
1✔
172

173
                        // TODO: support ECDiffieHellman and ECDsa?
174

175
                        throw new NotSupportedException (string.Format ("'{0}' is currently not supported.", key.GetType ().Name));
×
176
                }
1✔
177

178
                /// <summary>
179
                /// Convert an AsymmetricAlgorithm into a BouncyCastle AsymmetricCipherKeyPair.
180
                /// </summary>
181
                /// <remarks>
182
                /// <para>Converts an AsymmetricAlgorithm into a BouncyCastle AsymmetricCipherKeyPair.</para>
183
                /// <note type="note">Currently, only RSA and DSA keys are supported.</note>
184
                /// </remarks>
185
                /// <returns>The Bouncy Castle AsymmetricCipherKeyPair.</returns>
186
                /// <param name="key">The key.</param>
187
                /// <exception cref="System.ArgumentNullException">
188
                /// <paramref name="key"/> is <see langword="null"/>.
189
                /// </exception>
190
                /// <exception cref="System.ArgumentException">
191
                /// <paramref name="key"/> is a public key.
192
                /// </exception>
193
                /// <exception cref="System.NotSupportedException">
194
                /// <paramref name="key"/> is an unsupported asymmetric algorithm.
195
                /// </exception>
196
                public static AsymmetricCipherKeyPair AsAsymmetricCipherKeyPair (this AsymmetricAlgorithm key)
197
                {
1✔
198
                        if (key == null)
1✔
199
                                throw new ArgumentNullException (nameof (key));
1✔
200

201
                        if (key is RSACryptoServiceProvider rsaKey)
1✔
202
                                return GetAsymmetricCipherKeyPair (rsaKey);
1✔
203

204
                        if (key is RSA rsa)
1✔
205
                                return GetAsymmetricCipherKeyPair (rsa);
1✔
206

207
                        if (key is DSACryptoServiceProvider dsaKey)
×
208
                                return GetAsymmetricCipherKeyPair (dsaKey);
×
209

210
                        if (key is DSA dsa)
×
211
                                return GetAsymmetricCipherKeyPair (dsa);
×
212

213
                        // TODO: support ECDiffieHellman and ECDsa?
214

215
                        throw new NotSupportedException (string.Format ("'{0}' is currently not supported.", key.GetType ().Name));
×
216
                }
1✔
217

218
                static byte[] GetPaddedByteArray (BigInteger big, int length)
219
                {
1✔
220
                        var bytes = big.ToByteArrayUnsigned ();
1✔
221

222
                        if (bytes.Length >= length)
1✔
223
                                return bytes;
1✔
224

225
                        var padded = new byte[length];
×
226

227
                        Buffer.BlockCopy (bytes, 0, padded, length - bytes.Length, bytes.Length);
×
228

229
                        return padded;
×
230
                }
1✔
231

232
                static DSAParameters GetDSAParameters (DsaKeyParameters key)
233
                {
1✔
234
                        var parameters = new DSAParameters ();
1✔
235

236
                        if (key.Parameters.ValidationParameters != null) {
×
237
                                parameters.Counter = key.Parameters.ValidationParameters.Counter;
×
238
                                parameters.Seed = key.Parameters.ValidationParameters.GetSeed ();
×
239
                        }
×
240

241
                        parameters.P = key.Parameters.P.ToByteArrayUnsigned ();
1✔
242
                        parameters.Q = key.Parameters.Q.ToByteArrayUnsigned ();
1✔
243
                        parameters.G = GetPaddedByteArray (key.Parameters.G, parameters.P.Length);
1✔
244

245
                        return parameters;
1✔
246
                }
1✔
247

248
                static AsymmetricAlgorithm GetAsymmetricAlgorithm (DsaPrivateKeyParameters key, DsaPublicKeyParameters pub)
249
                {
1✔
250
                        var parameters = GetDSAParameters (key);
1✔
251
                        parameters.X = GetPaddedByteArray (key.X, parameters.Q.Length);
1✔
252

253
                        if (pub != null) {
×
254
                                parameters.Y = GetPaddedByteArray (pub.Y, parameters.P.Length);
×
255
                        } else {
1✔
256
                                // If pub is null, derive Y from the private key parameters
257
                                parameters.Y = key.Parameters.G.ModPow (key.X, key.Parameters.P).ToByteArrayUnsigned ();
1✔
258
                        }
1✔
259

260
                        var dsa = new DSACryptoServiceProvider (MinDsaKeySize);
1✔
261

262
                        dsa.ImportParameters (parameters);
1✔
263

264
                        return dsa;
×
265
                }
×
266

267
                static AsymmetricAlgorithm GetAsymmetricAlgorithm (DsaPublicKeyParameters key)
268
                {
×
269
                        var parameters = GetDSAParameters (key);
×
270
                        parameters.Y = GetPaddedByteArray (key.Y, parameters.P.Length);
×
271

272
                        var dsa = new DSACryptoServiceProvider (MinDsaKeySize);
×
273

274
                        dsa.ImportParameters (parameters);
×
275

276
                        return dsa;
×
277
                }
×
278

279
                static AsymmetricAlgorithm GetAsymmetricAlgorithm (RsaPrivateCrtKeyParameters key)
280
                {
1✔
281
                        var parameters = new RSAParameters {
1✔
282
                                Exponent = key.PublicExponent.ToByteArrayUnsigned (),
283
                                Modulus = key.Modulus.ToByteArrayUnsigned (),
284
                                P = key.P.ToByteArrayUnsigned (),
285
                                Q = key.Q.ToByteArrayUnsigned ()
286
                        };
287

288
                        parameters.InverseQ = GetPaddedByteArray (key.QInv, parameters.Q.Length);
1✔
289
                        parameters.D = GetPaddedByteArray (key.Exponent, parameters.Modulus.Length);
1✔
290
                        parameters.DP = GetPaddedByteArray (key.DP, parameters.P.Length);
1✔
291
                        parameters.DQ = GetPaddedByteArray (key.DQ, parameters.Q.Length);
1✔
292

293
                        var rsa = new RSACryptoServiceProvider (MinRsaKeySize);
1✔
294

295
                        rsa.ImportParameters (parameters);
1✔
296

297
                        return rsa;
1✔
298
                }
1✔
299

300
                static AsymmetricAlgorithm GetAsymmetricAlgorithm (RsaKeyParameters key)
301
                {
1✔
302
                        var parameters = new RSAParameters {
1✔
303
                                Exponent = key.Exponent.ToByteArrayUnsigned (),
304
                                Modulus = key.Modulus.ToByteArrayUnsigned ()
305
                        };
306

307
                        var rsa = new RSACryptoServiceProvider (MinRsaKeySize);
1✔
308

309
                        rsa.ImportParameters (parameters);
1✔
310

311
                        return rsa;
1✔
312
                }
1✔
313

314
                /// <summary>
315
                /// Convert a BouncyCastle AsymmetricKeyParameter into an AsymmetricAlgorithm.
316
                /// </summary>
317
                /// <remarks>
318
                /// <para>Converts a BouncyCastle AsymmetricKeyParameter into an AsymmetricAlgorithm.</para>
319
                /// <note type="note">Currently, only RSA and DSA keys are supported.</note>
320
                /// </remarks>
321
                /// <returns>The AsymmetricAlgorithm.</returns>
322
                /// <param name="key">The AsymmetricKeyParameter.</param>
323
                /// <exception cref="System.ArgumentNullException">
324
                /// <paramref name="key"/> is <see langword="null"/>.
325
                /// </exception>
326
                /// <exception cref="System.NotSupportedException">
327
                /// <paramref name="key"/> is an unsupported asymmetric key parameter.
328
                /// </exception>
329
                public static AsymmetricAlgorithm AsAsymmetricAlgorithm (this AsymmetricKeyParameter key)
330
                {
1✔
331
                        // TODO: Drop this API - it's no longer needed. The WindowsSecureMimeContext now exports the certificate & key into a pkcs12 and then loads that into an X509Certificate2.
332
                        if (key == null)
1✔
333
                                throw new ArgumentNullException (nameof (key));
1✔
334

335
                        if (key.IsPrivate) {
1✔
336
                                if (key is RsaPrivateCrtKeyParameters rsaPrivateKey)
1✔
337
                                        return GetAsymmetricAlgorithm (rsaPrivateKey);
1✔
338

339
                                if (key is DsaPrivateKeyParameters dsaPrivateKey)
1✔
340
                                        return GetAsymmetricAlgorithm (dsaPrivateKey, null);
1✔
341
                        } else {
1✔
342
                                if (key is RsaKeyParameters rsaPublicKey)
1✔
343
                                        return GetAsymmetricAlgorithm (rsaPublicKey);
1✔
344

345
                                if (key is DsaPublicKeyParameters dsaPublicKey)
×
346
                                        return GetAsymmetricAlgorithm (dsaPublicKey);
×
347
                        }
×
348

349
                        throw new NotSupportedException (string.Format ("{0} is currently not supported.", key.GetType ().Name));
×
350
                }
1✔
351

352
                /// <summary>
353
                /// Convert a BouncyCastle AsymmetricCipherKeyPair into an AsymmetricAlgorithm.
354
                /// </summary>
355
                /// <remarks>
356
                /// <para>Converts a BouncyCastle AsymmetricCipherKeyPair into an AsymmetricAlgorithm.</para>
357
                /// <note type="note">Currently, only RSA and DSA keys are supported.</note>
358
                /// </remarks>
359
                /// <returns>The AsymmetricAlgorithm.</returns>
360
                /// <param name="key">The AsymmetricCipherKeyPair.</param>
361
                /// <exception cref="System.ArgumentNullException">
362
                /// <paramref name="key"/> is <see langword="null"/>.
363
                /// </exception>
364
                /// <exception cref="System.NotSupportedException">
365
                /// <paramref name="key"/> is an unsupported asymmetric algorithm.
366
                /// </exception>
367
                public static AsymmetricAlgorithm AsAsymmetricAlgorithm (this AsymmetricCipherKeyPair key)
368
                {
1✔
369
                        // TODO: Drop this API - it's no longer needed. The WindowsSecureMimeContext now exports the certificate & key into a pkcs12 and then loads that into an X509Certificate2.
370
                        if (key == null)
1✔
371
                                throw new ArgumentNullException (nameof (key));
1✔
372

373
                        if (key.Private is RsaPrivateCrtKeyParameters rsaPrivateKey)
1✔
374
                                return GetAsymmetricAlgorithm (rsaPrivateKey);
1✔
375

376
                        if (key.Private is DsaPrivateKeyParameters dsaPrivateKey)
×
377
                                return GetAsymmetricAlgorithm (dsaPrivateKey, (DsaPublicKeyParameters) key.Public);
×
378

379
                        throw new NotSupportedException (string.Format ("{0} is currently not supported.", key.GetType ().Name));
×
380
                }
1✔
381
        }
382
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc