diff options
author | Wes Haggard <Wes.Haggard@microsoft.com> | 2015-05-14 19:50:18 -0700 |
---|---|---|
committer | Wes Haggard <Wes.Haggard@microsoft.com> | 2015-05-14 19:50:18 -0700 |
commit | 2cd11d1101f7d98ed28bbe61d6c21e5c2d0be45c (patch) | |
tree | ac3aba0e133a4d612e75b1371aa94518b953819d /src | |
parent | 08dd1c89375adbd9218475b8c6f044fe3a226c50 (diff) | |
download | coreclr-2cd11d1101f7d98ed28bbe61d6c21e5c2d0be45c.tar.gz coreclr-2cd11d1101f7d98ed28bbe61d6c21e5c2d0be45c.tar.bz2 coreclr-2cd11d1101f7d98ed28bbe61d6c21e5c2d0be45c.zip |
Merge changes from parent branch
[tfs-changeset: 1471040]
Diffstat (limited to 'src')
-rw-r--r-- | src/mscorlib/src/System/Security/Cryptography/RSACryptoServiceProvider.cs | 142 | ||||
-rw-r--r-- | src/mscorlib/src/System/Security/Cryptography/rsa.cs | 198 | ||||
-rw-r--r-- | src/mscorlib/src/mscorlib.txt | 25 |
3 files changed, 337 insertions, 28 deletions
diff --git a/src/mscorlib/src/System/Security/Cryptography/RSACryptoServiceProvider.cs b/src/mscorlib/src/System/Security/Cryptography/RSACryptoServiceProvider.cs index 00e1993186..650c6b925f 100644 --- a/src/mscorlib/src/System/Security/Cryptography/RSACryptoServiceProvider.cs +++ b/src/mscorlib/src/System/Security/Cryptography/RSACryptoServiceProvider.cs @@ -489,5 +489,147 @@ namespace System.Security.Cryptography { private static bool IsPublic(RSAParameters rsaParams) { return (rsaParams.P == null); } + +#if !FEATURE_CORECLR + // + // Adapt new RSA abstraction to legacy RSACryptoServiceProvider surface area. + // + + // NOTE: For the new API, we go straight to CAPI for fixed set of hash algorithms and don't use crypto config here. + // + // Reasons: + // 1. We're moving away from crypto config and we won't have it when porting to .NET Core + // + // 2. It's slow to lookup and slow to use as the base HashAlgorithm adds considerable overhead + // (redundant defensive copy + double-initialization for the single-use case). + // + + [SecuritySafeCritical] + protected override byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) { + // we're sealed and the base should have checked this already + Contract.Assert(data != null); + Contract.Assert(offset >= 0 && offset <= data.Length); + Contract.Assert(count >= 0 && count <= data.Length); + Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name)); + + using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) { + Utils.HashData(hashHandle, data, offset, count); + return Utils.EndHash(hashHandle); + } + } + + [SecuritySafeCritical] + protected override byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) { + // we're sealed and the base should have checked this already + Contract.Assert(data != null); + Contract.Assert(!String.IsNullOrEmpty(hashAlgorithm.Name)); + + using (SafeHashHandle hashHandle = Utils.CreateHash(Utils.StaticProvHandle, GetAlgorithmId(hashAlgorithm))) { + // Read the data 4KB at a time, providing similar read characteristics to a standard HashAlgorithm + byte[] buffer = new byte[4096]; + int bytesRead = 0; + do { + bytesRead = data.Read(buffer, 0, buffer.Length); + if (bytesRead > 0) { + Utils.HashData(hashHandle, buffer, 0, bytesRead); + } + } while (bytesRead > 0); + + return Utils.EndHash(hashHandle); + } + } + + private static int GetAlgorithmId(HashAlgorithmName hashAlgorithm) { + switch (hashAlgorithm.Name) { + case "MD5": + return Constants.CALG_MD5; + case "SHA1": + return Constants.CALG_SHA1; + case "SHA256": + return Constants.CALG_SHA_256; + case "SHA384": + return Constants.CALG_SHA_384; + case "SHA512": + return Constants.CALG_SHA_512; + default: + throw new CryptographicException(Environment.GetResourceString("Cryptography_UnknownHashAlgorithm", hashAlgorithm.Name)); + } + } + + public override byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + + if (padding == RSAEncryptionPadding.Pkcs1) { + return Encrypt(data, fOAEP: false); + } else if (padding == RSAEncryptionPadding.OaepSHA1) { + return Encrypt(data, fOAEP: true); + } else { + throw PaddingModeNotSupported(); + } + } + + public override byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + + if (padding == RSAEncryptionPadding.Pkcs1) { + return Decrypt(data, fOAEP: false); + } else if (padding == RSAEncryptionPadding.OaepSHA1) { + return Decrypt(data, fOAEP: true); + } else { + throw PaddingModeNotSupported(); + } + } + + public override byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (hash == null) { + throw new ArgumentNullException("hash"); + } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { + throw HashAlgorithmNameNullOrEmpty(); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + if (padding != RSASignaturePadding.Pkcs1) { + throw PaddingModeNotSupported(); + } + + return SignHash(hash, GetAlgorithmId(hashAlgorithm)); + } + + public override bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (hash == null) { + throw new ArgumentNullException("hash"); + } + if (signature == null) { + throw new ArgumentNullException("signature"); + } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { + throw HashAlgorithmNameNullOrEmpty(); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + if (padding != RSASignaturePadding.Pkcs1) { + throw PaddingModeNotSupported(); + } + + return VerifyHash(hash, GetAlgorithmId(hashAlgorithm), signature); + } + + private static Exception PaddingModeNotSupported() { + return new CryptographicException(Environment.GetResourceString("Cryptography_InvalidPaddingMode")); + } +#endif } } diff --git a/src/mscorlib/src/System/Security/Cryptography/rsa.cs b/src/mscorlib/src/System/Security/Cryptography/rsa.cs index 000b1be510..c10bad843f 100644 --- a/src/mscorlib/src/System/Security/Cryptography/rsa.cs +++ b/src/mscorlib/src/System/Security/Cryptography/rsa.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace System.Security.Cryptography { + using System.IO; using System.Text; using System.Runtime.Serialization; using System.Security.Util; @@ -27,17 +28,7 @@ namespace System.Security.Cryptography { [System.Runtime.InteropServices.ComVisible(true)] public abstract class RSA : AsymmetricAlgorithm { - // - // Extending this class allows us to know that you are really implementing - // an RSA key. This is required for anybody providing a new RSA key value - // implemention. - // - // The class provides no methods, fields or anything else. Its only purpose is - // as a heirarchy member for identification of algorithm. - // - protected RSA() { } - // // public methods // @@ -50,13 +41,188 @@ namespace System.Security.Cryptography { return (RSA) CryptoConfig.CreateFromName(algName); } - // Apply the private key to the data. This function represents a - // raw RSA operation -- no implicit depadding of the imput value - abstract public byte[] DecryptValue(byte[] rgb); +#if !FEATURE_CORECLR + // + // New RSA encrypt/decrypt/sign/verify RSA abstractions in .NET 4.6+ and .NET Core + // + // Methods that throw DerivedClassMustOverride are effectively abstract but we + // cannot mark them as such as it would be a breaking change. We'll make them + // abstract in .NET Core. + + public virtual byte[] Encrypt(byte[] data, RSAEncryptionPadding padding) { + throw DerivedClassMustOverride(); + } + + public virtual byte[] Decrypt(byte[] data, RSAEncryptionPadding padding) { + throw DerivedClassMustOverride(); + } + + public virtual byte[] SignHash(byte[] hash, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + throw DerivedClassMustOverride(); + } + + public virtual bool VerifyHash(byte[] hash, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + throw DerivedClassMustOverride(); + } + + protected virtual byte[] HashData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm) { + throw DerivedClassMustOverride(); + } + + protected virtual byte[] HashData(Stream data, HashAlgorithmName hashAlgorithm) { + throw DerivedClassMustOverride(); + } + + public byte[] SignData(byte[] data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + return SignData(data, 0, data.Length, hashAlgorithm, padding); + } + + public virtual byte[] SignData(byte[] data, int offset, int count, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + if (offset < 0 || offset > data.Length) { + throw new ArgumentOutOfRangeException("offset"); + } + if (count < 0 || count > data.Length - offset) { + throw new ArgumentOutOfRangeException("count"); + } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { + throw HashAlgorithmNameNullOrEmpty(); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + + byte[] hash = HashData(data, offset, count, hashAlgorithm); + return SignHash(hash, hashAlgorithm, padding); + } + + public virtual byte[] SignData(Stream data, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { + throw HashAlgorithmNameNullOrEmpty(); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + + byte[] hash = HashData(data, hashAlgorithm); + return SignHash(hash, hashAlgorithm, padding); + } + + public bool VerifyData(byte[] data, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + return VerifyData(data, 0, data.Length, signature, hashAlgorithm, padding); + } + + public virtual bool VerifyData(byte[] data, int offset, int count, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + if (offset < 0 || offset > data.Length) { + throw new ArgumentOutOfRangeException("offset"); + } + if (count < 0 || count > data.Length - offset) { + throw new ArgumentOutOfRangeException("count"); + } + if (signature == null) { + throw new ArgumentNullException("signature"); + } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { + throw HashAlgorithmNameNullOrEmpty(); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + + byte[] hash = HashData(data, offset, count, hashAlgorithm); + return VerifyHash(hash, signature, hashAlgorithm, padding); + } + + public bool VerifyData(Stream data, byte[] signature, HashAlgorithmName hashAlgorithm, RSASignaturePadding padding) { + if (data == null) { + throw new ArgumentNullException("data"); + } + if (signature == null) { + throw new ArgumentNullException("signature"); + } + if (String.IsNullOrEmpty(hashAlgorithm.Name)) { + throw HashAlgorithmNameNullOrEmpty(); + } + if (padding == null) { + throw new ArgumentNullException("padding"); + } + + byte[] hash = HashData(data, hashAlgorithm); + return VerifyHash(hash, signature, hashAlgorithm, padding); + } + + private static Exception DerivedClassMustOverride() { + return new NotImplementedException(Environment.GetResourceString("NotSupported_SubclassOverride")); + } + + internal static Exception HashAlgorithmNameNullOrEmpty() { + return new ArgumentException(Environment.GetResourceString("Cryptography_HashAlgorithmNameNullOrEmpty"), "hashAlgorithm"); + } +#endif + + // + // Legacy encrypt/decrypt RSA abstraction from .NET < 4.6 + // + // These should be obsolete, but we can't mark them as such here due to rules around not introducing + // source breaks to scenarios that compile against the GAC. + // + // They used to be abstract, but the only concrete implementation in RSACryptoServiceProvider threw + // NotSupportedException! This has been moved up to the base so all subclasses can ignore them moving forward. + // They will also be removed from .NET Core altogether. + // + // The original intent was for these to perform the RSA algorithm without padding/depadding. This can + // be seen by how the RSAXxx(De)Formatter classes call them in the non-RSACryptoServiceProvider case -- + // they do the padding/depadding in managed code. + // + // Unfortunately, these formatter classes are still incompatible with RSACng or any derived class that does not + // implement EncryptValue, DecryptValue as the formatters speculatively expected non-RSACryptoServiceProvider + // to do. That needs to be fixed in a subsequent release. We can still do it as it would move an exception to a + // correct result... + // + + // [Obsolete] + public virtual byte[] DecryptValue(byte[] rgb) { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_Method")); + } + + // [Obsolete] + public virtual byte[] EncryptValue(byte[] rgb) { + throw new NotSupportedException(Environment.GetResourceString("NotSupported_Method")); + } + + // + // These should also be obsolete (on the base). They aren't well defined nor are they used + // anywhere in the FX apart from checking that they're not null. + // + // For new derived RSA classes, we'll just return "RSA" which is analagous to what ECDsa + // and ECDiffieHellman do. + // + // Note that for compat, RSACryptoServiceProvider still overrides and returns RSA-PKCS1-KEYEX + // and http://www.w3.org/2000/09/xmldsig#rsa-sha1 + // + + public override string KeyExchangeAlgorithm { + get { return "RSA"; } + } + + public override string SignatureAlgorithm { + get { return "RSA"; } + } - // Apply the public key to the data. Again, this is a raw operation, no - // automatic padding. - abstract public byte[] EncryptValue(byte[] rgb); // Import/export functions diff --git a/src/mscorlib/src/mscorlib.txt b/src/mscorlib/src/mscorlib.txt index e287368297..96f2855ad3 100644 --- a/src/mscorlib/src/mscorlib.txt +++ b/src/mscorlib/src/mscorlib.txt @@ -1,4 +1,4 @@ -;==++== +;==++== ; ; Copyright (c) Microsoft Corporation. All rights reserved. ; @@ -946,6 +946,7 @@ Cryptography_CSP_NoPrivateKey = Object contains only the public half of a key pa Cryptography_CSP_OFBNotSupported = Output feedback mode (OFB) is not supported by this implementation. Cryptography_CSP_WrongKeySpec = The specified cryptographic service provider (CSP) does not support this key algorithm. Cryptography_HashNameSet = Hash name cannot be changed after the first write to the stream. +Cryptography_HashAlgorithmNameNullOrEmpty = The hash algorithm name cannot be null or empty. Cryptography_InvalidHashSize = {0} algorithm hash size is {1} bytes. Cryptography_InvalidKey_Weak = Specified key is a known weak key for '{0}' and cannot be used. Cryptography_InvalidKey_SemiWeak = Specified key is a known semi-weak key for '{0}' and cannot be used. @@ -1311,7 +1312,7 @@ IsolatedStorage_StoreNotOpen = Store must be open for this operation. IsolatedStorage_OldQuotaLarger = The new quota must be larger than the old quota. IsolatedStorage_UsageWillExceedQuota = There is not enough free space to perform the operation. IsolatedStorage_NotValidOnDesktop = The Site scope is currently not supported. -IsolatedStorage_OnlyIncreaseUserApplicationStore = Increasing the quota of this scope is not supported. Only the user application scope’s quota can be increased. +IsolatedStorage_OnlyIncreaseUserApplicationStore = Increasing the quota of this scope is not supported. Only the user application scope’s quota can be increased. #endif // FEATURE_ISOSTORE ; Verification Exception @@ -2655,13 +2656,13 @@ Globalization.ci_fr-BE = French (Belgium) Globalization.ci_fr-BF = French (Burkina Faso) Globalization.ci_fr-BI = French (Burundi) Globalization.ci_fr-BJ = French (Benin) -Globalization.ci_fr-BL = French (Saint Barth‚lemy) +Globalization.ci_fr-BL = French (Saint Barth‚lemy) Globalization.ci_fr-CA = French (Canada) Globalization.ci_fr-CD = French (Congo DRC) Globalization.ci_fr-CF = French (Central African Republic) Globalization.ci_fr-CG = French (Congo) Globalization.ci_fr-CH = French (Switzerland) -Globalization.ci_fr-CI = French (Côte d’Ivoire) +Globalization.ci_fr-CI = French (Côte d’Ivoire) Globalization.ci_fr-CM = French (Cameroon) Globalization.ci_fr-DJ = French (Djibouti) Globalization.ci_fr-DZ = French (Algeria) @@ -2883,9 +2884,9 @@ Globalization.ci_my = Burmese Globalization.ci_my-MM = Burmese (Myanmar) Globalization.ci_naq = Nama Globalization.ci_naq-NA = Nama (Namibia) -Globalization.ci_nb = Norwegian (Bokmål) -Globalization.ci_nb-NO = Norwegian, Bokmål (Norway) -Globalization.ci_nb-SJ = Norwegian, Bokmål (Svalbard and Jan Mayen) +Globalization.ci_nb = Norwegian (BokmÃ¥l) +Globalization.ci_nb-NO = Norwegian, BokmÃ¥l (Norway) +Globalization.ci_nb-SJ = Norwegian, BokmÃ¥l (Svalbard and Jan Mayen) Globalization.ci_nd = North Ndebele Globalization.ci_nd-ZW = North Ndebele (Zimbabwe) Globalization.ci_ne = Nepali @@ -2895,7 +2896,7 @@ Globalization.ci_nl = Dutch Globalization.ci_nl-AW = Dutch (Aruba) Globalization.ci_nl-BE = Dutch (Belgium) Globalization.ci_nl-BQ = Dutch (Bonaire, Sint Eustatius and Saba) -Globalization.ci_nl-CW = Dutch (Curaçao) +Globalization.ci_nl-CW = Dutch (Curaçao) Globalization.ci_nl-NL = Dutch (Netherlands) Globalization.ci_nl-SR = Dutch (Suriname) Globalization.ci_nl-SX = Dutch (Sint Maarten) @@ -2944,7 +2945,7 @@ Globalization.ci_pt-GW = Portuguese (Guinea-Bissau) Globalization.ci_pt-MO = Portuguese (Macao SAR) Globalization.ci_pt-MZ = Portuguese (Mozambique) Globalization.ci_pt-PT = Portuguese (Portugal) -Globalization.ci_pt-ST = Portuguese (São Tomé and Príncipe) +Globalization.ci_pt-ST = Portuguese (São Tomé and PrÃncipe) Globalization.ci_pt-TL = Portuguese (Timor-Leste) Globalization.ci_qps-ploc = Pseudo Language (Pseudo) Globalization.ci_qps-ploca = Pseudo Language (Pseudo Asia) @@ -3055,7 +3056,7 @@ Globalization.ci_st = Southern Sotho Globalization.ci_st-LS = Sesotho (Lesotho) Globalization.ci_st-ZA = Southern Sotho (South Africa) Globalization.ci_sv = Swedish -Globalization.ci_sv-AX = Swedish (land Islands) +Globalization.ci_sv-AX = Swedish (Ã…land Islands) Globalization.ci_sv-FI = Swedish (Finland) Globalization.ci_sv-SE = Swedish (Sweden) Globalization.ci_sw = Kiswahili @@ -3131,8 +3132,8 @@ Globalization.ci_ve = Venda Globalization.ci_ve-ZA = Venda (South Africa) Globalization.ci_vi = Vietnamese Globalization.ci_vi-VN = Vietnamese (Vietnam) -Globalization.ci_vo = Volapk -Globalization.ci_vo-001 = Volapk (World) +Globalization.ci_vo = Volapük +Globalization.ci_vo-001 = Volapük (World) Globalization.ci_vun = Vunjo Globalization.ci_vun-TZ = Vunjo (Tanzania) Globalization.ci_wae = Walser |