Java and python not getting the same sha-1 value - java

I need your help. My java and python scripts not getting the ame sha-1 value of a string:
hash.py
# -*- coding: utf-8 -*-
import hashlib
username = raw_input('username:')
timestamp = raw_input('timestamp:')
app_id = 'dad'
secret_key = 'dadda'
print 'The hashed string is: ' , hashlib.sha1( username + timestamp + app_id + secret_key ).hexdigest()
hash.java
public static String generateSHA1(String password)
{
String sha1 = "";
try
{
MessageDigest crypt = MessageDigest.getInstance("SHA-1");
crypt.reset();
crypt.update(password.getBytes("UTF-8"));
sha1 = byteToHex(crypt.digest());
}
catch(Exception e)
{
e.printStackTrace();
}
return sha1;
}
private static String byteToHex(final byte[] hash)
{
Formatter formatter = new Formatter();
for (byte b : hash)
{
formatter.format("%02x", b);
}
String result = formatter.toString();
formatter.close();
return result;
}
UPDATE:
Assuming password is already the concatenated: username, timestamp, app_id and secret_key
Is there something I missed? I think there is something wrong with my java code re. UTF-8 outputting this: \xe2\x80\x8b but I couldn't figure it out. Any help will be appreciated. Thanks.

Ensure that both inputs use exactly the same format and encoding and try to use HMAC library.
Java:
String key = "2b5ba589b618ff2485f3391e425f86f0f405fd8e";
String data = "Something you want to keep secret!";
byte[] decodedKey = Hex.decodeHex(key.toCharArray());
SecretKeySpec keySpec = new SecretKeySpec(decodedKey, "HmacSHA1");
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(keySpec);
byte[] dataBytes = data.getBytes("UTF-8");
byte[] signatureBytes = mac.doFinal(dataBytes);
String signature = new String(Base64.encodeBase64(signatureBytes), "UTF-8");
System.out.println("key = " + key);
System.out.println("data = " + data);
System.out.println("signature = " + signature);
Python:
import hmac
import hashlib
key = "2b5ba589b618ff2485f3391e425f86f0f405fd8e"
data = "Something you want to keep secret!"
decodedKey = key.decode("hex")
hmac = hmac.new(decodedKey, data.encode('UTF-8'), hashlib.sha1)
signature = hmac.digest().encode('base64')
print "key =", key
print "data =", data
print "signature =", signature
Both signature outputs should be the same.

Related

Android java SHA256 and C# sha256 give different values

Android java SHA256 and C# sha256 give different values. I want java to be same as c#.
c# code:
private static string _getHashSha256(string inputString)
{
string hashString = string.Empty;
using (SHA256Managed hashstring = new SHA256Managed())
{
byte[] bytes = UTF32Encoding.UTF32.GetBytes(inputString);
byte[] hash = hashstring.ComputeHash(bytes);
foreach (byte x in hash)
hashString += String.Format("{0:x2}", x);
}
return hashString;
}
input "111", result "f4b5625de0c6abd88521b87d39f5a4fe33935f27c4ac38a63575ad43d36c7fbb"
android java code:
String password="111";
MessageDigest digest=null;
String hash;
try {
digest = MessageDigest.getInstance("SHA-256");
digest.update(password.getBytes("UTF-32"));
hash = bytesToHexString(digest.digest());
Log.i("sha256", hash);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e1) {
z = "hash code error: " + e1.getMessage();
}
input is "111". result "12215d42454c57aa1039367b66509e53dcd2d6f9a6e80f9d00b2439ea7ebd43f"
please help me guys!
Thanks guys.
I found the problem was when java converts string to bytes by utf-32, there is additional 4 bytes preceded. it changed resulting sha256.
So I removed that initial 4 bytes as follows:
String password="111";
MessageDigest digest=null;
String hash;
byte[] bbb = user_pass.getBytes("UTF-32");
byte[] ccc = new byte[bbb.length - 4];
System.arraycopy(bbb, 4, ccc, 0, bbb.length - 4);
digest = MessageDigest.getInstance("SHA-256");
digest.update(ccc);
hash_password = bytesToHexString(digest.digest());

javax.crypto.Cipher equivalent code in Nodejs Crypto Javascript

