internal static int ComputeTotp(
#if NET6_0_OR_GREATER
        byte[] key,
#else
        HashAlgorithm hashAlgorithm,
#endif
        ulong timestepNumber,
        string?modifier)
    {
        // # of 0's = length of pin
        const int Mod = 1000000;

        // See https://tools.ietf.org/html/rfc4226
        // We can add an optional modifier
        var timestepAsBytes = BitConverter.GetBytes(IPAddress.HostToNetworkOrder((long)timestepNumber));

#if NET6_0_OR_GREATER
        var hash = HMACSHA1.HashData(key, ApplyModifier(timestepAsBytes, modifier));
#else
        var hash = hashAlgorithm.ComputeHash(ApplyModifier(timestepAsBytes, modifier));
#endif

        // Generate DT string
        var offset = hash[hash.Length - 1] & 0xf;
        Debug.Assert(offset + 4 < hash.Length);
        var binaryCode = (hash[offset] & 0x7f) << 24
                         | (hash[offset + 1] & 0xff) << 16
                         | (hash[offset + 2] & 0xff) << 8
                         | (hash[offset + 3] & 0xff);

        return(binaryCode % Mod);
    }
Example #2
0
 protected override int HashDataOneShot(ReadOnlySpan <byte> key, Stream source, Span <byte> destination) =>
 HMACSHA1.HashData(key, source, destination);
Example #3
0
 protected override byte[] HashDataOneShot(byte[] key, Stream source) =>
 HMACSHA1.HashData(key, source);
Example #4
0
 protected override byte[] HashDataOneShot(ReadOnlySpan <byte> key, Stream source) =>
 HMACSHA1.HashData(key, source);
Example #5
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());
        }