Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# System.Security.Cryptography.HMACSHA1.ComputeHash() does not return expected result

I am trying to implement a OTP solution in C# based on RFC 4226: https://www.rfc-editor.org/rfc/rfc4226

I have found a sample implementation and it looks like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Security.Cryptography;

namespace OTP
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Text.UTF8Encoding encoding = new System.Text.UTF8Encoding();
            byte[] secretKey = encoding.GetBytes("12345678901234567890");
            byte[] counter = encoding.GetBytes("1");
            Console.WriteLine(CalculateHotp(secretKey, counter));
            Console.ReadKey();
        }

        public static int CalculateHotp(byte[] key, byte[] counter)
        {
            var hmacsha1 = new HMACSHA1(key);
            byte[] hmac_result = hmacsha1.ComputeHash(counter);
            int offset = hmac_result[19] & 0x0f;
            int bin_code = (hmac_result[offset] & 0x7f) << 24
                           | (hmac_result[offset + 1] & 0xff) << 16
                           | (hmac_result[offset + 2] & 0xff) << 8
                           | (hmac_result[offset + 3] & 0xff);
            int hotp = bin_code % 1000000;
            return hotp;
        }
    }
}

The problem is that the call:

byte[] hmac_result = hmacsha1.ComputeHash(counter);

does not return the expected result and thus the returned OTP will be wrong. Reading the RFC4226 appendix D (https://www.rfc-editor.org/rfc/rfc4226#appendix-D), there are some test values to use and the result wont match them:

From the RFC 4226, Appendix D:
The following test data uses the ASCII string
 "12345678901234567890" for the secret:

  Secret = 0x3132333435363738393031323334353637383930

  Table 1 details for each count, the intermediate HMAC value.

Count    Hexadecimal HMAC-SHA-1(secret, count)
0        cc93cf18508d94934c64b65d8ba7667fb7cde4b0
1        75a48a19d4cbe100644e8ac1397eea747a2d33ab
2        0bacb7fa082fef30782211938bc1c5e70416ff44
3        66c28227d03a2d5529262ff016a1e6ef76557ece
4        a904c900a64b35909874b33e61c5938a8e15ed1c
<snip>

Table 2 details for each count the truncated values (both in
hexadecimal and decimal) and then the HOTP value.

                  Truncated
Count    Hexadecimal    Decimal        HOTP
0        4c93cf18       1284755224     755224
1        41397eea       1094287082     287082
2         82fef30        137359152     359152
3        66ef7655       1726969429     969429
4        61c5938a       1640338314     338314
<snip>

Since I in my example above use "12345678901234567890" as key and "1" as counter, I would expect the result of ComputeHash() to be: 75a48a19d4cbe100644e8ac1397eea747a2d33ab and the OTP to be: 287082

But I get the OTP: 906627

I really cant see what I'm doing wrong here, has anyone successfully implemented a counter based OTP in C# using the HMACSHA1 class?

like image 330
Grovah Avatar asked May 04 '12 12:05

Grovah


People also ask

What C is used for?

C programming language is a machine-independent programming language that is mainly used to create many types of applications and operating systems such as Windows, and other complicated programs such as the Oracle database, Git, Python interpreter, and games and is considered a programming foundation in the process of ...

What is C full form?

Originally Answered: What is the full form of C ? C - Compiler . C is a general-purpose, high-level language that was originally developed by Dennis M. Ritchie to develop the UNIX operating system at Bell Labs. C was originally first implemented on the DEC PDP-11 computer in 1972.

How old is the letter C?

The letter c was applied by French orthographists in the 12th century to represent the sound ts in English, and this sound developed into the simpler sibilant s.

What is C in C language?

What is C? C is a general-purpose programming language created by Dennis Ritchie at the Bell Laboratories in 1972. It is a very popular language, despite being old. C is strongly associated with UNIX, as it was developed to write the UNIX operating system.


1 Answers

You use the counter incorrectly. The counter should not be an ASCII string, it should be a numeric (long) value in big-endian.

Use

var counter = new byte[] { 0, 0, 0, 0, 0, 0, 0, 1 };

for this test instead, and your code will return the correct OTP.

like image 87
Mormegil Avatar answered Sep 21 '22 00:09

Mormegil