I have java program which calculates SHA-256 checksum as follows. For example, if I provide the input abcd123ABCD00-4000 it outputs 0QtyIu4B+lU+TLqM/zfJz5ULVpyXgfLRs5mKXCQvbHM= . It also matches the online check sum calculator.
However the PHP code I used won't match it.
PHP code :
$s = 'abcd123ABCD00-4000';
$signature = base64_encode(hash_hmac("sha256", $s, True));
print base64_encode($signature);
Output : TWpRM1pEWXpaVFl4TURoallqTXdPRFV6WVRrNU5XVTRNRGxoWkRJMU1XWTVNREk1TnpBeU4ySXhaR0psTW1ZMk16Y3hPRE01WldFelkySXhOalJrWXc9PQ==
Java Code :
private static String getSHA256Hash(String text) {
String hash = null;
MessageDigest md = null;
try {
md = MessageDigest.getInstance("SHA-256");
md.update(text.getBytes("UTF-8"));
byte[] shaDig = md.digest();
// hash = Hex.encodeHexString(shaDig);
hash = Base64.encodeBase64String(shaDig);
} catch (NoSuchAlgorithmException ex) {
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return hash;
}
Output : 0QtyIu4B+lU+TLqM/zfJz5ULVpyXgfLRs5mKXCQvbHM=
Here what I want is to get the equivalent result in PHP (i.e to change PHP code to match result of the Java program[ I won't able to change the Java code ]. Any help is appreciated
If you use hash() and base64 encode once you get the same result.
$s = 'abcd123ABCD00-4000';
$signature = base64_encode(hash("sha256", $s, True));
print $signature; // 0QtyIu4B+lU+TLqM/zfJz5ULVpyXgfLRs5mKXCQvbHM=
Related
I'm just starting to learn Go and I'm trying to rewrite my existing small application from Java to Go.
I need to create Base64 hash of input string with key using Hmac SHA1 algorithm.
My Java code:
private String getSignedBody(String input, String key) {
String result = "";
try {
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(input.getBytes("UTF-8"));
result = Base64.encodeToString(rawHmac, false);
} catch (Exception e) {
Logger.error("Failed to generate signature: " + e.getMessage());
}
return result;
}
My Go code:
func GetSignature(input, key string) string {
key_for_sign := []byte(key)
h := hmac.New(sha1.New, key_for_sign)
h.Write([]byte(input))
return base64.StdEncoding.EncodeToString(h.Sum(nil))
}
The problem is that Go code generates output that is not expected. For example, for input string "qwerty" and key "key" Java output will be RiD1vimxoaouU3VB1sVmchwhfhg= and Go output will be 9Cuw7rAY671Fl65yE3EexgdghD8=.
Where did I make mistakes in the Go code?
The Go code you provided gives exactly the same output as the Java code.
Try it on the Go Playground.
Output:
RiD1vimxoaouU3VB1sVmchwhfhg=
You made the mistake when you called your GetSignature() function. Call it like the linked example code:
fmt.Println(GetSignature("qwerty", "key"))
Your mistake was that you passed an empty input to your GetSignature() function. Calling it with empty "" input and "key" key produces the non-expected output you provided:
fmt.Println(GetSignature("", "key"))
Output:
9Cuw7rAY671Fl65yE3EexgdghD8=
I am porting part of an iOS app to Android, and I'm having trouble porting the following signature generating code in iOS to Android. The iOS code is:
+ (NSString *)hashedBase64ValueOfData:(NSString *) data WithSecretKey:(NSString*)secret {
// ascii convirsion
const char *cKey = [secret cStringUsingEncoding:NSASCIIStringEncoding];
const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding];
// HMAC Data structure initializtion
unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
CCHmac(kCCHmacAlgSHA256, cKey, strlen(cKey), cData, strlen(cData), cHMAC);
// Gerating hased value
NSData *da = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)];
return [da base64EncodedString];// conversion to base64 string & returns
}
The Android Java code I have written and tried is:
private static String hashedBase64ValueOfDataWithSecretKey(String data, String secret) {
try {
SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), HMAC_SHA1_ALGORITHM);
Mac mac = Mac.getInstance(HMAC_SHA1_ALGORITHM);
mac.init(signingKey);
byte[] rawHmac = mac.doFinal(data.getBytes());
return Base64.encodeToString(rawHmac, 0);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
Upon testing, the Android function is not outputting the same thing as the iOS function (given the same input), and I'm not sure why.
Not an expert at this, but NSASCIIStringEncoding seems to imply that you want data and secret interpreted as ASCII, whereas String.getBytes() uses the default character set by default (i.e. UTF-8).
You probably need to use a different charset:
data.getBytes(StandardCharsets.US_ASCII);
secret.getBytes(StandardCharsets.US_ASCII);
For Java pre-1.7, you'll need to use this and catch the UnsupportedEncodingException:
data.getBytes("US-ASCII");
secret.getBytes("US-ASCII");
You might use extras org.apache.commons.codec.binary.Base64. Google it and find it, then you can fellow the codes below. I think the hashed value will be generated by "private key" and appended behind a "public key" being sent to server with a "http-head" together. If no, you can just remove them. Anyway the codes might give you some suggestions. :)
private String getAppendedHeader(String str) {
try {
String hash = getHash(str);
String signature = new String(Base64.encodeBase64(hash.getBytes()));
StringBuilder sb = new StringBuilder();
sb.append(PUBLIC_KEY).append(' ').append(signature);
return sb.toString();
} catch (NoSuchAlgorithmException _e) {
LL.e("Get mac error: " + _e.getMessage());
return null;
} catch (InvalidKeyException _e) {
LL.e("Init mac error: " + _e.getMessage());
return null;
}
}
private String getHash(String str) throws NoSuchAlgorithmException, InvalidKeyException {
Mac mac = Mac.getInstance("HmacSHA256");
SecretKeySpec secret = new SecretKeySpec(PRIVATE_KEY.getBytes(), "HmacSHA256");
mac.init(secret);
byte[] digest = mac.doFinal(str.getBytes());
BigInteger hash = new BigInteger(1, digest);
String hmac = hash.toString(16);
if (hmac.length() % 2 != 0) {
hmac = "0" + hmac;
}
return hmac;
}
I need to encode a string in md5 and then it's bytes to 2 chars hex encoding.
I've got this short JAVA snippets and need to convert it into PHP.
// Condensed the message and do MD5
try {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] data = cleartext.getBytes(ENCODING);
md.update(data);
byte[] digestedByteArray = md.digest();
// Convert digested bytes to 2 chars Hex Encoding
md5String = HexUtils.bytesToHex(digestedByteArray);
} catch (NoSuchAlgorithmException ns) {
ns.printStackTrace();
} catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
I'm not quite sure how to achieve this in PHP. ENCODING is UTF-8
What I have in PHP is
$md5String = md5($clearText);
$hexString = "";
for($i = 0; $i < strlen($md5String); $i++) {
$hexString .= dechex(ord($md5String[$i]));
}
But the output is different, so I think I'm failing on the hex conversion.
So what's the proper port of this JAVA snippet to PHP?
The output of md5 is already a hex-encoded string, so there is nothing else you need to do (as long as you don't set the optional second parameter to true).
$hexString = md5($clearText);
I'm trying to hash a message to a server side (which I can't change his code) written in php and encoded by HMAC_SHA1 algorithm. I'm writing the code in Java.
the php code is as follows:
$utf8Str = mb_convert_encoding($strToSign, "UTF-8");
$hmac_sha1_str = base64_encode(hash_hmac("sha1", $utf8Str, KEY));
$signature = urlencode($hmac_sha1_str);
my java code is:
private static String HashStringSign(String toHash){
try {
String afterUTF = new String(toHash.getBytes(), "UTF-8");
String res = hmac_sha1(afterUTF, SecretAccessKey);
String signature = new String(Base64.encode(res.getBytes()));
String result = URLEncoder.encode(signature);
return result;
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
private static String hmac_sha1(String value, String key) {
try {
// Get an hmac_sha1 key from the raw key bytes
byte[] keyBytes = key.getBytes();
SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA1");
// Get an hmac_sha1 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signingKey);
// Compute the hmac on input data bytes
byte[] rawHmac = mac.doFinal(value.getBytes());
// Convert raw bytes to Hex
byte[] hexBytes = new Hex().encode(rawHmac);
return new String(hexBytes, "UTF-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
I followed each of the hashing methods used in the php code and in the same order as you can see. maybe there's a function(s) in java that works different in php?
I'm using - com.sun.org.apache.xml.internal.security.utils.Base64
java.net.URLEncoder, javax.crypto and org.apache.commons.codec.binary
Thanks!
In your hash_hmac function you need to set the 4th parameter to true.
PHP Code not responsible, Java only:
So now you say that you can't change the PHP side, you can do the following to your Java code.
In your last step of the Java code, you converted the raw byte array to hexademical. However, PHP generates a base64-encoded hexademical instead of just hexademical.
So that the end of your Java step, simply base64 encode your hexademical and you will get the same values. https://stackoverflow.com/questions/9845767/base64-encoder-java#
I have a sample application which generates a SHA1 hash in PHP as follows.
base64_encode(pack('H*', sha1($pass)));
I tried to achieve the same in Java, but so far, the output is different. The approach I used is as follows (Base64 and Hex classes come from commons-codec library).
byte[] rawSHA = null;
byte[] base64HexSHA = null;
String hex = null;
MessageDigest md= null;
// Get Message Digest Instance.
try {
md = MessageDigest.getInstance(SHA1_ALGORITHM);
} catch (NoSuchAlgorithmException e) {
LOG.error("Unable to load SHA-1 Message Digest : " + e.getMessage(), e);
throw new IllegalStateException("SHA-1 Message Digest Instance Not Found");
}
// Build SHA1 Hash
rawSHA = md.digest(rawText.getBytes("UTF-8"));
// Convert to HEX
hex = new String(Hex.encodeHex(rawSHA));
// Encode to Base 64
base64HexSHA = Base64.encodeBase64(hex.getBytes("UTF-8"));
// Return String
return new String(base64HexSHA);
My question is, would the approach I have taken yield the same output as PHP's pack() function? My guess is that PHP pack() function returns the raw bytes where as the Hex.encodeHex returns hex string form (ref : http://www.w3schools.com/php/func_misc_pack.asp).
How can I achieve the same output as PHP's pack() function in Java (or the full output of the above PHP code) ?
Convertion to HEX is not required, just use this:
base64HexSHA = Base64.encodeBase64(rawSHA);