0

I am trying to create a base64 hmac for sha256. I have two codes for the same, one in JS and other in Java,though I am doing it in android and a kotlin one will help me as well. I have mostly used codes from other SO answers only. The one in node js seems to give correct results and matches with the backend but in java is does not. Here are the codes

const crypto = require('crypto')
const base64urlm = require('base64url')
console.log('hello')

var yourMessage = 'Pritish8-s9';
var sharedSecret = 'Nilesh/ev12/';
//generate hmac sha256 hash
var hmacSignature = crypto.createHmac('SHA256', new Buffer(sharedSecret, 'base64')).update(yourMessage).digest('base64');
hmacSignature = base64urlm.fromBase64(hmacSignature)
console.log(hmacSignature)

It gives the output as

_eiq1peyHuPx8yQwzORwoT7wcNdzv2Y0LUp_E70aIvM

The above is the correct value. Now following is the java code.

 package com.drivertest.hmactest;


import android.util.Log;

import org.apache.commons.codec.binary.Hex;

import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;

public class HMAC {
    public static String cal() {
        try {
            String secret = "Nilesh/ev12/";
            String message = "Pritish8-s9";

            byte[] secretByteArray = new byte[0];
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                secretByteArray = Base64.getEncoder().encode(secret.getBytes());
            }

            //byte[] secretByteArray = Base64.encodeBase64(secret.getBytes("utf-8"), true);

            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secretByteArray, "HmacSHA256");
            sha256_HMAC.init(secret_key);

            String hash = null;
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                hash = Base64.getEncoder().encodeToString(sha256_HMAC.doFinal(message.getBytes()));
            }
            System.out.println("hash "+hash);
            Log.d("++++",hash);
            return hash;
        }
        catch (Exception e){
            System.out.println("Error");
        }
        return "";
    }
    public static String encode(String key, String data) {
        try {
            String secret = "Nilesh/ev12/";
            String message = "Pritish8-s9";
            key=secret;
            data=message;
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
            sha256_HMAC.init(secret_key);


            SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secretKey);
            String hash = android.util.Base64.encodeToString(sha256_HMAC.doFinal(message.getBytes()), android.util.Base64.DEFAULT);
            Log.d("++",hash);




            return Hex.encodeHexString(sha256_HMAC.doFinal(data.getBytes(StandardCharsets.UTF_8)));

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }

        return null;
    }
}

It is a class where I have attempted to do it in different ways with other SO answers. Unfortunately I get a value like

8i/ce0u0GZ+JhL3yblsGhaMnFC0UKkUwJSQSXZ3536s=

or

f22fdc7b4bb4199f8984bdf26e5b0685a327142d142a45302524125d9df9dfab

So can anyone help me in writing java/kotlin code for the same and get the same value like the above in nodejs ?

PS : I have verified the java results on random sites and they seem to match, but my api is failing with this value , and will only work if it can match with that os nodejs, so it is incorrect in that sense.

Thank you :)

Pritish
  • 1,284
  • 1
  • 19
  • 42
  • How do you know nodejs is a correct value? I used a random hmac sha256 online tool I found in the internet and I was able to replicate Java results, but I can't reproduce nodejs results. – broot Apr 29 '22 at 17:01
  • @broot yes even I checked on the sites, but that is because the other platforms are able to match the js and their api is successful, mine is failing in android. So if ios or other platform are able to replicate the nodejs mac, same is expected in android. So it is wrong in that relation. – Pritish Apr 29 '22 at 17:04

1 Answers1

0

There are two differences between your nodejs and Java implementations.

First and the most important: in nodejs you decode your secret using base64, while in Java you encode it:

Base64.getEncoder().encode(secret.getBytes())

Replace it with:

Base64.getDecoder().decode(secret.getBytes())

Second, in nodejs you use URL variant of base64 (base64urlm) when encoding the final result. In Java you use a regular base64. Replace it with:

Base64.getUrlEncoder().encodeToString(...)
broot
  • 21,588
  • 3
  • 30
  • 35
  • :) You are awesome man, you saved my day, I remember doing it, but both of the things separately ,and not at one time, in another function, and it did not work . Thanks a lot . – Pritish Apr 29 '22 at 17:31