|
1 | 1 | // Licensed to the .NET Foundation under one or more agreements.
|
2 | 2 | // The .NET Foundation licenses this file to you under the MIT license.
|
3 | 3 |
|
| 4 | +using System.Diagnostics; |
4 | 5 | using static Interop.BCrypt;
|
5 | 6 |
|
6 | 7 | namespace System.Security.Cryptography
|
@@ -77,6 +78,100 @@ internal static byte[] ExportKeyBlob(
|
77 | 78 | return blob;
|
78 | 79 | }
|
79 | 80 |
|
| 81 | + internal static ECParameters ExportExplicitParameters(CngKey key, bool includePrivateParameters) |
| 82 | + { |
| 83 | + if (includePrivateParameters) |
| 84 | + { |
| 85 | + return ExportPrivateExplicitParameters(key); |
| 86 | + } |
| 87 | + else |
| 88 | + { |
| 89 | + byte[] blob = ExportFullKeyBlob(key, includePrivateParameters: false); |
| 90 | + ECParameters ecparams = default; |
| 91 | + ExportPrimeCurveParameters(ref ecparams, blob, includePrivateParameters: false); |
| 92 | + return ecparams; |
| 93 | + } |
| 94 | + } |
| 95 | + |
| 96 | + internal static ECParameters ExportParameters(CngKey key, bool includePrivateParameters) |
| 97 | + { |
| 98 | + ECParameters ecparams = default; |
| 99 | + |
| 100 | + const string TemporaryExportPassword = "DotnetExportPhrase"; |
| 101 | + string? curveName = key.GetCurveName(out string? oidValue); |
| 102 | + |
| 103 | + if (string.IsNullOrEmpty(curveName)) |
| 104 | + { |
| 105 | + if (includePrivateParameters) |
| 106 | + { |
| 107 | + ecparams = ExportPrivateExplicitParameters(key); |
| 108 | + } |
| 109 | + else |
| 110 | + { |
| 111 | + byte[] fullKeyBlob = ExportFullKeyBlob(key, includePrivateParameters: false); |
| 112 | + ECCng.ExportPrimeCurveParameters(ref ecparams, fullKeyBlob, includePrivateParameters: false); |
| 113 | + } |
| 114 | + } |
| 115 | + else |
| 116 | + { |
| 117 | + bool encryptedOnlyExport = CngPkcs8.AllowsOnlyEncryptedExport(key); |
| 118 | + |
| 119 | + if (includePrivateParameters && encryptedOnlyExport) |
| 120 | + { |
| 121 | + byte[] exported = key.ExportPkcs8KeyBlob(TemporaryExportPassword, 1); |
| 122 | + EccKeyFormatHelper.ReadEncryptedPkcs8( |
| 123 | + exported, |
| 124 | + TemporaryExportPassword, |
| 125 | + out _, |
| 126 | + out ecparams); |
| 127 | + } |
| 128 | + else |
| 129 | + { |
| 130 | + byte[] keyBlob = ExportKeyBlob(key, includePrivateParameters); |
| 131 | + ECCng.ExportNamedCurveParameters(ref ecparams, keyBlob, includePrivateParameters); |
| 132 | + ecparams.Curve = ECCurve.CreateFromOid(new Oid(oidValue, curveName)); |
| 133 | + } |
| 134 | + } |
| 135 | + |
| 136 | + return ecparams; |
| 137 | + } |
| 138 | + |
| 139 | + private static ECParameters ExportPrivateExplicitParameters(CngKey key) |
| 140 | + { |
| 141 | + bool encryptedOnlyExport = CngPkcs8.AllowsOnlyEncryptedExport(key); |
| 142 | + |
| 143 | + ECParameters ecparams = default; |
| 144 | + |
| 145 | + if (encryptedOnlyExport) |
| 146 | + { |
| 147 | + // We can't ask CNG for the explicit parameters when performing a PKCS#8 export. Instead, |
| 148 | + // we ask CNG for the explicit parameters for the public part only, since the parameters are public. |
| 149 | + // Then we ask CNG by encrypted PKCS#8 for the private parameters (D) and combine the explicit public |
| 150 | + // key along with the private key. |
| 151 | + const string TemporaryExportPassword = "DotnetExportPhrase"; |
| 152 | + byte[] publicKeyBlob = ExportFullKeyBlob(key, includePrivateParameters: false); |
| 153 | + ExportPrimeCurveParameters(ref ecparams, publicKeyBlob, includePrivateParameters: false); |
| 154 | + |
| 155 | + byte[] exported = key.ExportPkcs8KeyBlob(TemporaryExportPassword, 1); |
| 156 | + EccKeyFormatHelper.ReadEncryptedPkcs8( |
| 157 | + exported, |
| 158 | + TemporaryExportPassword, |
| 159 | + out _, |
| 160 | + out ECParameters localParameters); |
| 161 | + |
| 162 | + Debug.Assert(ecparams.Q.X.AsSpan().SequenceEqual(localParameters.Q.X)); |
| 163 | + Debug.Assert(ecparams.Q.Y.AsSpan().SequenceEqual(localParameters.Q.Y)); |
| 164 | + ecparams.D = localParameters.D; |
| 165 | + } |
| 166 | + else |
| 167 | + { |
| 168 | + byte[] blob = ExportFullKeyBlob(key, includePrivateParameters: true); |
| 169 | + ExportPrimeCurveParameters(ref ecparams, blob, includePrivateParameters: true); |
| 170 | + } |
| 171 | + |
| 172 | + return ecparams; |
| 173 | + } |
| 174 | + |
80 | 175 | private static unsafe void FixupGenericBlob(byte[] blob)
|
81 | 176 | {
|
82 | 177 | if (blob.Length > sizeof(BCRYPT_ECCKEY_BLOB))
|
|
0 commit comments