How do you convert the following Java to PHP?
byte[] byteArray1 = key1.getBytes("UTF8");
byte[] byteArray2 = key2.getBytes("UTF8");
byte[] byteArray3 = key3.getBytes("UTF8");
byte[] byteArray4 = key4.getBytes("UTF8");
Mac mac = Mac.getInstance("HmacSHA1");
SecretKeySpec derivedKey = new SecretKeySpec(byteArray1, "HmacSha1");
mac.init(derivedKey); derivedKey = new SecretKeySpec(mac.doFinal(byteArray2), "HmacSha1"); }
mac.init(derivedKey); derivedKey = new SecretKeySpec(mac.doFinal(byteArray3), "HmacSha1");
mac.init(derivedKey); derivedKey = new SecretKeySpec(mac.doFinal(byteArray4), "HmacSha1");
From all the research I've done, it looks like if we'd remove the last two lines, we could neatly convert it to PHP as follows:
hash_hmac("sha1", $key2, $key1, true);
However, how to you convert this type of reiterative hashing to PHP?
Note: I've tried the following unsuccessfully:
$derivedKey = hash_hmac("sha1", $key2, $key1, true);
$derivedKey = hash_hmac("sha1", $key3, $derivedKey, true);
$derivedKey = hash_hmac("sha1", $key4, $derivedKey, true);
Related
I have the following example in Javascript, I can't seem to find the equivalent in Java for it
var rapyd_signature = CryptoJS.enc.Hex.stringify(CryptoJS.HmacSHA256(data, key));
rapyd_signature = CryptoJS.enc.Base64.stringify(CryptoJS.enc.Utf8.parse(rapyd_signature));
What I have (which does not give the same result)
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmacSHA256.init(secretKeySpec);
byte[] tobeEncoded = data.getBytes(StandardCharsets.UTF_8);
String rapyd_signature = Base64.getEncoder().encodeToString(tobeEncoded);
You initialized hmacSHA256 … and then you didn’t do anything with it.
You need to actually hash the data, by calling hmacSHA256.doFinal:
Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
hmacSHA256.init(secretKeySpec);
byte[] tobeEncoded = data.getBytes(StandardCharsets.UTF_8);
toBeEncoded = hmacSHA256.doFinal(toBeEncoded);
String rapyd_signature = Base64.getEncoder().encodeToString(tobeEncoded);
I am trying to emulate same behaviour of Java in C#. But I am not getting desired result. Key generated by both is different.
JAVA CODE
public static String generateDecryptedKey(String secretKey, String authKey)
{
String strDecryptedKey = "";
byte[] salt = { (byte)0x09, (byte)0xD5, (byte)0xA1, (byte)0xA6, (byte)0xA3, (byte)0xA7, (byte)0xA9, (byte)0xA0 };
int iterationCount = 10;
KeySpec keySpec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount);
SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);
AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);
dcipher = Cipher.getInstance(key.getAlgorithm());
dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
byte[] enc = Base64.decodeBase64(authKey.getBytes());
byte[] utf8 = dcipher.doFinal(enc);
strDecryptedKey = new String(utf8, "UTF-8");
return strDecryptedKey;
}
C# CODE
public static string generateDecryptedKey(string secretKey,string authKey)
{
string strDecryptedKey = string.Empty;
byte[] salt = { (byte)0x09, (byte)0xD5, (byte)0xA1, (byte)0xA6, (byte)0xA3, (byte)0xA7, (byte)0xA9, (byte)0xA0 };
int iterationCount = 10;
PKCSKeyGenerator kp = new PKCSKeyGenerator();
ICryptoTransform crypt = kp.Generate(secretKey, salt, iterationCount, 1);
var bytes = Encoding.UTF8.GetBytes(authKey);
byte[] resultBytes = crypt.TransformFinalBlock(bytes, 0, bytes.Length);
strDecryptedKey = Convert.ToBase64String(resultBytes);
return strDecryptedKey;
}
Result generated by both function upon same input is coming wrong. I am new to cryptography, please someone explain where I am doing wrong. Below is the link for class written by BobJanova that I am using in C# conversion.
https://www.codeproject.com/Articles/16450/Emulating-PBEWithMD-AndDES-Encryption-under-NET
NOTE: I don't want to reveal my SALT value so I had changed to some value. Hope you understand.
You should use
var bytes = Convert.FromBase64String(authKey);
instead of
var bytes = Encoding.UTF8.GetBytes(authKey);
and
strDecryptedKey = Encoding.UTF8.GetString(resultBytes);
instead of
strDecryptedKey = Convert.ToBase64String(resultBytes);
in C#.
Also, authKey.getBytes() in Java might lead to problems down the line. Always specify an encoding like authKey.getBytes("UTF-8").
I am having a PHP which is working fine and I want to replicate the same and want to do it using java.
My PHP code uses MCRYPT_RIJNDAEL_256 :
$iv = "42309842389462374623784692423642";
$key = "asfuyjkdhfabcdef";
$text = "0007";
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
$crypttext64=base64_encode($crypttext);
echo $crypttext64;
which returns: KdL2lWUGqy+UqLxbe9VTS6OCgvnJFn1jtMCgkj1434A=
But while encrypting using java :
byte[] sessionKey = "asfuyjkdhfabcdef".getBytes(Charset.forName("ASCII"));
byte[] iv = "42309842389462374623784692423642".getBytes(Charset.forName("ASCII"));
String plaintext="0007";
String data = new String(new char[28]).replace("\0", Character.toString ((char) 28));
String newdata = plaintext+data;
newdata = newdata.substring(0,32);
byte [] dataBytes = newdata.getBytes(Charset.forName("ASCII"));
System.out.println(dataBytes);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new RijndaelEngine(256)),new PKCS7Padding());
cipher.init(true, new ParametersWithIV(new KeyParameter(sessionKey), iv));
byte[] encrypted = new byte[cipher.getOutputSize(dataBytes.length)];
int oLen = cipher.processBytes(dataBytes, 0, dataBytes.length, encrypted, 0);
cipher.doFinal(encrypted, oLen);
String s = new String(encrypted);
System.out.println(Base64.getEncoder().encodeToString(s.getBytes()));
I am getting below output:
KdL2lWUGqy+UqLxbe9VTS6OCgvnJFn1jtMCgkj1434DMpLehN7ve0AhnMOQtT1fLcZIUfM9rF/iVOKj6UtgwyA==
Both the outputs are different.
Please suggest the way so that I can get the same output in JAVA also.
You seem to try and perform the padding twice:
String data = new String(new char[28]).replace("\0", Character.toString ((char) 28));
String newdata = plaintext+data;
newdata = newdata.substring(0,32);
byte [] dataBytes = newdata.getBytes(Charset.forName("ASCII"));
System.out.println(dataBytes);
seems to be an ill written attempt to perform the PKCS#7 padding, which you already do in your code (new PKCS7Padding()).
Just replace it by:
plaintext.getBytes(StandardCharsets.US_ASCII)
As you can see, the first part of the base 64 is identical in both PHP and Java. Note that PHP doesn't contain PKCS#7 padding, which is why this was coded using str_repeat.
Furthermore the encrypted array should be directly put into the encodeToString method, first converting to String and then back to byte[] again can only loose data. So strip out s in the following code:
String s = new String(encrypted);
System.out.println(Base64.getEncoder().encodeToString(s.getBytes()));
I'm converting a php script to java (for android) but find myself stuck converting the hmac signature process.
PHP which gives correct sign:
$secret = "lT4fhviR7ILvwGeiBJgolfYji1uz/f7B6HQWaWQWVl/sWEz3Kwt4QjzCHWE+MBENOmtgBS6PlN87s+1d7/8bRw==";
$nonce = "1388256620813308";
$postdata = "nonce=1388256620813308";
$path = "/0/private/Balance";
$sign = hash_hmac('sha512', $path . hash('sha256', $nonce . $postdata, true), base64_decode($this->secret), true);
echo $sign;
Hmac = 2IVoBCoadCEivxKVRB/4quJET4DoZV4JdY6bMC2oEYJZuygF5JiAhGrxVMyw2yPhz+KdiwvbzV43cicGamzr2A==
Which is correct and accepted signature
Java (with invalid sign):
String secret = "lT4fhviR7ILvwGeiBJgolfYji1uz/f7B6HQWaWQWVl/sWEz3Kwt4QjzCHWE+MBENOmtgBS6PlN87s+1d7/8bRw==";
String nonce = "1388256620813308";
String postdata = "nonce=1388256620813308";
String path = "/0/private/Balance";
// hash nonce + data
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update((nonce+postdata).getBytes());
byte[] digest = md.digest();
String baseString = path + new String(digest); //this is probably root of evil
// HMAC
Mac mac = Mac.getInstance("HmacSHA512");
SecretKey secretKey = new SecretKeySpec(Base64.decode(secret, Base64.DEFAULT), "HmacSHA512");
mac.init(secretKey);
String sign = new String(Base64.encodeToString(mac.doFinal(baseString.getBytes()), Base64.DEFAULT)).trim();
Log.d(TAG, sign);
Hmac = 7ZQfn+fqMpMEFN5Z/T5UwcqP1uo0JOyAVSn4HEBeE/KotnEf4a5bPOWriiC//gdoEg2kOe60EIr3Lv7irXuejw==
The problem is in the java string conversion of the bytes (even if I add "UTF-8" as characted encoding in getBytes). I know this because if I don add path to the hmac, and just feed it with digest without the string conversion the signature matches.
After posting question I did a quick and dirty test to add bytes from path manually to a new bytes array
byte[] digest = md.digest();
byte[] pBytes = path.getBytes();
int L = digest.length + pBytes.length;
byte[] message = new byte[L];
for (int i=0;i<pBytes.length;i++) {
message[i] = pBytes[i];
}
for (int i=pBytes.length,n=0; n<digest.length; n++) {
message[i+n] = digest[n];
}
String sign = new String(Base64.encodeToString(mac.doFinal(message), Base64.NO_WRAP));
And voilà; the hmac sign matches!
I have solved my problem but keeping question unanswered for some day to say if a better answer is provided that sheds light on this.
I just want to encode a given string to HmacSHA256 according to a private key in java.anyone can provide a simple program....?
SecureRandom sr = new SecureRandom();
byte[] keyBytes = new byte[20];
sr.nextBytes(keyBytes);
SecretKey key = new SecretKeySpec(keyBytes, "HmacSHA1");
Mac m = Mac.getInstance("HmacSHA1");
m.init(key);
m.update(inputData);
byte[] mac = m.doFinal();
Copied from 'http://oreilly.com/catalog/javacrypt/chapter/ch06.html', you'll find all other cryptographic information there.