I'm trying to convert below java code into nodejs.
public static String encrypt(String accessToken) throws Exception {
Cipher cipher = Cipher.getInstance("AES");
String merchantKey = "11111111111111111111";
String st = StringUtils.substring(merchantKey, 0, 16);
System.out.println(st);
Key secretKey = new SecretKeySpec(st.getBytes(), "AES");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] encryptedByte = cipher.doFinal(accessToken.getBytes());
// convert the byte to hex format
StringBuffer sb = new StringBuffer();
for (int i = 0; i < encryptedByte.length; i++) {
sb.append(Integer.toString((encryptedByte[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
Here is what I was able to figure out-
function freeChargeEncryptAES(token){
var fcKey = "11111111111111111111".substring(0, 16);
var cipher = crypto.createCipher('aes-128-ecb', fcKey, "");
var encrypted = cipher.update(token,'ascii','hex');
encrypted += cipher.final('hex');
return encrypted;
}
I'm not able to get same output. For example if
token = "abcdefgh"
Java Code output - bc02de7c1270a352a98faa686f155df3
Nodejs Code output - eae7ec6943953aca94594641523c3c6d
I've read from this answer that by default encryption algorithm is aes-ecb which does not need IV. As the key length is 16, I'm assuming aes-128-ecb (16*8 = 128) is the algorithm that I should use.
Can someone help me figure out the problem ??
Just need to change -
crypto.createCipher('aes-128-ecb', fcKey, "");
to
crypto.createCipheriv('aes-128-ecb', fcKey, "");
Reason is simple - createCipher method treats second parameter as Encryption Password while it is an Encryption Key.
My bad, even after reading this answer, I've used wrong method (crypto.createCipher instead of crypto.createCipheriv). Below is proper working code in nodejs. That was all needed.
function freeChargeEncryptAES(token){
var fcKey = "11111111111111111111".substring(0, 16);
var cipher = crypto.createCipheriv('aes-128-ecb', fcKey, "");
var encrypted = cipher.update(token,'ascii','hex');
encrypted += cipher.final('hex');
return encrypted;
}

convert php mcrypt_encrypt MCRYPT_3DES to Java

I have code in PHP
$res = strtoupper(bin2hex(mcrypt_encrypt(MCRYPT_3DES, $this->hex2str($key), $this->hex2str($data), MCRYPT_MODE_ECB)));
public function hex2str($data) {
$len = strlen($data);
$res = pack("H" . $len, $data);
return $res;
}
I try to create in java version.
Java code :
private String doEncrypt3DES(String key, String data) throws Exception{
SecretKey secretKey;
byte[] keyValue;
Cipher c;
keyValue = Hex.decodeHex(key.toCharArray());
DESedeKeySpec keySpec = new DESedeKeySpec(keyValue);
secretKey = SecretKeyFactory.getInstance("DESede").generateSecret(keySpec);
// Create the cipher
c = Cipher.getInstance("DESede/ECB/NoPadding");
c.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] text = data.getBytes("utf-8"); // Base64.decodeBase64(data);
byte[] textEncrypt = c.doFinal(text);
String hex = bytesToHex(textEncrypt);
return hex;
}
But they got different result. Can you help me to fix java code?
data : CED0CF172E8AC451B39FC746C5339F29
key : 436C6561724B657944657632536E724D436C6561724B6579
Use hex decode and not utf-8 decode to data.

why PHP's hash_hmac('sha256') gives different result than java sha256_HMAC

in PHP I have the following function:
base64_encode(hash_hmac('sha256', $data, $secret, false));
I'm trying to create a function in Java that will give the same result for the same "data" and "secret" parameters.
I tried to use this function:
public static String base64sha256(String data, String secret) {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] res = sha256_HMAC.doFinal(data.getBytes());
return Base64.encodeToString(res, Base64.NO_WRAP);
}
But I get different results for the same input
Update: This function works. Enjoy.
public static String base64sha256(String data, String secret) {
String hash = null;
try {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] res = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
hash = getHex(res);
hash = Base64.encodeToString(hash.getBytes("UTF-8"), Base64.NO_WRAP);
} catch (Exception e){}
return hash;
}
static final String HEXES = "0123456789abcdef";
public static String getHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
The output of the php function are lowercase hex digits when the fourth parameter is false. Your second java version however produces uppercase hex digits. Either correct the case difference or you could change the fourth parameter of hash_hmac to true and it will probably match with your first Java version.
If trying to match output of drupal_hmac_base64 with Java 8, you can use the following code:
final String ALGORITHM = "HmacSHA256";
Mac mac = Mac.getInstance(ALGORITHM);
SecretKeySpec secret = new SecretKeySpec(authorizationKey.getBytes(), ALGORITHM);
mac.init(secret);
byte[] digest = mac.doFinal(body.getBytes());
hash = Base64.getUrlEncoder().withoutPadding().encodeToString(digest);
return signature.equals(hash);
Note that drupal returns a hash using raw binary data (3rd parameter TRUE). Also, base64 encoding in PHP matches the URL and Filename safe base64 encoder in Java https://docs.oracle.com/javase/8/docs/api/java/util/Base64.html#url.
For someone who might be facing a slight change (not working) in Java result compared to PHP, my issue was in returning the hash from HmacSHA256 as String, while you should return it and pass to Hex as byte[].
Here are the working methods to simulate PHP's hash_hmac()
public String hashValue(String message) {
byte[] hash = toHmacSHA256(message);
String hashHexed = toHex(hash);
return hashHexed;
}
private String toHex(byte[] value) {
String hexed = String.format("%040x", new BigInteger(1, value));
return hexed;
}
private byte[] toHmacSHA256(String value) {
byte[] hash = null;
try {
SecretKey secretKey = new SecretKeySpec(PRIVATE_KEY.getBytes("UTF-8"), "HmacSHA256");
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(secretKey);
hash = mac.doFinal(value.getBytes("UTF-8"));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return hash;
}

Remove \r and \n from AES encrypted string

I am encrypting a string using AES but the encrypted string contains \n and \r at the end.
public class AESImpl {
private static String decryptedString;
private static String encryptedString;
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, ClassNotFoundException {
String strToEncrypt = "This text has to be encrypted";
SecretKey secretKey = generateSecretKey();
String encryptStr = encrypt(strToEncrypt, secretKey);
System.out.println("Encrypted String : " + encryptStr + "It should not come in new line");
String decryptStr = decrypt(encryptStr, secretKey);
System.out.println("Decrypted String : " + decryptStr);
}
private static SecretKey generateSecretKey() throws NoSuchAlgorithmException, IOException {
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
SecretKey sk = kg.generateKey();
String secretKey = String.valueOf(Hex.encodeHex(sk.getEncoded()));
System.out.println("Secret key is " + secretKey);
return sk;
}
public static String encrypt(String strToEncrypt, SecretKey secretKey) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
encryptedString = new String(Base64.encodeBase64String(cipher.doFinal(strToEncrypt.getBytes())));
} catch (Exception e) {
System.out.println("Error while encrypting: " + e.toString());
}
return encryptedString;
}
public static String decrypt(String strToDecrypt, SecretKey secretKey) {
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
decryptedString = new String(cipher.doFinal(Base64.decodeBase64(strToDecrypt)));
} catch (Exception e) {
System.out.println("Error while decrypting: " + e.toString());
}
return decryptedString;
}
}
Output
Secret key is 2df36561b09370637d35b4a310617e60
Encrypted String : TUDUORnWtsZFJAhBw1fYMF9CFExb/tSsLeDx++cpupI=
It should not come in new line
Decrypted String : This text has to be encrypted
Actually, the encrypted string is TUDUORnWtsZFJAhBw1fYMF9CFExb/tSsLeDx++cpupI=/r/n.
Do I need to explicitly replace the \r and \n from encrypted string or I have done something wrong in the above code?
Adding
Base64.encodeBase64String(hashPassword,Base64.NO_WRAP) removes the \n.
By default it uses Base64.DEFAULT which adds newline.
click here: source
click here: Main source
Actually,I was using apache commons-codec-1.4.0.jar to encode the string. Changing it to higher version solves the issue.
The behaviour of encodeBase64String method has been changed from multi-line chunking (commons-codec-1.4) to single-line non-chunking (commons-codec-1.5).
Please follow the link for more details.
http://commons.apache.org/proper/commons-codec/apidocs/org/apache/commons/codec/binary/Base64.html
It seems like the base64 encoding standard requires that there is a line break at least every 75 characters. My guess is that the base64 encoding function is adding this automatically, you haven't done anything wrong, and that it's fine to leave it in or remove it. According to the link below, base64 decoding functions should ignore line breaks, so whether you remove it or not is up to you...
See here for someone else who's run into this problem, and a quote from the base64 standard: http://lists.w3.org/Archives/Public/w3c-ietf-xmldsig/2001AprJun/0183.html
Simply perform encryptedString = encryptedString.replaceAll("(?:\\r\\n|\\n\\r|\\n|\\r)", "") on the encoded string.
It works fine when you try do decode it back to bytes. I did test it several times with random generated byte arrays. Obviously decoding process just ignores the newlines either they are present or not. I tested this "confirmed working" by using com.sun.org.apache.xml.internal.security.utils.Base64 Other encoders not tested.
This is the code block which adds \n at the end ofthe encoded string
keyBytes = secret_key.substring(0, 32).toByteArray(charset("UTF8"))
val skey = SecretKeySpec(keyBytes, "AES")
val input = strToEncrypt.toByteArray(charset("UTF8"))
synchronized(Cipher::class.java) {
val cipher = Cipher.getInstance("AES/ECB/PKCS5Padding")
cipher.init(Cipher.ENCRYPT_MODE, skey)
val cipherText = ByteArray(cipher.getOutputSize(input.size))
var ctLength = cipher.update(
input, 0, input.size,
cipherText, 0
)
ctLength += cipher.doFinal(cipherText, ctLength)
return String(
android.util.Base64.encode(cipherText, 1)
)
}
and THIS IS THE CODE BELOW WORKS FINE !!
val algorithm = "AES"
val keyValue = secret_key.substring(0, 32).toByteArray(charset("UTF8"))
val key: Key = SecretKeySpec(keyValue, algorithm)
val c: Cipher = Cipher.getInstance(algorithm, "BC")
c.init(Cipher.ENCRYPT_MODE, key);
val encValue: ByteArray =
c.doFinal(
strToEncrypt.toByteArray()
)
return Base64.getEncoder().encodeToString(encValue)

Categories