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

jstedfast / MimeKit / 4.10.0.1509

02 Feb 2025 05:09PM UTC coverage: 94.542% (-0.009%) from 94.551%
4.10.0.1509

push

coveralls.net

jstedfast
Updated MimeParser/MimeReader benchmark baselines

31336 of 33145 relevant lines covered (94.54%)

0.95 hits per line

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

83.87
/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
                static void GetAsymmetricKeyParameters (DSA dsa, bool publicOnly, out AsymmetricKeyParameter pub, out AsymmetricKeyParameter key)
44
                {
1✔
45
                        var dp = dsa.ExportParameters (!publicOnly);
1✔
46
                        var validationParameters = dp.Seed != null ? new DsaValidationParameters (dp.Seed, dp.Counter) : null;
1✔
47
                        var parameters = new DsaParameters (
1✔
48
                                new BigInteger (1, dp.P),
49
                                new BigInteger (1, dp.Q),
50
                                new BigInteger (1, dp.G),
51
                                validationParameters);
52

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

57
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (DSACryptoServiceProvider dsa)
58
                {
1✔
59
                        GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out var pub, out var key);
1✔
60

61
                        return dsa.PublicOnly ? pub : key;
1✔
62
                }
1✔
63

64
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (DSACryptoServiceProvider dsa)
65
                {
1✔
66
                        if (dsa.PublicOnly)
1✔
67
                                throw new ArgumentException ("DSA key is not a private key.", "key");
×
68

69
                        GetAsymmetricKeyParameters (dsa, dsa.PublicOnly, out var pub, out var key);
1✔
70

71
                        return new AsymmetricCipherKeyPair (pub, key);
1✔
72
                }
1✔
73

74
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (DSA dsa)
75
                {
1✔
76
                        GetAsymmetricKeyParameters (dsa, false, out _, out var key);
1✔
77

78
                        return key;
1✔
79
                }
1✔
80

81
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (DSA dsa)
82
                {
×
83
                        GetAsymmetricKeyParameters (dsa, false, out var pub, out var key);
×
84

85
                        return new AsymmetricCipherKeyPair (pub, key);
×
86
                }
×
87

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

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

107
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (RSACryptoServiceProvider rsa)
108
                {
1✔
109
                        GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out var pub, out var key);
1✔
110

111
                        return rsa.PublicOnly ? pub : key;
1✔
112
                }
1✔
113

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

119
                        GetAsymmetricKeyParameters (rsa, rsa.PublicOnly, out var pub, out var key);
1✔
120

121
                        return new AsymmetricCipherKeyPair (pub, key);
1✔
122
                }
1✔
123

124
                static AsymmetricKeyParameter GetAsymmetricKeyParameter (RSA rsa)
125
                {
1✔
126
                        GetAsymmetricKeyParameters (rsa, false, out _, out var key);
1✔
127

128
                        return key;
1✔
129
                }
1✔
130

131
                static AsymmetricCipherKeyPair GetAsymmetricCipherKeyPair (RSA rsa)
132
                {
×
133
                        GetAsymmetricKeyParameters (rsa, false, out var pub, out var key);
×
134

135
                        return new AsymmetricCipherKeyPair (pub, key);
×
136
                }
×
137

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

158
                        if (key is RSACryptoServiceProvider rsaKey)
1✔
159
                                return GetAsymmetricKeyParameter (rsaKey);
1✔
160

161
                        if (key is RSA rsa)
1✔
162
                                return GetAsymmetricKeyParameter (rsa);
1✔
163

164
                        if (key is DSACryptoServiceProvider dsaKey)
1✔
165
                                return GetAsymmetricKeyParameter (dsaKey);
1✔
166

167
                        if (key is DSA dsa)
1✔
168
                                return GetAsymmetricKeyParameter (dsa);
1✔
169

170
                        // TODO: support ECDiffieHellman and ECDsa?
171

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

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

198
                        if (key is RSACryptoServiceProvider rsaKey)
1✔
199
                                return GetAsymmetricCipherKeyPair (rsaKey);
1✔
200

201
                        if (key is RSA rsa)
1✔
202
                                return GetAsymmetricCipherKeyPair (rsa);
×
203

204
                        if (key is DSACryptoServiceProvider dsaKey)
1✔
205
                                return GetAsymmetricCipherKeyPair (dsaKey);
1✔
206

207
                        if (key is DSA dsa)
×
208
                                return GetAsymmetricCipherKeyPair (dsa);
×
209

210
                        // TODO: support ECDiffieHellman and ECDsa?
211

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

215
                static byte[] GetPaddedByteArray (BigInteger big, int length)
216
                {
1✔
217
                        var bytes = big.ToByteArrayUnsigned ();
1✔
218

219
                        if (bytes.Length >= length)
1✔
220
                                return bytes;
1✔
221

222
                        var padded = new byte[length];
×
223

224
                        Buffer.BlockCopy (bytes, 0, padded, length - bytes.Length, bytes.Length);
×
225

226
                        return padded;
×
227
                }
1✔
228

229
                static DSAParameters GetDSAParameters (DsaKeyParameters key)
230
                {
1✔
231
                        var parameters = new DSAParameters ();
1✔
232

233
                        if (key.Parameters.ValidationParameters != null) {
×
234
                                parameters.Counter = key.Parameters.ValidationParameters.Counter;
×
235
                                parameters.Seed = key.Parameters.ValidationParameters.GetSeed ();
×
236
                        }
×
237

238
                        parameters.P = key.Parameters.P.ToByteArrayUnsigned ();
1✔
239
                        parameters.Q = key.Parameters.Q.ToByteArrayUnsigned ();
1✔
240
                        parameters.G = GetPaddedByteArray (key.Parameters.G, parameters.P.Length);
1✔
241

242
                        return parameters;
1✔
243
                }
