Пример #1
0
        private static unsafe byte[] MacAndEncode(
            AsnWriter tmpWriter,
            ReadOnlyMemory <byte> encodedAuthSafe,
            ReadOnlySpan <char> passwordSpan)
        {
            const int   MacSize = 160 / 8; // HMAC-SHA1 is 160 bits.
            Span <byte> macKey  = stackalloc byte[MacSize];
            Span <byte> macSalt = stackalloc byte[MacSize];
            Span <byte> macSpan = stackalloc byte[MacSize];

            RandomNumberGenerator.Fill(macSalt);

            Pkcs12Kdf.DeriveMacKey(
                passwordSpan,
                HashAlgorithmName.SHA1,
                s_windowsPbe.IterationCount,
                macSalt,
                macKey);

            int bytesWritten = HMACSHA1.HashData(macKey, encodedAuthSafe.Span, macSpan);

            if (bytesWritten != MacSize)
            {
                Debug.Fail($"HMACSHA1.HashData wrote {bytesWritten} of {MacSize} bytes");
                throw new CryptographicException();
            }

            CryptographicOperations.ZeroMemory(macKey);

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // PFX ::= SEQUENCE {
            //   version    INTEGER {v3(3)}(v3,...),
            //   authSafe   ContentInfo,
            //   macData    MacData OPTIONAL
            // }
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);
            tmpWriter.PushSequence();

            tmpWriter.WriteInteger(3);

            tmpWriter.PushSequence();
            {
                tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data);

                tmpWriter.PushSequence(s_contextSpecific0);
                {
                    tmpWriter.WriteOctetString(encodedAuthSafe.Span);
                    tmpWriter.PopSequence(s_contextSpecific0);
                }

                tmpWriter.PopSequence();
            }

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // MacData ::= SEQUENCE {
            //   mac        DigestInfo,
            //   macSalt    OCTET STRING,
            //   iterations INTEGER DEFAULT 1
            //   -- Note: The default is for historical reasons and its use is
            //   -- deprecated.
            // }
            tmpWriter.PushSequence();
            {
                tmpWriter.PushSequence();
                {
                    tmpWriter.PushSequence();
                    {
                        tmpWriter.WriteObjectIdentifier(Oids.Sha1);
                        tmpWriter.PopSequence();
                    }

                    tmpWriter.WriteOctetString(macSpan);
                    tmpWriter.PopSequence();
                }

                tmpWriter.WriteOctetString(macSalt);
                tmpWriter.WriteInteger(s_windowsPbe.IterationCount);

                tmpWriter.PopSequence();
            }

            tmpWriter.PopSequence();
            return(tmpWriter.Encode());
        }
Пример #2
0
        internal bool VerifyMac(
            ReadOnlySpan <char> macPassword,
            ReadOnlySpan <byte> authSafeContents)
        {
            Debug.Assert(MacData.HasValue);

            HashAlgorithmName hashAlgorithm;
            int expectedOutputSize;

            string algorithmValue = MacData.Value.Mac.DigestAlgorithm.Algorithm;

            switch (algorithmValue)
            {
            case Oids.Md5:
                expectedOutputSize = 128 >> 3;
                hashAlgorithm      = HashAlgorithmName.MD5;
                break;

            case Oids.Sha1:
                expectedOutputSize = 160 >> 3;
                hashAlgorithm      = HashAlgorithmName.SHA1;
                break;

            case Oids.Sha256:
                expectedOutputSize = 256 >> 3;
                hashAlgorithm      = HashAlgorithmName.SHA256;
                break;

            case Oids.Sha384:
                expectedOutputSize = 384 >> 3;
                hashAlgorithm      = HashAlgorithmName.SHA384;
                break;

            case Oids.Sha512:
                expectedOutputSize = 512 >> 3;
                hashAlgorithm      = HashAlgorithmName.SHA512;
                break;

            default:
                throw new CryptographicException(
                          SR.Format(SR.Cryptography_UnknownHashAlgorithm, algorithmValue));
            }

            if (MacData.Value.Mac.Digest.Length != expectedOutputSize)
            {
                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
            }

#if NETCOREAPP
            Debug.Assert(expectedOutputSize <= 64); // SHA512 is the largest digest size we know about
            Span <byte> derived = stackalloc byte[expectedOutputSize];
#else
            byte[] derived = new byte[expectedOutputSize];
#endif


            int iterationCount =
                PasswordBasedEncryption.NormalizeIterationCount(MacData.Value.IterationCount);

            Pkcs12Kdf.DeriveMacKey(
                macPassword,
                hashAlgorithm,
                iterationCount,
                MacData.Value.MacSalt.Span,
                derived);

            using (IncrementalHash hmac = IncrementalHash.CreateHMAC(hashAlgorithm, derived))
            {
                hmac.AppendData(authSafeContents);

                if (!hmac.TryGetHashAndReset(derived, out int bytesWritten) || bytesWritten != expectedOutputSize)
                {
                    Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} bytes when {expectedOutputSize} was expected");
                    throw new CryptographicException();
                }

                return(CryptographicOperations.FixedTimeEquals(
                           derived,
                           MacData.Value.Mac.Digest.Span));
            }
        }
