< Summary - CoreWCF Coverage — PR #1766

Information
Class: CoreWCF.IdentityModel.CryptoHelper
Assembly: CoreWCF.Primitives
File(s): /home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/CryptoHelper.cs
Line coverage
38%
Covered lines: 54
Uncovered lines: 88
Coverable lines: 142
Total lines: 455
Line coverage: 38%
Branch coverage
20%
Covered branches: 50
Total branches: 250
Branch coverage: 20%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

/home/runner/work/CoreWCF/CoreWCF/src/CoreWCF.Primitives/src/CoreWCF/IdentityModel/CryptoHelper.cs

#LineLine coverage
 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
 4using System;
 5using System.Collections.Generic;
 6using System.Reflection;
 7using System.Security.Cryptography;
 8using CoreWCF.IdentityModel.Tokens;
 9using Linq = System.Linq;
 10
 11namespace CoreWCF.IdentityModel
 12{
 13    internal static class CryptoHelper
 14    {
 15        private static RandomNumberGenerator s_random;
 16        private const string SHAString = "SHA";
 17        private const string SHA1String = "SHA1";
 18        private const string SHA256String = "SHA256";
 19        private const string SystemSecurityCryptographySha1String = "System.Security.Cryptography.SHA1";
 20        private static byte[] s_emptyBuffer;
 21
 222        private static readonly Dictionary<string, Func<object>> s_algorithmDelegateDictionary = new Dictionary<string, 
 223        private static readonly object s_algorithmDictionaryLock = new object();
 24
 25        internal static byte[] EmptyBuffer
 26        {
 27            get
 28            {
 2329                if (s_emptyBuffer == null)
 30                {
 231                    byte[] tmp = Array.Empty<byte>();
 232                    s_emptyBuffer = tmp;
 33                }
 2334                return s_emptyBuffer;
 35            }
 36        }
 37
 38        public static byte[] GenerateSymmetricKey(int keySizeInBits)
 39        {
 040            int keySizeInBytes = ValidateKeySizeInBytes(keySizeInBits);
 041            byte[] key = new byte[keySizeInBytes];
 042            CryptoHelper.GenerateRandomBytes(key);
 043            return key;
 44        }
 45
 46        private static int ValidateKeySizeInBytes(int keySizeInBits)
 47        {
 048            int keySizeInBytes = keySizeInBits / 8;
 49
 050            if (keySizeInBits <= 0)
 51            {
 052                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(keySize
 53            }
 054            else if (keySizeInBytes * 8 != keySizeInBits)
 55            {
 056                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format(SR.ID6002, key
 57            }
 58
 059            return keySizeInBytes;
 60        }
 61
 62        internal static void ValidateBufferBounds(Array buffer, int offset, int count)
 63        {
 064            if (buffer == null)
 65            {
 066                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(buffer)));
 67            }
 068            if (count < 0 || count > buffer.Length)
 69            {
 070                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(count),
 71            }
 072            if (offset < 0 || offset > buffer.Length - count)
 73            {
 074                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(offset)
 75            }
 076        }
 77
 78        public static bool FixedTimeEquals(byte[] a, byte[] b)
 79        {
 080            if (a == null && b == null)
 81            {
 082                return true;
 83            }
 084            else if (a == null || b == null)
 85            {
 086                return false;
 87            }
 088            else if (a.Length != b.Length)
 89            {
 090                return false;
 91            }
 92
 093            int result = 0;
 094            int length = a.Length;
 95
 096            for (int i = 0; i < length; i++)
 97            {
 098                result |= a[i] ^ b[i];
 99            }
 100
 0101            return result == 0;
 102        }
 103
 104        internal static byte[] UnwrapKey(byte[] wrappingKey, byte[] wrappedKey, string algorithm)
 105        {
 0106            throw new PlatformNotSupportedException();
 107        }
 108
 109        internal static byte[] WrapKey(byte[] wrappingKey, byte[] keyToBeWrapped, string algorithm)
 110        {
 0111            throw new PlatformNotSupportedException();
 112        }
 113
 114        internal static byte[] GenerateDerivedKey(byte[] key, string algorithm, byte[] label, byte[] nonce, int derivedK
 115        {
 0116            throw new PlatformNotSupportedException();
 117        }
 118
 119        internal static int GetIVSize(string algorithm)
 120        {
 0121            throw new PlatformNotSupportedException();
 122        }
 123
 124        internal static ICryptoTransform CreateDecryptor(byte[] key, byte[] iv, string algorithm)
 125        {
 0126            throw new PlatformNotSupportedException();
 127        }
 128
 129        internal static ICryptoTransform CreateEncryptor(byte[] key, byte[] iv, string algorithm)
 130        {
 0131            throw new PlatformNotSupportedException();
 132        }
 133
 134        internal static KeyedHashAlgorithm CreateKeyedHashAlgorithm(byte[] key, string algorithm)
 135        {
 30136            object algorithmObject = GetAlgorithmFromConfig(algorithm);
 137
 30138            if (algorithmObject != null)
 139            {
 30140                if (algorithmObject is KeyedHashAlgorithm keyedHashAlgorithm)
 141                {
 30142                    keyedHashAlgorithm.Key = key;
 30143                    return keyedHashAlgorithm;
 144                }
 145
 0146                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.Format("Cus
 147            }
 148
 149            switch (algorithm)
 150            {
 151                case SecurityAlgorithms.HmacSha1Signature:
 0152                    return new HMACSHA1(key);
 153                case SecurityAlgorithms.HmacSha256Signature:
 0154                    return new HMACSHA256(key);
 155                default:
 0156                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.Format(
 157            }
 158        }
 159
 160        internal static SymmetricAlgorithm GetSymmetricAlgorithm(byte[] key, string algorithm)
 161        {
 0162            throw new PlatformNotSupportedException();
 163        }
 164
 165        internal static bool IsSymmetricSupportedAlgorithm(string algorithm, int keySize)
 166        {
 20167            bool found = false;
 20168            object algorithmObject = null;
 169
 170            try
 171            {
 20172                algorithmObject = GetAlgorithmFromConfig(algorithm);
 20173            }
 0174            catch (InvalidOperationException)
 175            {
 176                // We swallow the exception and continue.
 0177            }
 20178            if (algorithmObject != null)
 179            {
 20180                SymmetricAlgorithm symmetricAlgorithm = algorithmObject as SymmetricAlgorithm;
 20181                KeyedHashAlgorithm keyedHashAlgorithm = algorithmObject as KeyedHashAlgorithm;
 182
 20183                if (symmetricAlgorithm != null || keyedHashAlgorithm != null)
 184                {
 20185                    found = true;
 186                }
 187                // The reason we do not return here even when the user has provided a custom algorithm to CryptoConfig
 188                // is because we need to check if the user has overwritten an existing standard URI.
 189            }
 190
 191            switch (algorithm)
 192            {
 193                case SecurityAlgorithms.DsaSha1Signature:
 194                case SecurityAlgorithms.RsaSha1Signature:
 195                case SecurityAlgorithms.RsaSha256Signature:
 196                case SecurityAlgorithms.RsaOaepKeyWrap:
 197                case SecurityAlgorithms.RsaV15KeyWrap:
 0198                    return false;
 199                case SecurityAlgorithms.HmacSha1Signature:
 200                case SecurityAlgorithms.HmacSha256Signature:
 201                case SecurityAlgorithms.Psha1KeyDerivation:
 202                case SecurityAlgorithms.Psha1KeyDerivationDec2005:
 20203                    return true;
 204                case SecurityAlgorithms.Aes128Encryption:
 205                case SecurityAlgorithms.Aes128KeyWrap:
 0206                    return keySize >= 128 && keySize <= 256;
 207                case SecurityAlgorithms.Aes192Encryption:
 208                case SecurityAlgorithms.Aes192KeyWrap:
 0209                    return keySize >= 192 && keySize <= 256;
 210                case SecurityAlgorithms.Aes256Encryption:
 211                case SecurityAlgorithms.Aes256KeyWrap:
 0212                    return keySize == 256;
 213                case SecurityAlgorithms.TripleDesEncryption:
 214                case SecurityAlgorithms.TripleDesKeyWrap:
 0215                    return keySize == 128 || keySize == 192;
 216                default:
 0217                    if (found)
 218                    {
 0219                        return true;
 220                    }
 221
 0222                    return false;
 223                    // We do not expect the user to map the uri of an existing standrad algorithm with say key size 128 
 224                    // to a custom algorithm with keySize 192 bits. If he does that, we anyways make sure that we return
 225            }
 226        }
 227
 228        internal static void FillRandomBytes(byte[] buffer)
 229        {
 0230            RandomNumberGenerator.GetBytes(buffer);
 0231        }
 232
 233        /// <summary>
 234        /// This generates the entropy using random number. This is usually used on the sending
 235        /// side to generate the requestor's entropy.
 236        /// </summary>
 237        /// <param name="data">The array to fill with cryptographically strong random nonzero bytes.</param>
 238        public static void GenerateRandomBytes(byte[] data)
 239        {
 0240            RandomNumberGenerator.GetNonZeroBytes(data);
 0241        }
 242
 243        /// <summary>
 244        /// This method generates a random byte array used as entropy with the given size.
 245        /// </summary>
 246        /// <param name="sizeInBits"></param>
 247        /// <returns></returns>
 248        public static byte[] GenerateRandomBytes(int sizeInBits)
 249        {
 0250            int sizeInBytes = sizeInBits / 8;
 0251            if (sizeInBits <= 0)
 252            {
 0253                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(sizeInB
 254            }
 0255            else if (sizeInBytes * 8 != sizeInBits)
 256            {
 0257                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentException(SR.Format("ID6002", size
 258            }
 259
 0260            byte[] data = new byte[sizeInBytes];
 0261            GenerateRandomBytes(data);
 262
 0263            return data;
 264        }
 265
 266        internal static RandomNumberGenerator RandomNumberGenerator
 267        {
 268            get
 269            {
 0270                if (s_random == null)
 271                {
 0272                    s_random = RandomNumberGenerator.Create();
 273                }
 0274                return s_random;
 275            }
 276        }
 277
 278        internal static HashAlgorithm CreateHashAlgorithm(string algorithm)
 279        {
 23280            object algorithmObject = GetAlgorithmFromConfig(algorithm);
 281
 23282            if (algorithmObject != null)
 283            {
 23284                if (algorithmObject is HashAlgorithm hashAlgorithm)
 285                {
 23286                    return hashAlgorithm;
 287                }
 0288                throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.Format(SR.C
 289            }
 290
 291            switch (algorithm)
 292            {
 293                case SHAString:
 294                case SHA1String:
 295                case SystemSecurityCryptographySha1String:
 296                case SecurityAlgorithms.Sha1Digest:
 0297                    return SHA1.Create();
 298                case SHA256String:
 299                case SecurityAlgorithms.Sha256Digest:
 0300                    return SHA256.Create();
 301                default:
 0302                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperWarning(new InvalidOperationException(SR.Format(
 303            }
 304        }
 305
 306        private static object GetDefaultAlgorithm(string algorithm)
 307        {
 4308            if (string.IsNullOrEmpty(algorithm))
 309            {
 0310                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(algorithm)));
 311            }
 312
 313            switch (algorithm)
 314            {
 315                //case SecurityAlgorithms.RsaSha1Signature:
 316                //case SecurityAlgorithms.DsaSha1Signature:
 317                // For these algorithms above, crypto config returns internal objects.
 318                // As we cannot create those internal objects, we are returning null.
 319                // If no custom algorithm is plugged-in, at least these two algorithms
 320                // will be inside the delegate dictionary.
 321                case SecurityAlgorithms.Sha1Digest:
 2322                    return SHA1.Create();
 323                case SecurityAlgorithms.ExclusiveC14n:
 0324                    throw new PlatformNotSupportedException();
 325                case SHA256String:
 326                case SecurityAlgorithms.Sha256Digest:
 0327                    return SHA256.Create();
 328                case SecurityAlgorithms.Sha512Digest:
 0329                    return SHA512.Create();
 330                case SecurityAlgorithms.Aes128Encryption:
 331                case SecurityAlgorithms.Aes192Encryption:
 332                case SecurityAlgorithms.Aes256Encryption:
 333                case SecurityAlgorithms.Aes128KeyWrap:
 334                case SecurityAlgorithms.Aes192KeyWrap:
 335                case SecurityAlgorithms.Aes256KeyWrap:
 0336                    return Aes.Create();
 337                case SecurityAlgorithms.TripleDesEncryption:
 338                case SecurityAlgorithms.TripleDesKeyWrap:
 0339                    return TripleDES.Create();
 340                case SecurityAlgorithms.HmacSha1Signature:
 2341                    return new HMACSHA1();
 342                case SecurityAlgorithms.HmacSha256Signature:
 0343                    return new HMACSHA256();
 344                case SecurityAlgorithms.ExclusiveC14nWithComments:
 0345                    throw new PlatformNotSupportedException();
 346                case SecurityAlgorithms.Ripemd160Digest:
 0347                    return null;
 348                case SecurityAlgorithms.DesEncryption:
 0349                    return DES.Create();
 350                default:
 0351                    return null;
 352            }
 353        }
 354
 355        internal static object GetAlgorithmFromConfig(string algorithm)
 356        {
 79357            if (string.IsNullOrEmpty(algorithm))
 358            {
 0359                throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentNullException(nameof(algorithm)));
 360            }
 361
 79362            object algorithmObject = null;
 79363            object defaultObject = null;
 364
 79365            if (!s_algorithmDelegateDictionary.TryGetValue(algorithm, out Func<object> delegateFunction))
 366            {
 5367                lock (s_algorithmDictionaryLock)
 368                {
 5369                    if (!s_algorithmDelegateDictionary.ContainsKey(algorithm))
 370                    {
 371                        try
 372                        {
 5373                            algorithmObject = CryptoConfig.CreateFromName(algorithm);
 5374                        }
 0375                        catch (TargetInvocationException)
 376                        {
 0377                            s_algorithmDelegateDictionary[algorithm] = null;
 0378                        }
 379
 5380                        if (algorithmObject == null)
 381                        {
 1382                            s_algorithmDelegateDictionary[algorithm] = null;
 383                        }
 384                        else
 385                        {
 4386                            defaultObject = GetDefaultAlgorithm(algorithm);
 4387                            if (defaultObject != null && defaultObject.GetType() == algorithmObject.GetType())
 388                            {
 2389                                s_algorithmDelegateDictionary[algorithm] = null;
 390                            }
 391                            else
 392                            {
 393                                // Create a factory delegate which returns new instances of the algorithm type for later
 2394                                Type algorithmType = algorithmObject.GetType();
 2395                                System.Linq.Expressions.NewExpression algorithmCreationExpression = Linq.Expressions.Exp
 2396                                Linq.Expressions.LambdaExpression creationFunction = Linq.Expressions.Expression.Lambda<
 2397                                delegateFunction = creationFunction.Compile() as Func<object>;
 398
 2399                                if (delegateFunction != null)
 400                                {
 2401                                    s_algorithmDelegateDictionary[algorithm] = delegateFunction;
 402                                }
 2403                                return algorithmObject;
 404                            }
 405                        }
 406                    }
 0407                }
 408            }
 409            else
 410            {
 74411                if (delegateFunction != null)
 412                {
 21413                    return delegateFunction.Invoke();
 414                }
 415            }
 416
 417            //
 418            // This is a fallback in case CryptoConfig fails to return a valid
 419            // algorithm object. CrytoConfig does not understand all the uri's and
 420            // can return a null in that case, in which case it is our responsibility
 421            // to fallback and create the right algorithm if it is a uri we understand
 422            //
 423            switch (algorithm)
 424            {
 425                case SHA256String:
 426                case SecurityAlgorithms.Sha256Digest:
 0427                    return SHA256.Create();
 428                case SecurityAlgorithms.Sha1Digest:
 0429                    return SHA1.Create();
 430                case SecurityAlgorithms.HmacSha1Signature:
 53431                    return new HMACSHA1();
 432                default:
 433                    break;
 434            }
 435
 3436            return null;
 2437        }
 438
 439        internal static HashAlgorithm NewSha1HashAlgorithm()
 440        {
 0441            return CreateHashAlgorithm(SecurityAlgorithms.Sha1Digest);
 442        }
 443
 444        internal static HashAlgorithm NewSha256HashAlgorithm()
 445        {
 0446            return CreateHashAlgorithm(SecurityAlgorithms.Sha256Digest);
 447        }
 448
 449        internal static KeyedHashAlgorithm NewHmacSha1KeyedHashAlgorithm(byte[] key)
 450        {
 10451            return CreateKeyedHashAlgorithm(key, SecurityAlgorithms.HmacSha1Signature);
 452        }
 453    }
 454}
 455