1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using Internal.Cryptography;
6 using Internal.NativeCrypto;
7 using System.IO;
8 
9 namespace System.Security.Cryptography
10 {
11     public sealed class DSACryptoServiceProvider : DSA, ICspAsymmetricAlgorithm
12     {
13         private const int SHA1_HASHSIZE = 20;
14 
15         private readonly DSA _impl;
16         private bool _publicOnly;
17 
18         private static KeySizes[] s_legalKeySizes =
19         {
20             new KeySizes(512, 1024, 64)  // Use the same values as Csp Windows because the _impl has different values (512, 3072, 64)
21         };
22 
DSACryptoServiceProvider()23         public DSACryptoServiceProvider() : base()
24         {
25             // This class wraps DSA
26             _impl = DSA.Create();
27             KeySize = 1024;
28         }
29 
DSACryptoServiceProvider(int dwKeySize)30         public DSACryptoServiceProvider(int dwKeySize) : base()
31         {
32             if (dwKeySize < 0)
33                 throw new ArgumentOutOfRangeException(nameof(dwKeySize), SR.ArgumentOutOfRange_NeedNonNegNum);
34 
35             // This class wraps DSA
36             _impl = DSA.Create();
37             KeySize = dwKeySize;
38         }
39 
DSACryptoServiceProvider(int dwKeySize, CspParameters parameters)40         public DSACryptoServiceProvider(int dwKeySize, CspParameters parameters)
41         {
42             throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CAPI_Required, nameof(CspParameters)));
43         }
44 
DSACryptoServiceProvider(CspParameters parameters)45         public DSACryptoServiceProvider(CspParameters parameters)
46         {
47             throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CAPI_Required, nameof(CspParameters)));
48         }
49 
50         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "This is the implementation of DSACryptoServiceProvider")]
51         public override byte[] CreateSignature(byte[] rgbHash) => _impl.CreateSignature(rgbHash);
52 
TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten)53         public override bool TryCreateSignature(ReadOnlySpan<byte> source, Span<byte> destination, out int bytesWritten) =>
54             _impl.TryCreateSignature(source, destination, out bytesWritten);
55 
56         public CspKeyContainerInfo CspKeyContainerInfo
57         {
58             get { throw new PlatformNotSupportedException(SR.Format(SR.Cryptography_CAPI_Required, nameof(CspKeyContainerInfo))); }
59         }
60 
Dispose(bool disposing)61         protected override void Dispose(bool disposing)
62         {
63             if (disposing)
64             {
65                 _impl.Dispose();
66                 base.Dispose(disposing);
67             }
68         }
69 
ExportCspBlob(bool includePrivateParameters)70         public byte[] ExportCspBlob(bool includePrivateParameters)
71         {
72             DSAParameters parameters = ExportParameters(includePrivateParameters);
73             return parameters.ToKeyBlob();
74         }
75 
76         public override DSAParameters ExportParameters(bool includePrivateParameters) =>
77             _impl.ExportParameters(includePrivateParameters);
78 
FromXmlString(string xmlString)79         public override void FromXmlString(string xmlString) => _impl.FromXmlString(xmlString);
80 
HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)81         protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
82         {
83             if (hashAlgorithm != HashAlgorithmName.SHA1)
84                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
85 
86             return AsymmetricAlgorithmHelpers.HashData(data, offset, count, hashAlgorithm);
87         }
88 
HashData(Stream data, HashAlgorithmName hashAlgorithm)89         protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm)
90         {
91             if (hashAlgorithm != HashAlgorithmName.SHA1)
92                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
93 
94             return AsymmetricAlgorithmHelpers.HashData(data, hashAlgorithm);
95         }
96 
TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)97         protected override bool TryHashData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
98         {
99             if (hashAlgorithm != HashAlgorithmName.SHA1)
100                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
101 
102             return AsymmetricAlgorithmHelpers.TryHashData(source, destination, hashAlgorithm, out bytesWritten);
103         }
104 
ImportCspBlob(byte[] keyBlob)105         public void ImportCspBlob(byte[] keyBlob)
106         {
107             DSAParameters parameters = keyBlob.ToDSAParameters(!IsPublic(keyBlob), null);
108             ImportParameters(parameters);
109         }
110 
ImportParameters(DSAParameters parameters)111         public override void ImportParameters(DSAParameters parameters)
112         {
113             // Although _impl supports key sizes > 1024, limit here for compat.
114             if (parameters.Y != null && parameters.Y.Length > 1024 / 8)
115                 throw new CryptographicException(SR.Argument_InvalidValue);
116 
117             _impl.ImportParameters(parameters);
118 
119             _publicOnly = (parameters.X == null);
120         }
121 
122         public override string KeyExchangeAlgorithm => _impl.KeyExchangeAlgorithm;
123 
124         public override int KeySize
125         {
126             get { return _impl.KeySize; }
127             set
128             {
129                 // Perform the check here because LegalKeySizes are more restrictive here than _impl
130                 if (!value.IsLegalSize(s_legalKeySizes))
131                     throw new CryptographicException(SR.Cryptography_InvalidKeySize);
132 
133                 _impl.KeySize = value;
134             }
135         }
136 
137         public override KeySizes[] LegalKeySizes => s_legalKeySizes.CloneKeySizesArray();
138 
139         // PersistKeyInCsp has no effect in Unix
140         public bool PersistKeyInCsp { get; set; }
141 
142         public bool PublicOnly
143         {
144             get { return _publicOnly; }
145         }
146 
147         public override string SignatureAlgorithm => "http://www.w3.org/2000/09/xmldsig#dsa-sha1";
148 
SignData(byte[] buffer)149         public byte[] SignData(byte[] buffer)
150         {
151             return _impl.SignData(buffer, HashAlgorithmName.SHA1);
152         }
153 
SignData(byte[] buffer, int offset, int count)154         public byte[] SignData(byte[] buffer, int offset, int count)
155         {
156             return _impl.SignData(buffer, offset, count, HashAlgorithmName.SHA1);
157         }
158 
SignData(Stream inputStream)159         public byte[] SignData(Stream inputStream)
160         {
161             return _impl.SignData(inputStream, HashAlgorithmName.SHA1);
162         }
163 
164         public override string ToXmlString(bool includePrivateParameters) =>
165             _impl.ToXmlString(includePrivateParameters);
166 
SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)167         public override byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm)
168         {
169             if (hashAlgorithm != HashAlgorithmName.SHA1)
170                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
171 
172             return _impl.SignData(data, offset, count, hashAlgorithm);
173         }
174 
SignData(Stream data, HashAlgorithmName hashAlgorithm)175         public override byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm)
176         {
177             if (hashAlgorithm != HashAlgorithmName.SHA1)
178                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
179 
180             return _impl.SignData(data, hashAlgorithm);
181         }
182 
TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)183         public override bool TrySignData(ReadOnlySpan<byte> source, Span<byte> destination, HashAlgorithmName hashAlgorithm, out int bytesWritten)
184         {
185             if (hashAlgorithm != HashAlgorithmName.SHA1)
186                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
187 
188             return _impl.TrySignData(source, destination, hashAlgorithm, out bytesWritten);
189         }
190 
191         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA5351", Justification = "This is the implementation of DSACryptoServiceProvider")]
SignHash(byte[] rgbHash, string str)192         public byte[] SignHash(byte[] rgbHash, string str)
193         {
194             if (rgbHash == null)
195                 throw new ArgumentNullException(nameof(rgbHash));
196             if (PublicOnly)
197                 throw new CryptographicException(SR.Cryptography_CSP_NoPrivateKey);
198             if (rgbHash.Length != SHA1_HASHSIZE)
199                 throw new CryptographicException(string.Format(SR.Cryptography_InvalidHashSize, "SHA1", SHA1_HASHSIZE));
200 
201             // Only SHA1 allowed; the default value is SHA1
202             if (str != null && string.Compare(str, "SHA1", StringComparison.OrdinalIgnoreCase) != 0)
203                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, str);
204 
205             return CreateSignature(rgbHash);
206         }
207 
VerifyData(byte[] rgbData, byte[] rgbSignature)208         public bool VerifyData(byte[] rgbData, byte[] rgbSignature) =>
209             _impl.VerifyData(rgbData, rgbSignature, HashAlgorithmName.SHA1);
210 
VerifyHash(byte[] rgbHash, string str, byte[] rgbSignature)211         public bool VerifyHash(byte[] rgbHash, string str, byte[] rgbSignature)
212         {
213             if (rgbHash == null)
214                 throw new ArgumentNullException(nameof(rgbHash));
215             if (rgbSignature == null)
216                 throw new ArgumentNullException(nameof(rgbSignature));
217 
218             // For compat with Windows, no check for rgbHash.Length != SHA1_HASHSIZE
219 
220             // Only SHA1 allowed; the default value is SHA1
221             if (str != null && string.Compare(str, "SHA1", StringComparison.OrdinalIgnoreCase) != 0)
222                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, str);
223 
224             return _impl.VerifySignature(rgbHash, rgbSignature);
225         }
226 
VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm)227         public override bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm)
228         {
229             if (hashAlgorithm != HashAlgorithmName.SHA1)
230                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
231 
232             return _impl.VerifyData(data, offset, count, signature, hashAlgorithm);
233         }
234 
VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm)235         public override bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm)
236         {
237             if (hashAlgorithm != HashAlgorithmName.SHA1)
238                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
239 
240             return _impl.VerifyData(data, signature, hashAlgorithm);
241         }
242 
VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm)243         public override bool VerifyData(ReadOnlySpan<byte> data, ReadOnlySpan<byte> signature, HashAlgorithmName hashAlgorithm)
244         {
245             if (hashAlgorithm != HashAlgorithmName.SHA1)
246                 throw new CryptographicException(SR.Cryptography_UnknownHashAlgorithm, hashAlgorithm.Name);
247 
248             return _impl.VerifyData(data, signature, hashAlgorithm);
249         }
250 
VerifySignature(byte[] rgbHash, byte[] rgbSignature)251         public override bool VerifySignature(byte[] rgbHash, byte[] rgbSignature) =>
252             _impl.VerifySignature(rgbHash, rgbSignature);
253 
VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature)254         public override bool VerifySignature(ReadOnlySpan<byte> rgbHash, ReadOnlySpan<byte> rgbSignature) =>
255             _impl.VerifySignature(rgbHash, rgbSignature);
256 
257         // UseMachineKeyStore has no effect in Unix
258         public static bool UseMachineKeyStore { get; set; }
259 
260         /// <summary>
261         /// Find whether a DSS key blob is public.
262         /// </summary>
IsPublic(byte[] keyBlob)263         private static bool IsPublic(byte[] keyBlob)
264         {
265             if (keyBlob == null)
266                 throw new ArgumentNullException(nameof(keyBlob));
267 
268             // The CAPI DSS public key representation consists of the following sequence:
269             //  - BLOBHEADER (the first byte is bType)
270             //  - DSSPUBKEY or DSSPUBKEY_VER3 (the first field is the magic field)
271 
272             // The first byte should be PUBLICKEYBLOB
273             if (keyBlob[0] != CapiHelper.PUBLICKEYBLOB)
274             {
275                 return false;
276             }
277 
278             // Magic should be DSS_MAGIC or DSS_PUB_MAGIC_VER3
279             if ((keyBlob[11] != 0x31 && keyBlob[11] != 0x33) || keyBlob[10] != 0x53 || keyBlob[9] != 0x53 || keyBlob[8] != 0x44)
280             {
281                 return false;
282             }
283 
284             return true;
285         }
286     }
287 }
288