0

While testing the code in a previous post on the differences between the java and c# hmacsha256 implementation outputs, I noticed that the outputs were slightly different, i.e. when I ran java code the output was

ivEyFpkagEoghGnTw_LmfhDOsiNbcnEON50mFGzW9_w=

but in C# code I get

ivEyFpkagEoghGnTw/LmfhDOsiNbcnEON50mFGzW9/w=

Has anybody seen this, i.e. there is a _ in the java example but an / in the c# example

Java Code

import java.util.*;
import javax.crypto.*;
import javax.crypto.spec.*;

public class Test {
    public static void main (String[] args) throws Exception {
        String secretAccessKey = "mykey";
        String data = "my data";
        byte[] secretKey = secretAccessKey.getBytes();
        SecretKeySpec signingKey = new SecretKeySpec(secretKey, "HmacSHA256");
        Mac mac = Mac.getInstance("HmacSHA256");
        mac.init(signingKey);
        byte[] bytes = data.getBytes();
        byte[] rawHmac = mac.doFinal(bytes);
        System.out.println(Base64.getUrlEncoder().encodeToString(rawHmac));
    }
}

C# Code

using System;
using System.Security.Cryptography;
using System.Text;

class Test
{
    static void Main()
    {
        String secretAccessKey = "mykey";
        String data = "my data";
        byte[] secretKey = Encoding.UTF8.GetBytes(secretAccessKey);
        HMACSHA256 hmac = new HMACSHA256(secretKey);
        hmac.Initialize();
        byte[] bytes = Encoding.UTF8.GetBytes(data);
        byte[] rawHmac = hmac.ComputeHash(bytes);
        Console.WriteLine(Convert.ToBase64String(rawHmac));
    }
}
Eric Hauenstein
  • 2,557
  • 6
  • 31
  • 41
O Dibble
  • 3
  • 1

1 Answers1

0

This seems to be a design choice for the Base64 encoders, one of them chose to use the _ character and one of them chose to use the / character (C# also uses the + character instead of the - character). If you need to use that string across languages you can use myString.replace(oldChar, newChar) (myString.Replace(oldChar, newChar) in C#) to replace the mismatch characters.


If you want C# Base64 strings to look like Java's Base64 strings you can use Microsoft.IdentityModel.Tokens.Base64UrlEncoder, but this is a Nuget package you would have to install. This uses - and _ instead of + and /.

vandench
  • 1,973
  • 3
  • 19
  • 28
  • Why a regex replace? Why not an ordinary character replace? – khelwood Dec 28 '17 at 15:05
  • @khelwood If I remember correctly, in Java to do `replaceAll` you have to use RegEx. This may not be the case in C#. – vandench Dec 28 '17 at 15:07
  • You remember incorrectly. In Java you can use [`replace`](https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)) . You don't need to use the regex version, [`replaceAll`](https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replaceAll(java.lang.String,%20java.lang.String)). – khelwood Dec 28 '17 at 15:08
  • Thanks, while using Microsoft.IdentityModel.Tokens.Base64UrlEncoder is a little heavy handed, it does do the trick, (also gets rid of the padding!). – O Dibble Dec 28 '17 at 15:21
  • btw @van dench how do you know that only the + and / characters will be an issue – O Dibble Dec 28 '17 at 16:01
  • @O Dibble Because Base64 is `[A-Za-z0-9+/]`, but because of URL's the `+` and `/` characters had to be replaced. Java's Base64 converter uses the web safe standard. – vandench Dec 28 '17 at 16:17