convert byte array to string in java - java

I try to convert byte array to string in java using new String( bytes, "UTF-8") method, but they only return the object. like this #AB4634bSbbfa
So, I searched some way to solve this problem.
I finally get valid string array, by converting hex-code to basic-character array.
like this. char[] chars = {"0", "1", ... "e", "f"};
This never happened before why do i have to convert hex-code to get valid string.
Here is method.
byte array which is hashed by Mac-sha-256 with specific key when i hashed.
public static String getHashString() {
String algorithm = "HmacSHA256";
String hashKey = "some_key";
String message = "abcdefg";
String hexed = "";
try {
Mac sha256_HMAC = Mac.getInstance(algorithm);
SecretKeySpec secret_key = new SecretKeySpec(hashKey.getBytes(), algorithm);
sha256_HMAC.init(secret_key);
byte[] hash = sha256_HMAC.doFinal(message.getBytes("UTF-8"));
// it doesn't work for me.
// hexed = new String(hash, "UTF-8");
// it works.
hexed = bytesToHex(hash);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return hexed;
}
public static final char[] HEX_DIGITS = "0123456789abcdef".toCharArray();
public static String bytesToHex(final byte[] data ) {
final int l = data.length;
final char[] hexChars = new char[l<<1];
for( int i=0, j =0; i < l; i++ ) {
hexChars[j++] = HEX_DIGITS[(0xF0 & data[i]) >>> 4];
hexChars[j++] = HEX_DIGITS[0x0F & data[i]];
}
return new String(hexChars);
}
Thanks.

Following is a sample which shows Conversion of Byte array to String :-
public class TestByte
{
public static void main(String[] argv) {
String example = "This is an example";
byte[] bytes = example.getBytes();
System.out.println("Text : " + example);
System.out.println("Text [Byte Format] : " + bytes);
System.out.println("Text [Byte Format] : " + bytes.toString());
String s = new String(bytes);
System.out.println("Text Decryted : " + s);
}}

I'm not sure the string you get in the end is what you're after. I think a common scenario is to use
new BASE64Encoder().encode(hash)
which will return you the hashed message as String.

just do new String(byteArray);

Related

Bouncy Castle PBKDF2WithHmacSHA3-256 implementation

I am trying to encrypt the password using the PBKDF2WithHmacSHA3-256. Based on the bouncycastle sample, I have the following sample
JAVA Code
The output from the Java code and Node JS seems to be different.
public static void main (String args[]) {
String saltVal = "a5dcea8d0bba2f1fcfa5824085bf06e65fa1255484dafd499984323672b71fee";
String passwordToHash = "password";
int iterations = 10000;
try {
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator((new SHA3Digest(256)));
generator.init(passwordToHash.getBytes("UTF-8"),
saltVal.getBytes(),
iterations);
byte[] derivedKey = ((KeyParameter)generator.generateDerivedParameters(32 * 8)).getKey();
BigInteger bi = new BigInteger(1, derivedKey);
System.out.println(String.format("%0" + (derivedKey.length << 1) + "x", bi));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
Node JS
const crypto = require("crypto");
const iteration = 10000;
const length = 32;
const digest = "sha3-256";
const sharedSecret = "a5dcea8d0bba2f1fcfa5824085bf06e65fa1255484dafd499984323672b71fee";
const valuesToHash = ["password"];
const hashFn = (value, salt) => {
const saltBuf = Buffer.from(salt, "hex")
const key = crypto.pbkdf2Sync(value, saltBuf, iteration, length, digest);
return key.toString("hex");
}
for (const value of valuesToHash) {
console.log(`>>> ${value}: ${hashFn(value, sharedSecret)}`);
}
Thanks!
This is the updated code. The salt and iterations are defined outside.
private static String encodePassword (String password)
{
String returnVal = "";
try {
PKCS5S2ParametersGenerator generator = new PKCS5S2ParametersGenerator((new SHA3Digest(256)));
generator.init(password.getBytes("UTF-8"),
Hex.decode(saltVal),
iterations);
byte[] derivedKey = ((KeyParameter)generator.generateDerivedParameters(32 * 8)).getKey();
returnVal = Hex.toHexString(derivedKey);
System.out.println(">>> " + password + " : " + returnVal);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return returnVal;
}

what this android function returns

I am trying to decode an APK file. I need to get what m21862a function returns.
Simply I need HASH value. Hash is requested to https://api.SOMESITE.net/external/auth. How it is generated?
Here is my part code:
a = HttpTools.m22199a("https://api.somesite.net/external/hello", false);
String str = BuildConfig.FLAVOR;
str = BuildConfig.FLAVOR;
str = BuildConfig.FLAVOR;
try {
str = ((String) new JSONObject(a).get("token")) + ZaycevApp.f15130a.m21564W();
Logger.m22256a("ZAuth", "token - " + str);
str = m21862a(str);
a = new JSONObject(HttpTools.m22199a(String.format("https://api.SOMESITE.net/external/auth?code=%s&hash=%s", new Object[]{a, str}), false)).getString("token");
if (!ae.m21746b((CharSequence) a)) {
ZaycevApp.f15130a.m21595f(a);
}
}
I need to know what is m21862a function. Is there PHP replacement for m21862a? Here is m21862a function:
private String m21862a(String str) {
try {
MessageDigest instance = MessageDigest.getInstance("MD5");
instance.update(str.getBytes());
byte[] digest = instance.digest();
StringBuffer stringBuffer = new StringBuffer();
for (byte b : digest) {
String toHexString = Integer.toHexString(b & RadialCountdown.PROGRESS_ALPHA);
while (toHexString.length() < 2) {
toHexString = "0" + toHexString;
}
stringBuffer.append(toHexString);
}
return stringBuffer.toString();
} catch (Exception e) {
Logger.m22252a((Object) this, e);
return BuildConfig.FLAVOR;
}
}
The function computes the MD5 digest of the input, takes each byte of the computed MD5, "ANDize" with RadialCountdown.PROGRESS_ALPHA, translates to hex (pad with 0 to have 2 char) and appends that to the ouput.
There is probably a way to do the same thing in php (using md5()?).

Issue with java, String.getBytes method

I have a byte array of size 8.
I am converting it to string using the following code. (See below).
Now, when I convert the string again to byte[] using getBytes method, the result is absurd, which is a 16-sized byte[] with only a few (2 or 3) matching bytes to the previous byte array. Can someone tell me where I am going wrong?
byte[] message = new byte[8];
//initialize message
printBytes("message: " + message.length + " = ", message);
try {
String test = new String(message, "utf-8");
System.out.println(test);
byte[] f = test.getBytes("utf-8");
Help.printBytes("test = " + f.length, f);
} catch (UnsupportedEncodingException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
printBytes function:
public static void printBytes(String msg, byte[] b){
System.out.print(msg + " = ");
for(int i = 0; i < b.length; i++){
System.out.print("" + String.format("%02X", b[i]));
}
System.out.println("\n");
}
Output:
message: 8 = = 9A52D5D6C6E999AD
�R���陭
test = 16 = EFBFBD52EFBFBDEFBFBDEFBFBDE999AD
Your original byte[] had illegal byte sequences (that is, sequences that don't form valid UTF-8 characters). This has unspecified behavior for the String(byte[], String) constructor, but in your implementation, these bad bytes are replaced by the "�" characters, which is \uFFFD -- a three-byte character in UTF-8. You seem to have four of these, which account for 12 bytes right there.
new String(message, "utf-8");
This code tells the string object, that your message utf-8 encoded is.
test.getBytes("utf-8");
This code means, give me the bytes of string and encode as utf-8 encoded string. The result is, your string will be double utf-8 encoded.
Do once code, only.
String test = new String(message, "utf-8");
test.getBytes();
Sample for double encoded strings:
public class Test {
public static void main(String[] args) {
try {
String message = "äöü";
Test.printBytes("java internal encoded: = ", message.getBytes());
Test.printBytes("utf-8 encoded: = ", message.getBytes("utf-8"));
// get the string utf-8 encoded and create a new string with the
// utf-8 encoded content
message = new String(message.getBytes("utf-8"), "utf-8");
Test.printBytes("test get bytes without charset: = ", message.getBytes());
Test.printBytes("test get bytes with charset: = ", message.getBytes("utf-8"));
System.out.println(message);
System.out.println("double encoded: " + new String(message.getBytes("utf-8")));
} catch (Exception e) {
e.printStackTrace();
}
}
public static void printBytes(String msg, byte[] b) {
System.out.print(msg + " = ");
for (int i = 0; i < b.length; i++) {
System.out.print("" + String.format("%02X", b[i]));
}
System.out.println("\n");
}
}
Ouput:
java internal encoded: = = E4F6FC
utf-8 encoded: = = C3A4C3B6C3BC
test get bytes without charset: = = E4F6FC
test get bytes with charset: = = C3A4C3B6C3BC
äöü
double encoded: äöü <-- the java internal encoding is not converted to utf-8, it is double encoded

Convert HMAC-SHA256 function from Java to Ruby

I'm trying to convert this hashing function to Ruby from Java.
Java code:
Mac localMac = "HMAC-SHA256";
String str1 = "a4d1b77bbb1a4a5ca695ad72c84b77e5";
localMac.init(new SecretKeySpec(str1.getBytes("UTF-8"), localMac.getAlgorithm()));
byte[] arrayOfByte = localMac.doFinal("{"_uid":"3396112","_csrftoken":"a23482932482sdsf4428","media_id":"616150302791211280_187036957"}");
BigInteger localBigInteger = new BigInteger(1, arrayOfByte);
String str3 = String.format("%0" + (arrayOfByte.length << 1) + "x", new Object[] { localBigInteger });
return str3;
Ruby code:
require 'openssl'
require 'base64'
secret = "a4d1b77bbb1a4a5ca695ad72c84b77e5"
digest = OpenSSL::Digest::Digest.new('sha256')
hash = OpenSSL::HMAC.hexdigest(digest, secret,'{"_uid":"3396112","_csrftoken":"a23482932482sdsf4428","media_id":"616150302791211280_187036957"}')
p hash
For some reason the hashes are never the same. Any help?
You can do it like this
public static void main(String[] args) {
String str1 = "a4d1b77bbb1a4a5ca695ad72c84b77e5";
byte[] keyBytes = str1.getBytes();
SecretKeySpec localMac = new SecretKeySpec(
keyBytes, "HmacSHA256");
final String inputStr = "{\"_uid\":\"3396112\",\"_csrftoken\":"
+ "\"a23482932482sdsf4428\","
+ "\"media_id\":\"616150302791211280_187036957\"}";
try {
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(localMac);
// Compute the hmac on input data bytes
byte[] arrayOfByte = mac.doFinal(inputStr
.getBytes());
BigInteger localBigInteger = new BigInteger(1,
arrayOfByte);
String str3 = String.format("%0"
+ (arrayOfByte.length << 1) + "x",
new Object[] { localBigInteger });
System.out.println(str3);
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IllegalStateException e) {
e.printStackTrace();
}
}
Which will output e48d690dc6825e8f2895845be112fb1e5ee22f5283f2243512d6cca2714e8b35.
$ cat test.rb
#!/usr/bin/env ruby
require 'openssl'
require 'base64'
secret = "a4d1b77bbb1a4a5ca695ad72c84b77e5"
digest = OpenSSL::Digest::Digest.new('sha256')
hash = OpenSSL::HMAC.hexdigest(digest, secret,'{"_uid":"3396112","_csrftoken":"a23482932482sdsf4428","media_id":"616150302791211280_187036957 "}')
p hash
$ ./test.rb
"e48d690dc6825e8f2895845be112fb1e5ee22f5283f2243512d6cca2714e8b35"

Java SHA512 digest output differs from PHP script

Can someone figure out why the output of these (php and java) snippets of code don't return the same SHA512 for the same input?
$password = 'whateverpassword';
$salt = 'ieerskzcjy20ec8wkgsk4cc8kuwgs8g';
$salted = $password.'{'.$salt.'}';
$digest = hash('sha512', $salted, true);
echo "digest: ".base64_encode($digest);
for ($i = 1; $i < 5000; $i++) {
$digest = hash('sha512', $digest.$salted, true);
}
$encoded_pass = base64_encode($digest);
echo $encoded_pass;
This is the code on the android application:
public String processSHA512(String pw, String salt, int rounds)
{
try {
md = MessageDigest.getInstance("SHA-512");
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
throw new RuntimeException("No Such Algorithm");
}
String result = hashPw(pw, salt, rounds);
System.out.println(result);
return result;
}
private static String hashPw(String pw, String salt, int rounds) {
byte[] bSalt;
byte[] bPw;
String appendedSalt = new StringBuilder().append('{').append(salt).append('}').toString();
try {
bSalt = appendedSalt.getBytes("ISO-8859-1");
bPw = pw.getBytes("ISO-8859-1");
} catch (UnsupportedEncodingException e) {
throw new RuntimeException("Unsupported Encoding", e);
}
byte[] digest = run(bPw, bSalt);
Log.d(LCAT, "first hash: " + Base64.encodeBytes(digest));
for (int i = 1; i < rounds; i++) {
digest = run(digest, bSalt);
}
return Base64.encodeBytes(digest);
}
private static byte[] run(byte[] input, byte[] salt) {
md.update(input);
return md.digest(salt);
}
The library for base64 encoding is this: base64lib
This java code is actually some modified code I found around another question in StackOverflow.
Although the Android code is running fine it doesn't match with the output from the php script. It doesn't even match the first hash!
Note 1: On php hash('sha512',$input, $raw_output) returns raw binary output
Note 2: On java I tried to change the charset (UTF-8, ASCII) but it also didn't work.
Note 3: The code from the server can not be changed, so I would appreciate any answer regarding how to change my android code.
The first hash should be the same on the server and in Java. But then in the loop what gets appended to the digest is password{salt} in the PHP code, but only {salt} in the Java code.
For the lazy ones, one example better than a thousand words ;). I finally understood what was happening. The method update appends bytes to the digest, so when you append $password.{$salt} is the same as doing mda.update(password bytes) and the mda.digest("{$salt}" bytes. I do that answer because I was going crazy finding why it was not working and it was all in this answer.
Thanks guys.
This is the example that works in a Java Server:
public static String hashPassword(String password, String salt) throws Exception {
String result = password;
String appendedSalt = new StringBuilder().append('{').append(salt).append('}').toString();
String appendedSalt2 = new StringBuilder().append(password).append('{').append(salt).append('}').toString();
if(password != null) {
//Security.addProvider(new BouncyCastleProvider());
MessageDigest mda = MessageDigest.getInstance("SHA-512");
byte[] pwdBytes = password.getBytes("UTF-8");
byte[] saltBytes = appendedSalt.getBytes("UTF-8");
byte[] saltBytes2 = appendedSalt2.getBytes("UTF-8");
byte[] digesta = encode(mda, pwdBytes, saltBytes);
//result = new String(digesta);
System.out.println("first hash: " + new String(Base64.encode(digesta),"UTF-8"));
for (int i = 1; i < ROUNDS; i++) {
digesta = encode(mda, digesta, saltBytes2);
}
System.out.println("last hash: " + new String(Base64.encode(digesta),"UTF-8"));
result = new String(Base64.encode(digesta));
}
return result;
}
private static byte[] encode(MessageDigest mda, byte[] pwdBytes,
byte[] saltBytes) {
mda.update(pwdBytes);
byte [] digesta = mda.digest(saltBytes);
return digesta;
}

Categories