1✔
244

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

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

257
                        var dsa = new DSACryptoServiceProvider ();
1✔
258

259
                        dsa.ImportParameters (parameters);
1✔
260

261
                        return dsa;
1✔
262
                }
1✔
263

264
                static AsymmetricAlgorithm GetAsymmetricAlgorithm (DsaPublicKeyParameters key)
265
                {
1✔
266
                        var parameters = GetDSAParameters (key);
1✔
267
                        parameters.Y = GetPaddedByteArray (key.Y, parameters.P.Length);
1✔
268

269
                        var dsa = new DSACryptoServiceProvider ();
1✔
270

271
                        dsa.ImportParameters (parameters);
1✔
272

273
                        return dsa;
1✔
274
                }
1✔
275

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

285
                        parameters.InverseQ = GetPaddedByteArray (key.QInv, parameters.Q.Length);
1✔
286
                        parameters.D = GetPaddedByteArray (key.Exponent, parameters.Modulus.Length);
1✔
287
                        parameters.DP = GetPaddedByteArray (key.DP, parameters.P.Length);
1✔
288
                        parameters.DQ = GetPaddedByteArray (key.DQ, parameters.Q.Length);
1✔
289

290
                        var rsa = new RSACryptoServiceProvider ();
1✔
291

292
                        rsa.ImportParameters (parameters);
1✔
293

294
                        return rsa;
1✔
295
                }
1✔
296

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

304
                        var rsa = new RSACryptoServiceProvider ();
1✔
305

306
                        rsa.ImportParameters (parameters);
1✔
307

308
                        return rsa;
1✔
309
                }
1✔
310

311
                /// <summary>
312
                /// Convert a BouncyCastle AsymmetricKeyParameter into an AsymmetricAlgorithm.
313
                /// </summary>
314
                /// <remarks>
315
                /// <para>Converts a BouncyCastle AsymmetricKeyParameter into an AsymmetricAlgorithm.</para>
316
                /// <note type="note">Currently, only RSA and DSA keys are supported.</note>
317
                /// </remarks>
318
                /// <returns>The AsymmetricAlgorithm.</returns>
319
                /// <param name="key">The AsymmetricKeyParameter.</param>
320
                /// <exception cref="System.ArgumentNullException">
321
                /// <paramref name="key"/> is <see langword="null"/>.
322
                /// </exception>
323
                /// <exception cref="System.NotSupportedException">
324
                /// <paramref name="key"/> is an unsupported asymmetric key parameter.
325
                /// </exception>
326
                public static AsymmetricAlgorithm AsAsymmetricAlgorithm (this AsymmetricKeyParameter key)
327
                {
1✔
328
                        // 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.
329
                        if (key == null)
1✔
330
                                throw new ArgumentNullException (nameof (key));
1✔
331

332
                        if (key.IsPrivate) {
1✔
333
                                if (key is RsaPrivateCrtKeyParameters rsaPrivateKey)
1✔
334
                                        return GetAsymmetricAlgorithm (rsaPrivateKey);
1✔
335

336
                                if (key is DsaPrivateKeyParameters dsaPrivateKey)
1✔
337
                                        return GetAsymmetricAlgorithm (dsaPrivateKey, null);
1✔
338
                        } else {
1✔
339
                                if (key is RsaKeyParameters rsaPublicKey)
1✔
340
                                        return GetAsymmetricAlgorithm (rsaPublicKey);
1✔
341

342
                                if (key is DsaPublicKeyParameters dsaPublicKey)
1✔
343
                                        return GetAsymmetricAlgorithm (dsaPublicKey);
1✔
344
                        }
×
345

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

349
                /// <summary>
350
                /// Convert a BouncyCastle AsymmetricCipherKeyPair into an AsymmetricAlgorithm.
351
                /// </summary>
352
                /// <remarks>
353
                /// <para>Converts a BouncyCastle AsymmetricCipherKeyPair into an AsymmetricAlgorithm.</para>
354
                /// <note type="note">Currently, only RSA and DSA keys are supported.</note>
355
                /// </remarks>
356
                /// <returns>The AsymmetricAlgorithm.</returns>
357
                /// <param name="key">The AsymmetricCipherKeyPair.</param>
358
                /// <exception cref="System.ArgumentNullException">
359
                /// <paramref name="key"/> is <see langword="null"/>.
360
                /// </exception>
361
                /// <exception cref="System.NotSupportedException">
362
                /// <paramref name="key"/> is an unsupported asymmetric algorithm.
363
                /// </exception>
364
                public static AsymmetricAlgorithm AsAsymmetricAlgorithm (this AsymmetricCipherKeyPair key)
365
                {
1✔
366
                        // 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.
367
                        if (key == null)
1✔
368
                                throw new ArgumentNullException (nameof (key));
1✔
369

370
                        if (key.Private is RsaPrivateCrtKeyParameters rsaPrivateKey)
1✔
371
                                return GetAsymmetricAlgorithm (rsaPrivateKey);
1✔
372

373
                        if (key.Private is DsaPrivateKeyParameters dsaPrivateKey)
1✔
374
                                return GetAsymmetricAlgorithm (dsaPrivateKey, (DsaPublicKeyParameters) key.Public);
1✔
375

376
                        throw new NotSupportedException (string.Format ("{0} is currently not supported.", key.GetType ().Name));
×
377
                }
1✔
378
        }
379
}
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