3 // Copyright (c) Microsoft Corporation. All rights reserved.
6 // <OWNER>[....]</OWNER>
10 // DSACryptoServiceProvider.cs
12 // CSP-based implementation of DSA
15 namespace System.Security.Cryptography {
18 using System.Security.Cryptography.X509Certificates;
19 using System.Security.Permissions;
20 using System.Globalization;
21 using System.Runtime.Versioning;
22 using System.Diagnostics.Contracts;
24 // Object layout of the DSAParameters structure
25 internal class DSACspObject {
36 [System.Runtime.InteropServices.ComVisible(true)]
37 public sealed class DSACryptoServiceProvider : DSA, ICspAsymmetricAlgorithm {
38 private int _dwKeySize;
39 private CspParameters _parameters;
40 private bool _randomKeyContainer;
41 [System.Security.SecurityCritical] // auto-generated
42 private SafeProvHandle _safeProvHandle;
43 [System.Security.SecurityCritical] // auto-generated
44 private SafeKeyHandle _safeKeyHandle;
45 private SHA1CryptoServiceProvider _sha1;
47 private static volatile CspProviderFlags s_UseMachineKeyStore = 0;
50 // public constructors
53 [ResourceExposure(ResourceScope.None)]
54 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
55 public DSACryptoServiceProvider()
56 : this(0, new CspParameters(Constants.PROV_DSS_DH, null, null, s_UseMachineKeyStore)) {
59 [ResourceExposure(ResourceScope.None)]
60 [ResourceConsumption(ResourceScope.Machine, ResourceScope.Machine)]
61 public DSACryptoServiceProvider(int dwKeySize)
62 : this(dwKeySize, new CspParameters(Constants.PROV_DSS_DH, null, null, s_UseMachineKeyStore)) {
65 public DSACryptoServiceProvider(CspParameters parameters)
66 : this(0, parameters) {
69 [System.Security.SecuritySafeCritical] // auto-generated
70 public DSACryptoServiceProvider(int dwKeySize, CspParameters parameters) {
72 throw new ArgumentOutOfRangeException("dwKeySize", Environment.GetResourceString("ArgumentOutOfRange_NeedNonNegNum"));
73 Contract.EndContractBlock();
75 _parameters = Utils.SaveCspParameters(CspAlgorithmType.Dss, parameters, s_UseMachineKeyStore, ref _randomKeyContainer);
76 LegalKeySizesValue = new KeySizes[] { new KeySizes(512, 1024, 64) }; // per the DSS spec
77 _dwKeySize = dwKeySize;
78 _sha1 = new SHA1CryptoServiceProvider();
80 // If this is not a random container we generate, create it eagerly
81 // in the constructor so we can report any errors now.
82 if (!_randomKeyContainer || Environment.GetCompatibilityFlag(CompatibilityFlag.EagerlyGenerateRandomAsymmKeys))
90 [System.Security.SecurityCritical] // auto-generated
91 private void GetKeyPair () {
92 if (_safeKeyHandle == null) {
94 if (_safeKeyHandle == null)
95 Utils.GetKeyPairHelper(CspAlgorithmType.Dss, _parameters, _randomKeyContainer, _dwKeySize, ref _safeProvHandle, ref _safeKeyHandle);
100 [System.Security.SecuritySafeCritical] // overrides public transparent member
101 protected override void Dispose(bool disposing) {
102 base.Dispose(disposing);
104 if (_safeKeyHandle != null && !_safeKeyHandle.IsClosed)
105 _safeKeyHandle.Dispose();
106 if (_safeProvHandle != null && !_safeProvHandle.IsClosed)
107 _safeProvHandle.Dispose();
114 [System.Runtime.InteropServices.ComVisible(false)]
115 public bool PublicOnly {
116 [System.Security.SecuritySafeCritical] // auto-generated
119 byte[] publicKey = (byte[]) Utils._GetKeyParameter(_safeKeyHandle, Constants.CLR_PUBLICKEYONLY);
120 return (publicKey[0] == 1);
124 [System.Runtime.InteropServices.ComVisible(false)]
125 public CspKeyContainerInfo CspKeyContainerInfo {
126 [System.Security.SecuritySafeCritical] // auto-generated
129 return new CspKeyContainerInfo(_parameters, _randomKeyContainer);
133 public override int KeySize {
134 [System.Security.SecuritySafeCritical] // auto-generated
137 byte[] keySize = (byte[]) Utils._GetKeyParameter(_safeKeyHandle, Constants.CLR_KEYLEN);
138 _dwKeySize = (keySize[0] | (keySize[1] << 8) | (keySize[2] << 16) | (keySize[3] << 24));
143 public override string KeyExchangeAlgorithm {
147 public override string SignatureAlgorithm {
148 get { return "http://www.w3.org/2000/09/xmldsig#dsa-sha1"; }
151 public static bool UseMachineKeyStore {
152 get { return (s_UseMachineKeyStore == CspProviderFlags.UseMachineKeyStore); }
153 set { s_UseMachineKeyStore = (value ? CspProviderFlags.UseMachineKeyStore : 0); }
156 public bool PersistKeyInCsp {
157 [System.Security.SecuritySafeCritical] // auto-generated
159 if (_safeProvHandle == null) {
161 if (_safeProvHandle == null)
162 _safeProvHandle = Utils.CreateProvHandle(_parameters, _randomKeyContainer);
165 return Utils.GetPersistKeyInCsp(_safeProvHandle);
167 [System.Security.SecuritySafeCritical] // auto-generated
169 bool oldPersistKeyInCsp = this.PersistKeyInCsp;
170 if (value == oldPersistKeyInCsp)
173 KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
175 KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Delete);
176 kp.AccessEntries.Add(entry);
178 KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Create);
179 kp.AccessEntries.Add(entry);
183 Utils.SetPersistKeyInCsp(_safeProvHandle, value);
191 [System.Security.SecuritySafeCritical] // auto-generated
192 public override DSAParameters ExportParameters (bool includePrivateParameters) {
194 if (includePrivateParameters) {
195 KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
196 KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Export);
197 kp.AccessEntries.Add(entry);
200 DSACspObject dsaCspObject = new DSACspObject();
201 int blobType = includePrivateParameters ? Constants.PRIVATEKEYBLOB : Constants.PUBLICKEYBLOB;
202 // _ExportKey will check for failures and throw an exception
203 Utils._ExportKey(_safeKeyHandle, blobType, dsaCspObject);
204 return DSAObjectToStruct(dsaCspObject);
207 [System.Security.SecuritySafeCritical] // auto-generated
208 [System.Runtime.InteropServices.ComVisible(false)]
209 public byte[] ExportCspBlob (bool includePrivateParameters) {
211 return Utils.ExportCspBlobHelper(includePrivateParameters, _parameters, _safeKeyHandle);
214 [System.Security.SecuritySafeCritical] // auto-generated
215 public override void ImportParameters(DSAParameters parameters) {
216 DSACspObject dsaCspObject = DSAStructToObject(parameters);
217 // Free the current key handle
218 if (_safeKeyHandle != null && !_safeKeyHandle.IsClosed)
219 _safeKeyHandle.Dispose();
220 _safeKeyHandle = SafeKeyHandle.InvalidHandle;
222 if (IsPublic(parameters)) {
223 // Use our CRYPT_VERIFYCONTEXT handle, CRYPT_EXPORTABLE is not applicable to public only keys, so pass false
224 Utils._ImportKey(Utils.StaticDssProvHandle, Constants.CALG_DSS_SIGN, (CspProviderFlags) 0, dsaCspObject, ref _safeKeyHandle);
226 KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
227 KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Import);
228 kp.AccessEntries.Add(entry);
230 if (_safeProvHandle == null)
231 _safeProvHandle = Utils.CreateProvHandle(_parameters, _randomKeyContainer);
232 // Now, import the key into the CSP; _ImportKey will check for failures.
233 Utils._ImportKey(_safeProvHandle, Constants.CALG_DSS_SIGN, _parameters.Flags, dsaCspObject, ref _safeKeyHandle);
237 [System.Security.SecuritySafeCritical] // auto-generated
238 [System.Runtime.InteropServices.ComVisible(false)]
239 public void ImportCspBlob (byte[] keyBlob) {
240 Utils.ImportCspBlobHelper(CspAlgorithmType.Dss, keyBlob, IsPublic(keyBlob), ref _parameters, _randomKeyContainer, ref _safeProvHandle, ref _safeKeyHandle);
243 public byte[] SignData(Stream inputStream) {
244 byte[] hashVal = _sha1.ComputeHash(inputStream);
245 return SignHash(hashVal, null);
248 public byte[] SignData(byte[] buffer) {
249 byte[] hashVal = _sha1.ComputeHash(buffer);
250 return SignHash(hashVal, null);
253 public byte[] SignData(byte[] buffer, int offset, int count) {
254 byte[] hashVal = _sha1.ComputeHash(buffer, offset, count);
255 return SignHash(hashVal, null);
258 public bool VerifyData(byte[] rgbData, byte[] rgbSignature) {
259 byte[] hashVal = _sha1.ComputeHash(rgbData);
260 return VerifyHash(hashVal, null, rgbSignature);
263 override public byte[] CreateSignature(byte[] rgbHash) {
264 return SignHash(rgbHash, null);
267 override public bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) {
268 return VerifyHash(rgbHash, null, rgbSignature);
271 protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
273 // we're sealed and the base should have checked this before calling us
274 Contract.Assert(data != null);
275 Contract.Assert(offset >= 0 && offset <= data.Length);
276 Contract.Assert(count >= 0 && count <= data.Length - offset);
277 Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
279 if (hashAlgorithm != HashAlgorithmName.SHA1)
281 throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name));
284 return _sha1.ComputeHash(data, offset, count);
287 protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
289 // we're sealed and the base should have checked this before calling us
290 Contract.Assert(data != null);
291 Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name));
293 if (hashAlgorithm != HashAlgorithmName.SHA1)
295 throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name));
298 return _sha1.ComputeHash(data);
301 [System.Security.SecuritySafeCritical] // auto-generated
302 public byte[] SignHash(byte[] rgbHash, string str) {
304 throw new ArgumentNullException("rgbHash");
305 Contract.EndContractBlock();
307 throw new CryptographicException(Environment.GetResourceString("Cryptography_CSP_NoPrivateKey"));
309 int calgHash = X509Utils.NameOrOidToAlgId(str, OidGroup.HashAlgorithm);
310 if (rgbHash.Length != _sha1.HashSize / 8)
311 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidHashSize", "SHA1", _sha1.HashSize / 8));
314 if (!CspKeyContainerInfo.RandomlyGenerated) {
315 KeyContainerPermission kp = new KeyContainerPermission(KeyContainerPermissionFlags.NoFlags);
316 KeyContainerPermissionAccessEntry entry = new KeyContainerPermissionAccessEntry(_parameters, KeyContainerPermissionFlags.Sign);
317 kp.AccessEntries.Add(entry);
320 return Utils.SignValue(_safeKeyHandle, _parameters.KeyNumber, Constants.CALG_DSS_SIGN, calgHash, rgbHash);
323 [System.Security.SecuritySafeCritical] // auto-generated
324 public bool VerifyHash(byte[] rgbHash, string str, byte[] rgbSignature) {
326 throw new ArgumentNullException("rgbHash");
327 if (rgbSignature == null)
328 throw new ArgumentNullException("rgbSignature");
329 Contract.EndContractBlock();
331 int calgHash = X509Utils.NameOrOidToAlgId(str, OidGroup.HashAlgorithm);
332 if (rgbHash.Length != _sha1.HashSize / 8)
333 throw new CryptographicException(Environment.GetResourceString("Cryptography_InvalidHashSize", "SHA1", _sha1.HashSize / 8));
336 return Utils.VerifySign(_safeKeyHandle, Constants.CALG_DSS_SIGN, calgHash, rgbHash, rgbSignature);
340 // private static methods
343 private static DSAParameters DSAObjectToStruct (DSACspObject dsaCspObject) {
344 DSAParameters dsaParams = new DSAParameters();
345 dsaParams.P = dsaCspObject.P;
346 dsaParams.Q = dsaCspObject.Q;
347 dsaParams.G = dsaCspObject.G;
348 dsaParams.Y = dsaCspObject.Y;
349 dsaParams.J = dsaCspObject.J;
350 dsaParams.X = dsaCspObject.X;
351 dsaParams.Seed = dsaCspObject.Seed;
352 dsaParams.Counter = dsaCspObject.Counter;
356 private static DSACspObject DSAStructToObject (DSAParameters dsaParams) {
357 DSACspObject dsaCspObject = new DSACspObject();
358 dsaCspObject.P = dsaParams.P;
359 dsaCspObject.Q = dsaParams.Q;
360 dsaCspObject.G = dsaParams.G;
361 dsaCspObject.Y = dsaParams.Y;
362 dsaCspObject.J = dsaParams.J;
363 dsaCspObject.X = dsaParams.X;
364 dsaCspObject.Seed = dsaParams.Seed;
365 dsaCspObject.Counter = dsaParams.Counter;
369 private static bool IsPublic (DSAParameters dsaParams) {
370 return (dsaParams.X == null);
373 // find whether a DSS key blob is public.
374 private static bool IsPublic (byte[] keyBlob) {
376 throw new ArgumentNullException("keyBlob");
377 Contract.EndContractBlock();
379 // The CAPI DSS public key representation consists of the following sequence:
388 // The first should be PUBLICKEYBLOB and magic should be DSS_MAGIC "DSS1" or DSS_PUB_MAGIC_VER3 "DSS3"
389 if (keyBlob[0] != Constants.PUBLICKEYBLOB)
392 if ((keyBlob[11] != 0x31 && keyBlob[11] != 0x33) || keyBlob[10] != 0x53 || keyBlob[9] != 0x53 || keyBlob[8] != 0x44)