Пример #3
0
        private static unsafe byte[] MacAndEncode(
            AsnWriter tmpWriter,
            ReadOnlyMemory <byte> encodedAuthSafe,
            ReadOnlySpan <char> passwordSpan)
        {
            // Windows/macOS compatibility: Use HMAC-SHA-1,
            // other algorithms may not be understood
            byte[]            macKey        = new byte[20];
            Span <byte>       macSalt       = stackalloc byte[20];
            Span <byte>       macSpan       = stackalloc byte[20];
            HashAlgorithmName hashAlgorithm = HashAlgorithmName.SHA1;

            RandomNumberGenerator.Fill(macSalt);

            fixed(byte *macKeyPtr = macKey)
            {
                Span <byte> macKeySpan = macKey;

                Pkcs12Kdf.DeriveMacKey(
                    passwordSpan,
                    hashAlgorithm,
                    s_windowsPbe.IterationCount,
                    macSalt,
                    macKeySpan);

                using (IncrementalHash mac = IncrementalHash.CreateHMAC(hashAlgorithm, macKey))
                {
                    mac.AppendData(encodedAuthSafe.Span);

                    if (!mac.TryGetHashAndReset(macSpan, out int bytesWritten) || bytesWritten != macSpan.Length)
                    {
                        Debug.Fail($"TryGetHashAndReset wrote {bytesWritten} of {macSpan.Length} bytes");
                        throw new CryptographicException();
                    }
                }

                CryptographicOperations.ZeroMemory(macKeySpan);
            }

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // PFX ::= SEQUENCE {
            //   version    INTEGER {v3(3)}(v3,...),
            //   authSafe   ContentInfo,
            //   macData    MacData OPTIONAL
            // }
            Debug.Assert(tmpWriter.GetEncodedLength() == 0);
            tmpWriter.PushSequence();

            tmpWriter.WriteInteger(3);

            tmpWriter.PushSequence();
            {
                tmpWriter.WriteObjectIdentifier(Oids.Pkcs7Data);

                tmpWriter.PushSequence(s_contextSpecific0);
                {
                    tmpWriter.WriteOctetString(encodedAuthSafe.Span);
                    tmpWriter.PopSequence(s_contextSpecific0);
                }

                tmpWriter.PopSequence();
            }

            // https://tools.ietf.org/html/rfc7292#section-4
            //
            // MacData ::= SEQUENCE {
            //   mac        DigestInfo,
            //   macSalt    OCTET STRING,
            //   iterations INTEGER DEFAULT 1
            //   -- Note: The default is for historical reasons and its use is
            //   -- deprecated.
            // }
            tmpWriter.PushSequence();
            {
                tmpWriter.PushSequence();
                {
                    tmpWriter.PushSequence();
                    {
                        tmpWriter.WriteObjectIdentifier(Oids.Sha1);
                        tmpWriter.PopSequence();
                    }

                    tmpWriter.WriteOctetString(macSpan);
                    tmpWriter.PopSequence();
                }

                tmpWriter.WriteOctetString(macSalt);
                tmpWriter.WriteInteger(s_windowsPbe.IterationCount);

                tmpWriter.PopSequence();
            }

            tmpWriter.PopSequence();
            return(tmpWriter.Encode());
        }