Sha256 hash function gives a longer hashed string in objective c than Java. Extra Zeros being added in objective C, how can I rationalise the hashing?
Objective C:
-(NSString*) sha256:(NSString *)clear{
const char *s=[clear cStringUsingEncoding:NSASCIIStringEncoding];
NSData *keyData=[NSData dataWithBytes:s length:strlen(s)];
uint8_t digest[CC_SHA256_DIGEST_LENGTH]={0};
CC_SHA256(keyData.bytes, keyData.length, digest);
NSData *out=[NSData dataWithBytes:digest
length:CC_SHA256_DIGEST_LENGTH];
NSString *hash=[out description];
hash = [hash stringByReplacingOccurrencesOfString:#" " withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#"<" withString:#""];
hash = [hash stringByReplacingOccurrencesOfString:#">" withString:#""];
return hash;
}
Java
public static String generateHashString(String data)
{
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
byte[] dataInBytes = data.getBytes(StandardCharsets.UTF_8);
md.update(dataInBytes);
byte[] mdbytes = md.digest();
StringBuffer hexString = new StringBuffer();
for (int i=0;i<mdbytes.length;i++) {
hexString.append(Integer.toHexString(0xFF & mdbytes[i]));
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
Integer.toHexString() on an integer less than 16 will only be one character long, whereas you want the extra '0' character.
You could use String.format():
for (int i = 0; i < mdbytes.length; i++) {
hexString.append(String.format("%02x", 0xFF & mdbytes[i]));
}
Also, you really should be using StringBuilder rather than StringBuffer in this case because only a single thread is involved.
See Java code To convert byte to Hexadecimal for some alternative solutions to hex-encoding a byte array in Java.
Related
I used the function below to calculate a hash of password. My problem is when I try to print hashcode I get an array of int even that the hash variable is of type String.
private static String getHashCode(String password) {
String hash = "";
try {
MessageDigest md5 = MessageDigest.getInstance("SHA-512");
byte [] digest = md5.digest(password.getBytes("UTF-8"));
hash = Arrays.toString(digest);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
System.out.println(hash);
return hash;
}
That is because you called Arrays.toString which returns a direct string representation of the array.
Instead, you probably want a hexadecimal representation of the byte[] array, which you can do with something like this (untested):
StringBuilder hexString = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
String hex = Integer.toHexString(0xFF & digest[i]);
if (hex.length() == 1) {
hexString.append('0');
}
hexString.append(hex);
}
String hash = hexString.toString();
This is normal. You are calling:
hash = Arrays.toString(digest);
So you get a string which represents the array digest in a string form.
As you see byte [] digest is a byte array that contain int values after that you transform to string so confert array of int into string so it's normal....
public static void main(String[] args) throws SignatureException {
String data = "GET"+"\n"+"webservices.amazon.com"+"\n"+"/onca/xml"+"\n"+"AWSAccessKeyId=AKIAIOSFODNN7EXAMPLE&ItemId=0679722769&Operation=ItemLookup&ResponeGroup=ItemAttributes%2COffers%2CImages%2CReviews&Service=AWSECommerceService&Timestamp=2009-01-01T12%3A00%3A00Z&Version=2009-01-06";
String key = "1234567890";
String result = calculateRFC2104HMAC(data, key);
System.out.println(result);
}
private static final String HMAC_SHA_ALGORITHM = "HmacSHA256";
public static String calculateRFC2104HMAC(String data, String key)throws java.security.SignatureException{
String result;
try {
// get an hmac_sha256 key from the raw key bytes
SecretKeySpec signingKey = new SecretKeySpec(key.getBytes("UTF-8"), HMAC_SHA_ALGORITHM);
// get an hmac_sha256 Mac instance and initialize with the signing key
Mac mac = Mac.getInstance(HMAC_SHA_ALGORITHM);
mac.init(signingKey);
// compute the hmac256 on input data bytes
byte[] rawHmac = mac.doFinal(data.getBytes("UTF-8"));
// base64-encode the hmac256
result = Base64.encodeBase64String(rawHmac);
} catch (Exception e) {
throw new SignatureException("Failed to generate HMAC : " + e.getMessage());
}
return result;
}
So I am trying to calculate this hmac with sha256 for AWS, but I do not get the excpected result, even though this example is taken from official AWS docs: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSDeveloperGuide/AuthJavaSampleHMACSignature.html And the only thing changed is the algorithm, which did not break the program, so it should work, but it does not.
The result I get: k1T/qvVoXgEvmdFhTEh71vLDznqEVCyKcslA5RRSB6s=
The result I expect: M/y0+EAFFGaUAp4bWv/WEuXYah99pVsxvqtAuC8YN7I=
Does anyone have any idea what is wrong?
It may have to do with how the newline character is interpreted. \n can be a cr, lf, or cr-lf depending on your OS.
AWS uses to two different HMAC functions, the first returns the string representation, the other returns the binary representation. This is from my C++ implementation using OpenSSL, hope it helps:
string hmacHex(string key, string msg)
{
unsigned char hash[32];
HMAC_CTX hmac;
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL);
HMAC_Update(&hmac, (unsigned char*)&msg[0], msg.length());
unsigned int len = 32;
HMAC_Final(&hmac, hash, &len);
HMAC_CTX_cleanup(&hmac);
std::stringstream ss;
ss << std::hex << std::setfill('0');
for (int i = 0; i < len; i++)
{
ss << std::hex << std::setw(2) << (unsigned int)hash[i];
}
return (ss.str());
}
the string implementation
string hmac(string key, string msg)
{
unsigned char hash[32];
HMAC_CTX hmac;
HMAC_CTX_init(&hmac);
HMAC_Init_ex(&hmac, &key[0], key.length(), EVP_sha256(), NULL);
HMAC_Update(&hmac, ( unsigned char* )&msg[0], msg.length());
unsigned int len = 32;
HMAC_Final(&hmac, hash, &len);
HMAC_CTX_cleanup(&hmac);
std::stringstream ss;
ss << std::setfill('0');
for (int i = 0; i < len; i++)
{
ss << hash[i];
}
return (ss.str());
}
If you are using Java, I'd recommend using the corresponding SDK. I my experience the API's tend to change rather quickly.
I'm having a lot of trouble converting the following code to Objective-C, can anyone lend a hand:
public String encodeString(String s) {
try {
// Create MD5 Hash
MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
Base64 b = null;
return b.encodeToString(messageDigest,1);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
This should work:
#import <CommonCrypto/CommonDigest.h>
- (NSString *) encodeString:(NSString *) s {
const char *cStr = [s UTF8String];
unsigned char result[CC_MD5_DIGEST_LENGTH];
CC_MD5(cStr, strlen(cStr), result);
NSMutableString *result = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH * 2];
for(int i = 0; i < CC_MD5_DIGEST_LENGTH; ++i) {
[result appendFormat:#"%02x", result[i]];
}
return [NSString stringWithString:result];
}
How can I hash some String with SHA-256 in Java?
SHA-256 isn't an "encoding" - it's a one-way hash.
You'd basically convert the string into bytes (e.g. using text.getBytes(StandardCharsets.UTF_8)) and then hash the bytes. Note that the result of the hash would also be arbitrary binary data, and if you want to represent that in a string, you should use base64 or hex... don't try to use the String(byte[], String) constructor.
e.g.
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
I think that the easiest solution is to use Apache Common Codec:
String sha256hex = org.apache.commons.codec.digest.DigestUtils.sha256Hex(stringText);
Another alternative is Guava which has an easy-to-use suite of Hashing utilities. For example, to hash a string using SHA256 as a hex-string you would simply do:
final String hashed = Hashing.sha256()
.hashString("your input", StandardCharsets.UTF_8)
.toString();
Full example hash to string as another string.
public static String sha256(final String base) {
try{
final MessageDigest digest = MessageDigest.getInstance("SHA-256");
final byte[] hash = digest.digest(base.getBytes("UTF-8"));
final StringBuilder hexString = new StringBuilder();
for (int i = 0; i < hash.length; i++) {
final String hex = Integer.toHexString(0xff & hash[i]);
if(hex.length() == 1)
hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
} catch(Exception ex){
throw new RuntimeException(ex);
}
}
If you are using Java 8 you can encode the byte[] by doing
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(text.getBytes(StandardCharsets.UTF_8));
String encoded = Base64.getEncoder().encodeToString(hash);
import java.security.MessageDigest;
public class CodeSnippets {
public static String getSha256(String value) {
try{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(value.getBytes());
return bytesToHex(md.digest());
} catch(Exception ex){
throw new RuntimeException(ex);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuffer result = new StringBuffer();
for (byte b : bytes) result.append(Integer.toString((b & 0xff) + 0x100, 16).substring(1));
return result.toString();
}
}
String hashWith256(String textToHash) {
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] byteOfTextToHash = textToHash.getBytes(StandardCharsets.UTF_8);
byte[] hashedByetArray = digest.digest(byteOfTextToHash);
String encoded = Base64.getEncoder().encodeToString(hashedByetArray);
return encoded;
}
I traced the Apache code through DigestUtils and sha256 seems to default back to java.security.MessageDigest for calculation. Apache does not implement an independent sha256 solution. I was looking for an independent implementation to compare against the java.security library. FYI only.
In Java 8
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import javax.xml.bind.DatatypeConverter;
Scanner scanner = new Scanner(System.in);
String password = scanner.nextLine();
scanner.close();
MessageDigest digest = null;
try {
digest = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
String encoded = DatatypeConverter.printHexBinary(hash);
System.out.println(encoded.toLowerCase());
This was my approach using Kotlin:
private fun getHashFromEmailString(email : String) : String{
val charset = Charsets.UTF_8
val byteArray = email.toByteArray(charset)
val digest = MessageDigest.getInstance("SHA-256")
val hash = digest.digest(byteArray)
return hash.fold("", { str, it -> str + "%02x".format(it)})
}
This is what i have been used for hashing:
String pass = "password";
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte hashBytes[] = messageDigest.digest(pass.getBytes(StandardCharsets.UTF_8));
BigInteger noHash = new BigInteger(1, hashBytes);
String hashStr = noHash.toString(16);
Output: 5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8
Here is a slightly more performant way to turn the digest into a hex string:
private static final char[] hexArray = "0123456789abcdef".toCharArray();
public static String getSHA256(String data) {
StringBuilder sb = new StringBuilder();
try {
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(data.getBytes());
byte[] byteData = md.digest();
sb.append(bytesToHex(byteData);
} catch(Exception e) {
e.printStackTrace();
}
return sb.toString();
}
private static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for ( int j = 0; j < bytes.length; j++ ) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return String.valueOf(hexChars);
}
Does anyone know of a faster way in Java?
This method return a left padded String with zero:
Java 10 and after:
public static String sha256(String text) {
try {
var messageDigest = MessageDigest.getInstance("SHA-256");
var hash = messageDigest.digest(text.getBytes(StandardCharsets.UTF_8));
return String.format("%064x", new BigInteger(1, hash));
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
Java 8:
public static String sha256(String text) {
try {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(text.getBytes(StandardCharsets.UTF_8));
return String.format("%064x", new BigInteger(1, hash));
}
catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
BTW, you can use "%064X" for an uppercase result.
Example:
System.out.println(sha256("hello world 1"));
063dbf1d36387944a5f0ace625b4d3ee36b2daefd8bdaee5ede723637efb1cf4
Comparison to Linux cmd:
$ echo -n 'hello world 1' | sha256sum
063dbf1d36387944a5f0ace625b4d3ee36b2daefd8bdaee5ede723637efb1cf4 -
You can use MessageDigest in the following way:
public static String getSHA256(String data){
StringBuffer sb = new StringBuffer();
try{
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update(data.getBytes());
byte byteData[] = md.digest();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
} catch(Exception e){
e.printStackTrace();
}
return sb.toString();
}
Here's a method that shows how to hash a String with the sha-256
algorithm and encode the result in hex format. This is an often used format to hash and store passwords in a database:
public static String sha256(final String data) {
try {
final byte[] hash = MessageDigest.getInstance("SHA-256").digest(data.getBytes(StandardCharsets.UTF_8));
final StringBuilder hashStr = new StringBuilder(hash.length);
for (byte hashByte : hash)
hashStr.append(Integer.toHexString(255 & hashByte));
return hashStr.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
public static String sha256(String s) {
try {
return DatatypeConverter.printHexBinary(MessageDigest.getInstance("SHA-256").digest(s.getBytes(StandardCharsets.UTF_8))).toLowerCase();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return null;
}
In Java, MessageDigest class is used to calculate cryptographic hashing value. This class provides cryptographic hash function ( MD5, SHA-1 and SHA-256) to find hash value of text.
Code example for using SHA-256 algorithm.
public void printHash(String str) throws NoSuchAlgorithmException {
MessageDigest md=MessageDigest.getInstance("SHA-256");
byte[] sha256=md.digest(str.getBytes(StandardCharsets.UTF_8));
for(byte b : sha256){
System.out.printf("%02x",b);
}
}
private static String getMessageDigest(String message, String algorithm) {
MessageDigest digest;
try {
digest = MessageDigest.getInstance(algorithm);
byte data[] = digest.digest(message.getBytes("UTF-8"));
return convertByteArrayToHexString(data);
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
You can call above method with different algorithms like below.
getMessageDigest(message, "MD5");
getMessageDigest(message, "SHA-256");
getMessageDigest(message, "SHA-1");
You can refer this link for complete application.
I understand how it works but if I want to print out the MD5 as String how would I do that?
public static void getMD5(String fileName) throws Exception{
InputStream input = new FileInputStream(fileName);
byte[] buffer = new byte[1024];
MessageDigest hash = MessageDigest.getInstance("MD5");
int read;
do {
read = input.read(buffer);
if (read > 0) {
hash.update(buffer, 0, read);
}
} while (read != -1);
input.close();
}
You can get it writing less:
String hex = (new HexBinaryAdapter()).marshal(md5.digest(YOUR_STRING.getBytes()))
String input = "168";
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] md5sum = md.digest(input.getBytes());
String output = String.format("%032X", new BigInteger(1, md5sum));
or
DatatypeConverter.printHexBinary( MessageDigest.getInstance("MD5").digest("a".getBytes("UTF-8")))
Try this
StringBuffer hexString = new StringBuffer();
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = md.digest();
for (int i = 0; i < hash.length; i++) {
if ((0xff & hash[i]) < 0x10) {
hexString.append("0"
+ Integer.toHexString((0xFF & hash[i])));
} else {
hexString.append(Integer.toHexString(0xFF & hash[i]));
}
}
You can also use Apache Commons Codec library.
This library includes methods public static String md5Hex(InputStream data) and public static String md5Hex(byte[] data) in the DigestUtils class.
No need to invent this yourself ;)
First you need to get the byte[] output of the MessageDigest:
byte[] bytes = hash.digest();
You can't easily print this though (with e.g. new String(bytes)) because it's going to contain binary that won't have good output representations. You can convert it to hex for display like this however:
StringBuilder sb = new StringBuilder(2 * bytes.length);
for (byte b : bytes) {
sb.append("0123456789ABCDEF".charAt((b & 0xF0) >> 4));
sb.append("0123456789ABCDEF".charAt((b & 0x0F)));
}
String hex = sb.toString();
Shortest way:
String toMD5(String input) {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] raw = md.digest(input.getBytes());
return DatatypeConverter.printHexBinary(raw);
}
Just remember to handle the exception.
With the byte array, result from message digest:
...
byte hashgerado[] = md.digest(entrada);
...
for(byte b : hashgerado)
System.out.printf("%02x", Byte.toUnsignedInt(b));
Result (for example):
89e8a9f68ad3c4bba9b9d3581cf5201d
/**
* hashes:
* e7cfa2be5969e235138356a54bad7fc4
* 3c9ec110aa171b57bb41fc761130822c
*
* compiled with java 8 - 12 Dec 2015
*/
public static String generateHash() {
long r = new java.util.Random().nextLong();
String input = String.valueOf(r);
String md5 = null;
try {
java.security.MessageDigest digest = java.security.MessageDigest.getInstance("MD5");
//Update input string in message digest
digest.update(input.getBytes(), 0, input.length());
//Converts message digest value in base 16 (hex)
md5 = new java.math.BigInteger(1, digest.digest()).toString(16);
}
catch (java.security.NoSuchAlgorithmException e) {
e.printStackTrace();
}
return md5;
}
FYI...
In certain situations this did not work for me
md5 = new java.math.BigInteger(1, digest.digest()).toString(16);
but this did
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if ((0xff & digest[i]) < 0x10) {
sb.append("0").append(Integer.toHexString((0xFF & digest[i])));
} else {
sb.append(Integer.toHexString(0xFF & digest[i]));
}
}
String result = sb.toString();
Call hash.digest() to finish the process. It will return an array of bytes.
You can create a String from a byte[] using a String constructor, however if you want a hex string you'll have to loop through the byte array manually and work out the characters.
This is another version of #anything answer:
StringBuilder sb = new StringBuilder();
for (int i = 0; i < digest.length; i++) {
if ((0xff & digest[i]) < 0x10) {
sb.append("0").append(Integer.toHexString((0xFF & digest[i])));
} else {
sb.append(Integer.toHexString(0xFF & digest[i]));
}
}
String result = sb.toString();