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