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));
}
}
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 /.
Related
I have some java code I have been asked to convert to Python2.7 I have looked online and dont find a good example.
The Java code is building a signature using SecretKeySpec function and HmacSHA256.
It takes a keyString as parameter and a message string a
Below is the function I need to convert to Python:
public static String genSig(String key, String Params) throws Exception {
byte[] decodedKey = Base64.getDecoder().decode(key);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "HmacSHA256");
Mac hmacSha256 = Mac.getInstance("HmacSHA256");
hmacSha256.init(originalKey);
hmacSha256.update(Params.getBytes());
byte[] HmachSha256DigestBytes = hmacSha256.doFinal();
return Base64.getEncoder().encodeToString(HmachSha256DigestBytes);
}
I have looked into hmac and the hashlib libraries, but Im not sure what to use from these libraries to fulfill this conversion?
You can use the following code:
import hmac
import hashlib
import base64
def generateSignatureFromParams(key, params):
dig = hmac.new(base64.b64decode(key), msg=params, digestmod=hashlib.sha256).digest()
return base64.b64encode(dig).decode()
print generateSignatureFromParams("a2V5", "encrypt")
Notice to get HMACSha256, the digestmod=hashlib.sha256 is important.
I am very rarely use Java and I have an requirement of converting a function in Node.js which builds the HMAC signature for REST POST call to Java
Node JS function :
function buildSignature(buf, secret) {
const hmac = crypto.createHmac('sha256', Buffer.from(secret, 'utf8'));
hmac.update(buf);
return hmac.digest('hex');
}
What I have currently done is:
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
String hash = Base64.encodeBase64String(sha256_HMAC.doFinal(message.getBytes()));
System.out.println(hash);
This is not working out to be the same.
It's my suspicion that hmac.digest('hex'); isn't base 64 encoded. I'd try converting the response of sha256_HMAC.doFinal(message.getBytes()) to hex instead.
How to convert a byte array to a hex string in Java? 's
The answer I would prefer there (since I use Guava in many projects) is
final String hex = BaseEncoding.base16().lowerCase().encode(bytes);
Adapted to your question would be
final String hash = BaseEncoding.base16().lowerCase().encode(sha256_HMAC.doFinal(message.getBytes()));
Mac sha256_HMAC;
sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] hash = sha256_HMAC.doFinal(payload.getBytes());
return new String(Hex.encodeHex(hash));
I try to implement this Java method in Python, but it seems to hard to rewrite it in pure Python.
public static String CalculateHash(String input, String token) {
SecretKeySpec signingKey = new SecretKeySpec(token.getBytes(), "HmacSHA1");
Mac mac = null;
mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
assert mac != null;
byte[] bytes = mac.doFinal(input.getBytes(Charset.forName("UTF-8")));
String form = "";
for (byte aByte : bytes) {
String str = Integer.toHexString(((int) aByte) & 0xff);
if (str.length() == 1) {
str = "0" + str;
}
form = form + str;
}
return form;
}
I tried this one, but it generates other hash.
def sign_request():
from hashlib import sha1
import hmac
# key = CONSUMER_SECRET& #If you dont have a token yet
key = "CONSUMER_SECRET&TOKEN_SECRET"
# The Base String as specified here:
raw = "BASE_STRING" # as specified by oauth
hashed = hmac.new(key, raw, sha1)
# The signature
return hashed.digest().encode("base64").rstrip('\n')
What and how should I use in standart Python library to rewrite it? Thank you
Your python code and java code don't match in the fact that the python code uses base 64, while the java code uses hexadecimal (base 16).
You should change the phyton code to use base16 for its output, this can be done with the hex() function, caring to correctly pad the number with the correct numbers of 0 characters the java code does.
I am using the following code in c# for HMAC conversion:
string RawData = "data";
string sharedKey = "my-key";
byte[] signature = Encoding.UTF8.GetBytes(RawData);
var KeyByteArray = Encoding.UTF8.GetBytes(sharedKey);
using (HMACSHA256 hmac = new HMACSHA256(KeyByteArray))
{
byte[] signatureBytes =hmac.ComputeHash(signature);
var ContentBase64String =(Convert.ToBase64String(signatureBytes));
Console.WriteLine(ContentBase64String );
Console.ReadKey();
}
And the following in Java:
String RawData="data";
String Key="my-key";
byte[] KeyByteArray=Key.getBytes("UTF-8");
byte[] signature=RawData.getBytes("UTF-8");
Mac sha256_HMAC;
sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(KeyByteArray, "HmacSHA256");
sha256_HMAC.init(secret_key);
String ContentBase64String = Base64.encodeToString(sha256_HMAC.doFinal(signature),Base64.URL_SAFE|Base64.NO_WRAP);
The output for C# is as follows:
The output for android is as follows:
I have been it at it for many days and can't figure out what I am doing wrong as the outputs differ though they should be the same.Also, when I remove the - in the key the results are the same. I know I might be missing something simple but thought another pair of eyes might see my mistake. Thanks.
Those answers are the same (as far as the bytes contained in the HMAC goes). For the difference in the + and - characters in the output, you specifically told it to do that by specifying the Base64.URL_SAFE flag.
For future readers of this question: When in doubt, consult the documentation for everything you don't perfectly understand.
I am now trying to encode the string using HMAC-SHA256 using Java. The encoded string required to match another set of encoded string generated by Python using hmac.new(mySecret, myPolicy, hashlib.sha256).hexdigest(). I have tried
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hash = sha256_HMAC.doFinal(policy.getBytes());
byte[] hexB = new Hex().encode(hash);
String check = Hex.encodeHexString(hash);
String sha256 = DigestUtils.sha256Hex(secret.getBytes());
after I print them out, hash, hexB, check and sha256 didn't provide the same result as the following Python encryption method
hmac.new(mySecret, myPolicy, hashlib.sha256).hexdigest()
So, I have try to looking for the library or something that work similar to the above Python function. Can anybody help me out?
Are you sure your key and input are identical and correctly encoded in both java and python?
HMAC-SHA256 works the same on both platforms.
Java
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKey = new SecretKeySpec("1234".getBytes(), "HmacSHA256");
sha256_HMAC.init(secretKey);
byte[] hash = sha256_HMAC.doFinal("test".getBytes());
String check = Hex.encodeHexString(hash);
System.out.println(new String(check));
Output
24c4f0295e1bea74f9a5cb5bc40525c8889d11c78c4255808be00defe666671f
Python
print hmac.new("1234", "test", hashlib.sha256).hexdigest();
Output
24c4f0295e1bea74f9a5cb5bc40525c8889d11c78c4255808be00defe666671f