AWS Lambda not generating same HMAC as client (NET CORE 2.1)

0

I used the below code to generate a HMAC (signed hash) token on a client and again within a Lambda function to validate.

On my client app (.NET Core 2.1), it works fine. It both generates a HMAC token and it validates perfectly.

Put the same code in a Lambda and an issue arises. When the generated string is set to a Lambda endpoint, it always validates false. I even sent the string back to the client and once again, it validated fine.

Its almost as if there were a bug in the Lambda implementation of Net Core.

private static string GenerateHMAC(string password, string challenge)
{
HMACSHA256 hmc = new HMACSHA256(Encoding.UTF8.GetBytes(password));
byte[] hmres = hmc.ComputeHash(Encoding.UTF8.GetBytes(challenge));
string hmac = ByteToString(hmres);//
Console.WriteLine(hmac);
return hmac;
}

    private static bool ValidateHMAC(string password, string challenge, string suppliedHMAC)  
    {  
        HMACSHA256 hmc = new HMACSHA256(Encoding.UTF8.GetBytes(password));  
        byte\[] hmres = hmc.ComputeHash(Encoding.UTF8.GetBytes(challenge));  
        string hmac = ByteToString(hmres);//  
        Console.WriteLine(hmac);  

        if (suppliedHMAC == hmac)  
            return true;  
        else  
            return false;  
    }  

    public static string ByteToString(byte\[] buff)  
    {  
        string sbinary = "";  

        for (int i = 0; i < buff.Length; i++)  
        {  
            sbinary += buff\[i].ToString("X2"); // hex format  
        }  
        return (sbinary);  
    }
mmcc
asked 5 years ago425 views
4 Answers
0

I'm not able to reproduce any problem. I took your code and wrapped into a Lambda function like this and it returns true. Is there any more information you can give to help reproduce your issue.

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

using Amazon.Lambda.Core;

// Assembly attribute to enable the Lambda function's JSON input to be converted into a .NET class.
[assembly: LambdaSerializer(typeof(Amazon.Lambda.Serialization.Json.JsonSerializer))]

namespace LambdaHmacTest
{
    public class Function
    {
        
        public bool FunctionHandler(ILambdaContext context)
        {
            var password = "foobar";
            var challenge = "this is a test";

            var hmac = GenerateHMAC(password, challenge);
            context.Logger.LogLine($"Password: {password}, Challenge: {challenge}, Hmac: {hmac}");
            var validate = ValidateHMAC(password, challenge, hmac);
            context.Logger.LogLine($"IsValid: {validate}");


            return validate;
        }

        private static string GenerateHMAC(string password, string challenge)
        {
            HMACSHA256 hmc = new HMACSHA256(Encoding.UTF8.GetBytes(password));
            byte[] hmres = hmc.ComputeHash(Encoding.UTF8.GetBytes(challenge));
            string hmac = ByteToString(hmres);//
            Console.WriteLine(hmac);
            return hmac;
        }

        private static bool ValidateHMAC(string password, string challenge, string suppliedHMAC)
        {
            HMACSHA256 hmc = new HMACSHA256(Encoding.UTF8.GetBytes(password));
            byte[] hmres = hmc.ComputeHash(Encoding.UTF8.GetBytes(challenge));
            string hmac = ByteToString(hmres);//
            Console.WriteLine(hmac);

            if (suppliedHMAC == hmac)
                return true;
            else
                return false;
        }

        public static string ByteToString(byte[] buff)
        {
            string sbinary = "";

            for (int i = 0; i < buff.Length; i++)
            {
                sbinary += buff[i].ToString("X2"); // hex format
            }
            return (sbinary);
        }
    }
}
AWS
Norm
answered 5 years ago
0

Generate the HMAC on a client, pass the string to the Lambda endpoint (UTF8), then try to recreate the HMAC. I am getting different bytes, hence a different HMAC.

mmcc
answered 5 years ago
0

This is the code I use to generate the token client side. When the HMAC is validated in the Lambda, it will fail. If I do it locally, it works fine.

private static bool TestUnit()
        {
            
            Console.WriteLine("Beginning test of endpoint ");
            string url = "replace with endpoint url";

            MyRequest mr = new MyRequest();
            cr.Role = Roles.Unit;  //0 indexed enum
            cr.Timestamp = DateTime.UtcNow;
            cr.UnitId = Guid.NewGuid();
            cr.HMAC = GenerateHMAC(hmacSecret, cr.UnitId.ToString() + cr.Timestamp.ToString() + (int)cr.Role);

            HttpClient client = new HttpClient();
            //client.DefaultRequestHeaders.Add("x-api-key", "add api key");

            string jsonObject = JsonConvert.SerializeObject(cr);
            var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");

            try
            {
                var result = client.PostAsync(url, content).Result;
                Console.WriteLine(result);
                Console.WriteLine(result.Content.ReadAsStringAsync().Result);

                Console.WriteLine();
                Console.WriteLine("Ending test of endpoint Create");
                return true;
            }
            catch(Exception ex)
            {
                Console.WriteLine(ex.Message);
                return false;
            }
        }
		
		
[Serializable]
    public enum Roles
    {
        Unit = 0,
        SmallUnit,
        BigUnit,
    }

    public class MyRequest
    {
        public string HMAC { get; set; }
        public Roles Role { get; set; }
        public Guid UnitId { get; set; }
        public DateTime Timestamp { get; set; }
    }
mmcc
answered 5 years ago
0

I think I found the issue. The DateTime format is different between the client and server. Defining a format resolves the issue.

string format = "MMM ddd d HH:mm yyyy";

This can be passed as a variable to the .ToString(format) method of DateTime object.

mmcc
answered 5 years ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions