Make SHA1 encryption on Android? - java

Can you suggest me about how to encrypt string using SHA1 algorithm ?
I've searched about it. But no luck.
Thanks in advance.

binnyb's convertToHex method is not working properly. A more correct one that works for me is:
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if ((0 <= halfbyte) && (halfbyte <= 9)) {
buf.append((char) ('0' + halfbyte));
}
else {
buf.append((char) ('a' + (halfbyte - 10)));
}
halfbyte = data[i] & 0x0F;
} while(two_halfs++ < 1);
}
return buf.toString();
}
public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] sha1hash = new byte[40];
md.update(text.getBytes("iso-8859-1"), 0, text.length());
sha1hash = md.digest();
return convertToHex(sha1hash);
}
use the SHA1 method to get your sha1 string.
Update: providing a complete answer

here are 2 methods i have found while searching for a sha1 algorithm implementation:
private static String convertToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
int length = data.length;
for(int i = 0; i < length; ++i) {
int halfbyte = (data[i] >>> 4) & 0x0F;
int two_halfs = 0;
do {
if((0 <= halfbyte) && (halfbyte <= 9))
buf.append((char) ('0' + halfbyte));
else
buf.append((char) ('a' + (halfbyte - 10)));
halfbyte = data[i] & 0x0F;
}
while(++two_halfs < 1);
}
return buf.toString();
}
public static String SHA1(String text) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md = MessageDigest.getInstance("SHA-1");
byte[] sha1hash = new byte[40];
md.update(text.getBytes("iso-8859-1"), 0, text.length());
sha1hash = md.digest();
return convertToHex(sha1hash);
}
use the SHA1 method to get your sha1 string. I have not confirmed that this is indeed a sha1, but it works for my apps.

I've answered this before (How to SHA1 hash a string in Android?) but it fits here, as well:
Android comes with Apache's Commons Codec so you can simply use the following line to create a SHA-1 hexed String:
String myHexHash = DigestUtils.shaHex(myFancyInput);
That is the old deprecated method you get with Android 4 by default. The new versions of DigestUtils bring all flavors of shaHex() methods like sha256Hex() and also overload the methods with different argument types.
Of course, there is more functionality in DigestUtils and the rest of Commons Codec. Just have a look.
http://commons.apache.org/proper/commons-codec//javadocs/api-release/org/apache/commons/codec/digest/DigestUtils.html
EDIT:
If you get a ClassNotFoundError you will have to explicitly add commons-codec as dependency (even though it should come with Android as transitive dependency), in Maven e.g.:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.7</version>
</dependency>
And also, you will have to change the call to:
String myHexHash = new String(Hex.encodeHex(DigestUtils.sha512(myFancyInput)));
(My humble guess is that this is probably due to a ClassLoader issue (class name collision) in the Android VM - which would actually prove that the commons-codec classes are already present...)
See also:
https://stackoverflow.com/a/9284092/621690

binnyb set me on the right track, but I found some more, easier to understand code here:
http://www.coderanch.com/t/526487/java/java/Java-Byte-Hex-String
private static String convertToHex(byte[] data) {
StringBuilder sb = new StringBuilder(data.length * 2);
Formatter fmt = new Formatter(sb);
for (byte b : data) {
fmt.format("%02x", b);
}
return sb.toString();
}

Related

Enable Java sha1 raw mode like php sha1

I get a problem with php.sha1 and my java code.
My php code
echo base64_encode(sha1("test", TRUE));
qUqP5cyxm6YcTAhz05Hph5gvu9M=
And my java code is:
static String Hash(String input) throws Exception {
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(input.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
sb.append((result[i / Byte.SIZE] << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
}
return base64_encode(sb.toString());
}
output MTAxMDEwMDEwMTAwMTAxMDEwMDA=
How should I change the loop to get equal strings?
This one should works like RAW SHA-1
String base64 =
Base64.getEncoder().encodeToString(MessageDigest.
getInstance("SHA-1").digest(s.getBytes("ISO-8859-1")));

Google OTP Generation Java

I am currently trying to recreate a Google One Time Password generator. I use a shared secret generated when I setup Google Authenticator.
I tried looking into the Google Authenticator sources and all around the internet really and I find a lot of similarities with my code but I can't really find where i'm wrong.
The first part seems correct. As for the hmac, I don't think I could mess up here but I might be wrong. The truncating part is still a bit blurry for me and I tried a lot of different implementations but I just cannot get a working OTP. (I'm using Google Authenticator to compare the results)
private String truncateHash(byte[] hash) {
int offset = hash[hash.length - 1] & 0xF;
long truncatedHash = 0;
for (int i = 0; i < 4; ++i) {
truncatedHash <<= 8;
truncatedHash |= (hash[offset + i] & 0xFF);
}
truncatedHash &= 0x7FFFFFFF;
truncatedHash %= 1000000;
int code = (int) truncatedHash;
String result = Integer.toString(code);
for (int i = result.length(); i < 6; i++) {
result = "0" + result;
}
return result;
}
private byte[] hmacSha1(byte[] value, byte[] keyBytes) {
try {
Mac mac = HmacUtils.getHmacSha1(keyBytes);
byte[] rawHmac = mac.doFinal(value);
return new Hex().encode(rawHmac);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String GoogleAuthenticatorCode(String secret) throws UnsupportedEncodingException {
Base32 base = new Base32();
byte[] key = base.decode(secret);
//Update from Andrew Rueckert's response
long value = new Date().getTime() / TimeUnit.SECONDS.toMillis(30);
byte[] data = new byte[8];
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
//
System.out.println("Time remaining : " + new Date().getTime() / 1000 % 30);
byte[] hash = hmacSha1(data, key);
return truncateHash(hash);
}
UPDATE :
I tried copying and pasting the code from Andrew Rueckert's response's link as well as this one https://github.com/wstrange/GoogleAuth/blob/master/src/main/java/com/warrenstrange/googleauth/GoogleAuthenticator.java and the one from RFC 4226. Neither of these give me a correct OTP
Can anyone enlighten me please?
Your byte value[] needs to be the byte representation of the time as a long, and it looks like it's currently the byte representation of that number as a String of digit characters. Instead of
Double time = floor(new Date().getTime() / 1000 / 30);
String message = String.valueOf(time.intValue());
byte[] value = message.getBytes("UTF-8");
byte[] hash = hmacSha1(value, key);
You'd want something like:
// decimal truncation is free when dealing with int/long
long value = new Date().getTime() / 1000 / 30;
byte[] data = new byte[8];
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
byte[] hash = hmacSha1(data, key);
I managed to get a Google TOTP implementation set up by following this guide, if you want one more resource to look into.
I solved my problem so I thought I would post it there in case someone needs it.
It was partialy due to the Base32 class I was using which didn't return a correct key. The truncating wasn't correct either.
It's compatible with Google Authenticator app.
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Authentication {
Authentication() {};
private String truncateHash(byte[] hash) {
String hashString = new String(hash);
int offset = Integer.parseInt(hashString.substring(hashString.length() - 1, hashString.length()), 16);
String truncatedHash = hashString.substring(offset * 2, offset * 2 + 8);
int val = Integer.parseUnsignedInt(truncatedHash, 16) & 0x7FFFFFFF;
String finalHash = String.valueOf(val);
finalHash = finalHash.substring(finalHash.length() - 6, finalHash.length());
return finalHash;
}
private byte[] hmacSha1(byte[] value, byte[] keyBytes) {
SecretKeySpec signKey = new SecretKeySpec(keyBytes, "HmacSHA1");
try {
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(signKey);
byte[] rawHmac = mac.doFinal(value);
return new Hex().encode(rawHmac);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public String GoogleAuthenticatorCode(String secret) throws Exception {
if (secret == null || secret == "") {
throw new Exception("Secret key does not exist.");
}
long value = new Date().getTime() / TimeUnit.SECONDS.toMillis(30);
Base32 base = new Base32(Base32.Alphabet.BASE32, false, true);
byte[] key = base.fromString(secret);
byte[] data = new byte[8];
for (int i = 8; i-- > 0; value >>>= 8) {
data[i] = (byte) value;
}
byte[] hash = hmacSha1(data, key);
return truncateHash(hash);
}
}
The Base32 I used is available here if needed along with the rest of the project : https://github.com/Poncholay/OTPGenerator/blob/master/src/main/java/com/requireris/app/web/rest/Base32.java

Android MD5 issue calculating MD5, missing characters

I've been developing an Android App and in certain part of the app I need to calculate the MD5 of a certain string. I've been using the following code, but every now and then the output string if the byte it has to convert to String is lower than 10, then it will miss a 0 in the two byte representation:
MessageDigest di = java.security.MessageDigest.getInstance("MD5");
di.update(cadena.getBytes());
byte mdi[] = di.digest();
StringBuffer md5= new StringBuffer();
for (byte b : mdi) {
md5.append(Integer.toHexString(0xFF & b));
}
For example, if I pass the string 109370 the MD5 it will have to return is 932ff0696b0434d7a83e1ff84fe298c5 but instead it calculates the 932ff0696b434d7a83e1ff84fe298c5.
That's because the byte array has a 4 and Integer.toHexString() is returning only 1 char array instead of two.
Any thought about how can I handle this?
Thanks!
below is the code that i am using:
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
public class MD5Encode {
private static String convertedToHex(byte[] data) {
StringBuffer buf = new StringBuffer();
for (int i = 0; i < data.length; i++) {
int halfOfByte = (data[i] >>> 4) & 0x0F;
int twoHalfBytes = 0;
do {
if ((0 <= halfOfByte) && (halfOfByte <= 9)) {
buf.append((char) ('0' + halfOfByte));
} else {
buf.append((char) ('a' + (halfOfByte - 10)));
}
halfOfByte = data[i] & 0x0F;
} while (twoHalfBytes++ < 1);
}
return buf.toString();
}
public static String MD5(String text) throws NoSuchAlgorithmException,
UnsupportedEncodingException {
MessageDigest md;
md = MessageDigest.getInstance("MD5");
byte[] md5 = new byte[64];
md.update(text.getBytes("iso-8859-1"), 0, text.length());
md5 = md.digest();
return convertedToHex(md5);
}
}
and use it by this way:
MD5Encode.MD5("your string here")
hope this will help you :)
You can use a java.util.Formatter:
Formatter fmt = new Formatter(md5);
for (byte b : mdi) {
fmt.format("%02x", b&0xff);
}
fmt.close();
Use this:
public String calculateMD5(String string) {
StringBuilder result = new StringBuilder();
try {
MessageDigest m = MessageDigest.getInstance("MD5");
m.update(string.getBytes("UTF8"));
byte s[] = m.digest();
for (int i = 0; i < s.length; i++) {
result.append(Integer.toHexString((0x000000ff & s[i]) | 0xffffff00).substring(6));
}
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Password hash is unsupported by device android implementation.", e);
} catch (UnsupportedEncodingException e) {
throw new IllegalStateException("Password hash is unsupported by device android implementation.", e);
}
return result.toString();
}

Looking for javascript md5 method in java implementation

I have Javascript md5 on site auth.
I need to implement only this function:
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
I need help with following methods:
Convert an array of little-endian words to a hex string:
function binl2hex(binarray)
{
var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
var str = "";
for(var i = 0; i < binarray.length * 4; i++)
{
str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF);
}
return str;
}
Convert a string to an array of little-endian words
If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
function str2binl(str)
{
var bin = Array();
var mask = (1 << chrsz) - 1;
for(var i = 0; i < str.length * chrsz; i += chrsz)
bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
return bin;
}
If you're just looking to implement MD5, that's something which is built in to java.
https://stackoverflow.com/a/415971/576519
I have developed a simple Java MD5 function that is compatible with a standard JavaScript function you can download the class from: http://developersfound.com/HexMD5.zip
Here is the code:
/* This MD5 hash class is compatible with the JavaScript MD5 has code found at http://pajhome.org.uk/crypt/md5/md5.html */
package com.DevFound;
import java.security.MessageDigest;
public class HexMD5 {
public static String getMD5Str(String inputVal)throws Exception
{
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(inputVal.getBytes());
byte byteData[] = md.digest();
//convert the byte to hex format method 1
StringBuffer sb = new StringBuffer();
for (int i = 0; i < byteData.length; i++) {
sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
}
//convert the byte to hex format method 2
StringBuffer hexString = new StringBuffer();
for (int i=0;i<byteData.length;i++) {
String hex=Integer.toHexString(0xff & byteData[i]);
if(hex.length()==1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
}
I haven't tested this code with your particular JavaScript md5 function but I have listed the function that it is compatible with in the comment at the top of the code.

How to store password encrypted in database?

I am trying to store the password into the database in the encrypted form with the help of JSP and Servlets. How I can do that?
Self-written algorithms are a security risk, and painful to maintain.
MD5 is not secure.
Use the bcrypt algorithm, provided by jBcrypt (open source):
// Hash a password
String hashed = BCrypt.hashpw(password, BCrypt.gensalt());
// Check that an unencrypted password matches or not
if (BCrypt.checkpw(candidate, hashed))
System.out.println("It matches");
else
System.out.println("It does not match");
If you use Maven, you can get the library by inserting the following dependency in your pom.xml (if a newer version is available please let me know):
<dependency>
<groupId>de.svenkubiak</groupId>
<artifactId>jBCrypt</artifactId>
<version>0.4.1</version>
</dependency>
Try something like this to encrypt your data.
MessageDigest md = MessageDigest.getInstance("MD5");
......
synchronized (md) {
md.reset();
byte[] hash = md.digest(plainTextPassword.getBytes("CP1252"));
StringBuffer sb = new StringBuffer();
for (int i = 0; i < hash.length; ++i) {
sb.append(Integer.toHexString((hash[i] & 0xFF) | 0x100).toUpperCase().substring(1, 3));
}
String password = sb.toString();
}
You can also use something like below. Below is a crypt method which takes a string input and will return and encrypted string. You can pass password to this method.
public static String crypt(String str) {
if (str == null || str.length() == 0) {
throw new IllegalArgumentException(
"String to encrypt cannot be null or zero length");
}
StringBuffer hexString = new StringBuffer();
try {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(str.getBytes());
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]));
}
}
} catch (NoSuchAlgorithmException e) {
}
return hexString.toString();
}

Categories