Convert Java MessageDigest code snippet to C# - java

The java code below generates a SHA-256 hash of the input msg, using the key. However, all my attempts to write code that does same operation in C# have not yielded the same results given same input. I would need help getting the C# equivalent as I have tried a lot already with little success.
I think I've been able to translate most of the code into C# correctly, apart from the part which updates the digest (m.update()), first with the key, then later with the message before hashing.
JAVA CODE
public static String generateHash256Value(String msg, String key) {
MessageDigest m = null;
String hashText = null;
System.out.println("Value to hash::::::::::" + msg);
byte[] actualKeyBytes = HexToByte(secret_key);
try {
m = MessageDigest.getInstance("SHA-256");
m.update(actualKeyBytes, 0, actualKeyBytes.length);
try {
m.update(msg.getBytes("UTF-8"), 0, msg.length());
}
catch (UnsupportedEncodingException ex) {
ex.printStackTrace();
}
hashText = new BigInteger(1, m.digest()).toString(16);
if (hashText.length() < 64) { //must be 64 in length
int numberOfZeroes = 64 - hashText.length();
String zeroes = "";
for (int i = 0; i < numberOfZeroes; i++) {
zeroes = zeroes + "0";
}
hashText = zeroes + hashText;
}
}
catch (NoSuchAlgorithmException ex) {
ex.printStackTrace();
}
hashText = hashText.toUpperCase();
return hashText;
}
public static byte[] hex2Byte(String str) {
byte[] bytes = new byte[str.length() / 2];
for (int i = 0; i < bytes.length; i++) {
bytes[i] = (byte) Integer
.parseInt(str.substring(2 * i, 2 * i + 2), 16);
}
return bytes;
}
C# CODE (attempt)
private static string DoSpecialSha256Hash(string message, string key)
{
String hashText = null;
Console.WriteLine("Value to hash::::::::::" + message);
byte[] keyByte = hex2Byte(key);
Encoding encoder = new System.Text.UTF8Encoding();
var hashAlgo = new SHA256Managed();
var messageBytes = encoder.GetBytes(message);
var toDigest = Combine(keyByte, messageBytes);
hashText = ByteToString(hashAlgo.ComputeHash(toDigest, 0, message.Length));
if (hashText.Length < 64)
{ //must be 64 in length
int numberOfZeroes = 64 - hashText.Length;
String zeroes = "";
for (int i = 0; i < numberOfZeroes; i++)
{
zeroes = zeroes + "0";
}
hashText = zeroes + hashText;
}
hashText = hashText.ToUpper();
return hashText;
}
public static byte[] HexToByte(String hex)
{
return Enumerable.Range(0, hex.Length)
.Where(x => x % 2 == 0)
.Select(x => Convert.ToByte(hex.Substring(x, 2), 16))
.ToArray();
}
private static string ByteToString(byte[] buff)
{
string sbinary = "";
for (int i = 0; i < buff.Length; i++)
{
sbinary += buff[i].ToString("X2"); // hex format
}
return (sbinary);
}
private static byte[] Combine(params byte[][] arrays)
{
byte[] rv = new byte[arrays.Sum(a => a.Length)];
int offset = 0;
foreach (byte[] array in arrays)
{
System.Buffer.BlockCopy(array, 0, rv, offset, array.Length);
offset += array.Length;
}
return rv;
}
Thanks,

Related

How to translate custom md5 password + salt function in java to ruby?

I have the following java function:
public static String customPasswordFunction(String value, String salt) {
byte[] input = null;
try {
byte[] valueBytes = value.getBytes();
byte[] saltBytes = salt.getBytes();
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.reset();
digest.update(saltBytes);
input = digest.digest(valueBytes);
for(int i=0; i < 1000; i++) {
digest.reset();
input = digest.digest(input);
}
}
catch (NoSuchAlgorithmException ex) {
logger.error(ex.toString(), ex);
return null;
}
//convert digest to alphanumeric
String alphaNumReturn = "";
String tmp = null;
for (int i = 0; i < input.length; i++) {
tmp = (Integer.toHexString(0xFF & input[i]));
if (tmp.length() == 1) {
alphaNumReturn += "0" + tmp;
}
else {
alphaNumReturn += tmp;
}
}
return alphaNumReturn;
}
We have the quick ability in ruby to hash the salt and password as follows:
hashed_password = OpenSSL::Digest::MD5.hexdigest(salt+password)
But how would I re-produce the following java code in ruby?
for(int i=0; i < 1000; i++) {
digest.reset();
input = digest.digest(input);
}
So I don't know Java but it appears this part
digest = MessageDigest.getInstance("MD5");
digest.reset();
digest.update(saltBytes);
input = digest.digest(valueBytes);
for(int i=0; i < 1000; i++) {
digest.reset();
input = digest.digest(input);
}
Should translate to
require 'digest'
digest = Digest::MD5.new
digest.reset.update(salt)
input = digest.digest(value)
input = 1000
.times
.reduce(input) do |input,_|
digest.reset.digest(input)
end
Docs:
Digest::MD5
Integer#times
Enumerable#reduce
As a sidenote: MD5 is a hashing algorithm not an encryption.

hex to string chinese,chinese hex 2 byte ,english hex 1byte?

this is stringToHexAsciiString.
//将字符串转成ASCII十六进制的java方法
public static String stringToHexAsciiString(String value)
{
StringBuffer sbu = new StringBuffer();
char[] chars = value.toCharArray();
for (int i = 0; i < chars.length; i++)
{
sbu.append(Integer.toHexString(chars[i]));
}
return sbu.toString();
}
this is asciiToString begin
//将ASCII转成字符串的java方法
public static String asciiToString(String value)
{
StringBuffer sbu = new StringBuffer();
//System.out.println("value.length()/2 = " + value.length()/2);
byte[] chars = new byte[value.length()/2];
chars = hexStringToByte(value);
//System.out.println("chars.length = " + chars.length);
for(int i=0; i<chars.length; i++){
//sbu.append((char) Integer.parseInt(chars[i]));
byte[] change = new byte[1];
change[0] = chars[i];
//System.out.println("change[0] = " + change[0]);
sbu.append((char) chars[i]);
//System.out.println("i = " + i + " " + sbu.toString());
}
return sbu.toString();
}
public static byte[] hexStringToByte(String hexString){
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 |charToByte(hexChars[pos + 1]));
// d[i] = (byte) (hexChars[pos] << 4 |hexChars[pos + 1]);
}
return d;
}
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
use test english is ok,chinese is bad.
String strAscii = Encrypter.stringToHexAsciiString("汉1232").trim();
String asciiStr = Encrypter.asciiToString("6c4931323332".toUpperCase());
System.out.println("asciiStr:"+asciiStr);
System.out.println("strAscii:"+strAscii);
asciiToString result is chinese become messy code
asciiStr:lI1232
strAscii:6c4931323332
need to 汉1232.stringToHexAsciiString result :chinese char is 2 byte,english is 1 byte。how to div chinese hex and english hex。
I don't know what's the problem in your code... or what exactly you want, this is not clear in your question.
But if you just want convert a String to Hex format then you can try the following code:
import org.apache.commons.codec.binary.Hex;
public class StringToAscii
{
public static void main( String[] args )
{
try {
String s = "汉1232";
System.out.println(s);
String hexString = new String(Hex.encodeHexString(s.getBytes("UTF-8")));
System.out.println(hexString);
String unicode = new String(Hex.decodeHex(hexString.toCharArray()));
System.out.println(unicode);
}catch (Exception e)
{
e.printStackTrace();
}
}
}
The output on my laptop is:
汉1232
e6b18931323332
汉1232

Decrypt XOR on Java

Can any one help me write decrypt method for my XOR encryptor. So how i'm encrypt:
I'm making XOR
public static String idEncrypt(String id, String key)throws Exception
{
if (id == null)
return null;
if (key.length() == 0)
return id;
String utfID="", utfKey="";
try
{
utfID = new String(id.getBytes(), "UTF-8");
utfKey = new String(key.getBytes(), "UTF-8");
}
catch (UnsupportedEncodingException e)
{
Log.e("utf8", "conversion", e);
}
StringBuilder sb = new StringBuilder();
for(int i = 0; i < utfID.length(); i++)
sb.append((char)(utfID.charAt(i) ^ utfKey.charAt(i % utfKey.length())));
String result = sb.toString();
return toHex(result.getBytes());
}
Converting bytes to hex:
public static String toHex(byte[] buf) {
if (buf == null)
return "";
StringBuffer result = new StringBuffer(2*buf.length);
for (int i = 0; i < buf.length; i++) {
appendHex(result, buf[i]);
}
return result.toString();
}
private final static String HEX = "0123456789abcdef";
private static void appendHex(StringBuffer sb, byte b) {
sb.append(HEX.charAt((b>>4)&0x0f)).append(HEX.charAt(b&0x0f));
}
Actually all of my trying to decrypt result of this crypts failed =(
May be some on explains me how work with it?
P.S: the results of my trying is strings like "X¨»¾RkÖ_êQ", but must be 16 symbols of numbers and letters.
UPD:
My fromHEX() method
public static String fromHex(String hex) {
return new String(toByte(hex));
}
public static byte[] toByte(String hexString) {
int len = hexString.length()/2;
byte[] result = new byte[len];
for (int i = 0; i < len; i++)
result[i] = Integer.valueOf(hexString.substring(2*i, 2*i+2), 16).byteValue();
return result;
}

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();
}

Converting PHP mcrypt based security to a Java base (modified cryptastic)

after struggling for a while, I figured that I should bring my question here as I do not really know exactly what I am doing. Basically, I am using a somewhat modified version of the cryptastic version found here.
I am currently base64 encoding everything, then converting to hexidecimal in order to keep the data the same between the two langauges. Right now, I have managed to get decryption from PHP to work, but keep coming across errors when I try to encrypt. I am using BouncyCastle... and for some reason in the decrypt when I do an init, instead of using false it will only work with true (which the docs say is for encryption...)
Anyway, here is my class thus far if anyone has a chance to look at it that would be great.
Technically, decrypt is working only because I have a hack function to remove padding as the ZeroByteEncoding isn't working properly either.
So, I am able to decrypt from the PHP cryptastic, but not encrypt properly so that it can decrypt (it throws an error in my stringToHexidecimal then)
public class Cryptastic {
public final static String CHARSET = "US-ASCII";
public byte[] encrypt(String toEncrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
toEncrypt = serialize(toEncrypt);
byte[] newEncrypt = toEncrypt.getBytes(CHARSET);
BlockCipher blockCipher = new RijndaelEngine(256);
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[32];
secureRandom.nextBytes(iv);
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(true, cipherParameters);
int size = cipher.getOutputSize(newEncrypt.length);
byte[] encrypted = new byte[size];
System.out.println(displayBytes(encrypted, false));
int outputLength = cipher.processBytes(newEncrypt, 0, newEncrypt.length, encrypted, 0);
cipher.doFinal(encrypted, outputLength);
if(base64Encode)
{
encrypted = Base64.encode(encrypted);
}
byte[] temp = new byte[encrypted.length + 32];
for(int i = 0; i < iv.length; i++)
{
temp[i] = iv[i];
}
for(int i = iv.length; i < temp.length; i++)
{
temp[i] = encrypted[i - iv.length];
}
encrypted = temp;
byte[] mac = generateKey(encrypted, keyBytes, 1000, 32);
temp = new byte[encrypted.length + mac.length];
for(int i = 0; i < encrypted.length; i++)
{
temp[i] = encrypted[i];
}
for(int i = encrypted.length; i < temp.length; i++)
{
temp[i] = mac[i - encrypted.length];
}
return encrypted;
//System.out.println("Original IV: " + displayBytes(iv, false));
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] decrypt(String toDecrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
byte[] newDecrypt = hexToByte(toDecrypt);
//toDecrypt = hexToString(toDecrypt);
if(base64Encode)
{
newDecrypt = Base64.decode(newDecrypt);
//toDecrypt = new String(Base64.decode(toDecrypt.getBytes(CHARSET)), CHARSET);
}
byte[] iv = new byte[32];
byte[] extractedMac = new byte[32];
int offset = newDecrypt.length - 32;
for(int i = 0; i < 32; i++)
{
iv[i] = newDecrypt[i];
extractedMac[i] = newDecrypt[i + offset];
}
byte[] temp = new byte[offset - 32];
for(int i = 0; i < temp.length; i++)
{
temp[i] = newDecrypt[i + 32];
}
newDecrypt = temp;
byte[] combo = new byte[newDecrypt.length + iv.length];
for(int i = 0; i < iv.length; i++)
{
combo[i] = iv[i];
}
for(int i = iv.length; i < combo.length; i++)
{
combo[i] = newDecrypt[i - iv.length];
}
byte[] mac = generateKey(new String(combo, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
boolean matches = new String(extractedMac).equals(new String(mac));
if(!matches)
{
byte[] toReturn = new byte[0];
return toReturn;
}
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(true, cipherParameters);
int size = cipher.getOutputSize(newDecrypt.length);
byte[] decrypted = new byte[size];
System.out.println(displayBytes(newDecrypt, false));
System.out.println(displayBytes(decrypted, false));
int outputLength = cipher.processBytes(newDecrypt, 0, newDecrypt.length, decrypted, 0);
cipher.doFinal(decrypted, outputLength);
System.out.println(displayBytes(decrypted, false));
temp = new byte[newDecrypt.length];
for(int i = 0; i < temp.length; i++)
{
temp[i] = decrypted[i];
}
decrypted = temp;
decrypted = unserialize(new String(decrypted, CHARSET)).getBytes(CHARSET);
return decrypted;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(String password, String salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
String derived_key = "";
//System.out.println("Number of blocks: " + keyBlocks);
for(long block = 1; block <= keyBlocks; block++)
{
byte[] initialHash = hash_hmac(salt + new String(pack(block)/*, CHARSET */), password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
derived_key += new String(initialHash/*, CHARSET */);
}
return derived_key.substring(0, keyLength).getBytes(CHARSET);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(byte[] password, byte[] salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
byte[] derived_key = null;
//System.out.println("Number of blocks: " + keyBlocks);
for(long block = 1; block <= keyBlocks; block++)
{
byte[] packed = pack(block);
byte[] combined = new byte[salt.length + packed.length];
for(int i = 0; i < salt.length; i++)
{
combined[i] = salt[i];
}
for(int i = salt.length; i < combined.length; i++)
{
combined[i] = packed[i - salt.length];
}
byte[] initialHash = hash_hmac(combined, password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
{
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
if(derived_key == null)
{
derived_key = initialHash;
}
else
{
byte[] temp = new byte[derived_key.length + initialHash.length];
for(int i = 0; i < derived_key.length; i++)
{
temp[i] = derived_key[i];
}
for(int i = derived_key.length; i < temp.length; i++)
{
temp[i] = initialHash[i - derived_key.length];
}
derived_key = temp;
}
}
byte[] toReturn = new byte[keyLength];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = derived_key[i];
}
return toReturn;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] pack(long toPack)
{
String test = Long.toHexString(toPack);
while(test.length() < 8)
{
test = "0" + test;
}
byte[] toReturn = new byte[4];
toReturn[0] = Byte.parseByte(test.substring(0, 2));
toReturn[1] = Byte.parseByte(test.substring(2, 4));
toReturn[2] = Byte.parseByte(test.substring(4, 6));
toReturn[3] = Byte.parseByte(test.substring(6, 8));
return toReturn;
}
public String hexToString(String hex)
{
return new String(hexToByte(hex));
}
public byte[] hexToByte(String hex)
{
if(hex.length() % 2 != 0)
{
hex = "0" + hex;
}
byte[] toReturn = new byte[hex.length() / 2];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = Byte.parseByte(hex.substring(i * 2, (i + 1) * 2), 16);
}
//System.out.println(displayBytes(toReturn, false));
return toReturn;
}
public byte[] hash_hmac(String data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , String data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data.getBytes(/*CHARSET*/));
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(byte[] data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(byte[] data, byte[] key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , byte[] data , byte[] key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(String algorithm , byte[] data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public String displayBytes(byte[] bytes, boolean rawDisplay)
{
String toReturn = "";
if(rawDisplay)
{
toReturn = new String(bytes/*, CHARSET */);
}
else
{
for (byte b : bytes)
{
toReturn += String.format("%02x", b);
}
}
return toReturn;
}
public String toHex(String toConvert) {
if(toConvert.getBytes().length == 0)
{
return "";
}
return String.format("%04x", new BigInteger(toConvert.getBytes(/*YOUR_CHARSET?*/)));
}
/*
* This creates a string representation that should line up with PHPs serialize.
*/
public String serialize(String toSerialize)
{
return "s:" + toSerialize.length() + ":\"" + toSerialize + "\";";
}
public String unserialize(String toUnserialize)
{
System.out.println(toUnserialize);
int endIndex = toUnserialize.indexOf("\";");
while (endIndex < toUnserialize.length() && endIndex < toUnserialize.indexOf("\";", endIndex + 1))
{
endIndex = toUnserialize.indexOf("\";", endIndex + 1);
}
return toUnserialize.substring(toUnserialize.indexOf(":\"") + 2, endIndex);
}
Without reading through all the code, if an encrypt works instead of a decrypt, then you may have "decrypted" the plain text to form the cipher text, as symmetric encryption/decryption is reversable. In other words, you could use plain = encrypt(decrypt(plain)) as well as plain = decrypt(encrypt(plain)).
The only possible difference could be padding: decrypt should remove padding and encrypt should add it, so that would make a difference.
I have it working now... entire class is as follows. When using it with the PHP cryptastic, add in conversion to hexidecimal after conversion to base64.
public class Cryptastic {
public final static String CHARSET = "US-ASCII";
public byte[] encrypt(String toEncrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
toEncrypt = serialize(toEncrypt);
byte[] newEncrypt = toEncrypt.getBytes(CHARSET);
BlockCipher blockCipher = new RijndaelEngine(256);
SecureRandom secureRandom = new SecureRandom();
byte[] iv = new byte[32];
secureRandom.nextBytes(iv);
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(false, cipherParameters);
int size = cipher.getOutputSize(newEncrypt.length);
byte[] padded = new byte[size];
for(int i = 0; i < newEncrypt.length; i++)
{
padded[i] = newEncrypt[i];
}
for(int i = newEncrypt.length; i < size; i++)
{
padded[i] = 0;
}
newEncrypt = padded;
byte[] encrypted = new byte[size];
int outputLength = cipher.processBytes(newEncrypt, 0, newEncrypt.length, encrypted, 0);
cipher.doFinal(encrypted, outputLength);
byte[] temp = new byte[encrypted.length + 32];
for(int i = 0; i < iv.length; i++)
{
temp[i] = iv[i];
}
for(int i = iv.length; i < temp.length; i++)
{
temp[i] = encrypted[i - iv.length];
}
encrypted = temp;
byte[] mac = generateKey(new String(encrypted, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
temp = new byte[encrypted.length + mac.length];
for(int i = 0; i < encrypted.length; i++)
{
temp[i] = encrypted[i];
}
for(int i = encrypted.length; i < temp.length; i++)
{
temp[i] = mac[i - encrypted.length];
}
encrypted = temp;
if(base64Encode)
{
encrypted = Base64.encode(encrypted);
}
return encrypted;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] decrypt(String toDecrypt, byte[] keyBytes, boolean base64Encode)
{
try
{
byte[] newDecrypt = hexToByte(toDecrypt);
if(base64Encode)
{
newDecrypt = Base64.decode(newDecrypt);
}
byte[] iv = new byte[32];
byte[] extractedMac = new byte[32];
int offset = newDecrypt.length - 32;
for(int i = 0; i < 32; i++)
{
iv[i] = newDecrypt[i];
extractedMac[i] = newDecrypt[i + offset];
}
byte[] temp = new byte[offset - 32];
for(int i = 0; i < temp.length; i++)
{
temp[i] = newDecrypt[i + 32];
}
newDecrypt = temp;
byte[] combo = new byte[newDecrypt.length + iv.length];
for(int i = 0; i < iv.length; i++)
{
combo[i] = iv[i];
}
for(int i = iv.length; i < combo.length; i++)
{
combo[i] = newDecrypt[i - iv.length];
}
byte[] mac = generateKey(new String(combo, CHARSET), new String(keyBytes, CHARSET), 1000, 32);
boolean matches = new String(extractedMac).equals(new String(mac));
if(!matches)
{
byte[] toReturn = new byte[0];
return toReturn;
}
CipherParameters cipherParameters = new ParametersWithIV(new KeyParameter(keyBytes), iv);
RijndaelEngine rijndael = new RijndaelEngine(256);
SICBlockCipher ctrMode = new SICBlockCipher(rijndael);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(ctrMode, new ZeroBytePadding());
cipher.init(true, cipherParameters);
int size = cipher.getOutputSize(newDecrypt.length);
byte[] decrypted = new byte[size];
int outputLength = cipher.processBytes(newDecrypt, 0, newDecrypt.length, decrypted, 0);
cipher.doFinal(decrypted, outputLength);
temp = new byte[newDecrypt.length];
for(int i = 0; i < temp.length; i++)
{
temp[i] = decrypted[i];
}
decrypted = temp;
decrypted = unserialize(new String(decrypted, CHARSET)).getBytes(CHARSET);
return decrypted;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(String password, String salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
String derived_key = "";
//System.out.println("Number of blocks: " + keyBlocks);
for(long block = 1; block <= keyBlocks; block++)
{
byte[] initialHash = hash_hmac(salt + new String(pack(block)/*, CHARSET */), password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
{
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
derived_key += new String(initialHash/*, CHARSET */);
}
return derived_key.substring(0, keyLength).getBytes(CHARSET);
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] generateKey(byte[] password, byte[] salt, int blockIterations, int keyLength)
{
try
{
SHA256Digest digest = new SHA256Digest();
int hashLength = digest.getDigestSize();
long keyBlocks = (long) Math.ceil( (double) keyLength / (double) hashLength);
byte[] derived_key = null;
for(long block = 1; block <= keyBlocks; block++)
{
byte[] packed = pack(block);
byte[] combined = new byte[salt.length + packed.length];
for(int i = 0; i < salt.length; i++)
{
combined[i] = salt[i];
}
for(int i = salt.length; i < combined.length; i++)
{
combined[i] = packed[i - salt.length];
}
byte[] initialHash = hash_hmac(combined, password);
byte[] compareHash = initialHash;
//System.out.println("Block: " + block);
for(int i = 1; i < blockIterations; i++)
{
// XOR each iterate
compareHash = hash_hmac(compareHash, password);
for(int j = 0; j < initialHash.length; j++)
{
initialHash[j] = (byte) (initialHash[j] ^ compareHash[j]);
}
}
if(derived_key == null)
{
derived_key = initialHash;
}
else
{
byte[] temp = new byte[derived_key.length + initialHash.length];
for(int i = 0; i < derived_key.length; i++)
{
temp[i] = derived_key[i];
}
for(int i = derived_key.length; i < temp.length; i++)
{
temp[i] = initialHash[i - derived_key.length];
}
derived_key = temp;
}
}
byte[] toReturn = new byte[keyLength];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = derived_key[i];
}
return toReturn;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] pack(long toPack)
{
String test = Long.toHexString(toPack);
while(test.length() < 8)
{
test = "0" + test;
}
byte[] toReturn = new byte[4];
toReturn[0] = Byte.parseByte(test.substring(0, 2));
toReturn[1] = Byte.parseByte(test.substring(2, 4));
toReturn[2] = Byte.parseByte(test.substring(4, 6));
toReturn[3] = Byte.parseByte(test.substring(6, 8));
return toReturn;
}
public String hexToString(String hex)
{
return new String(hexToByte(hex));
}
public byte[] hexToByte(String hex)
{
if(hex.length() % 2 != 0)
{
hex = "0" + hex;
}
byte[] toReturn = new byte[hex.length() / 2];
for(int i = 0; i < toReturn.length; i++)
{
toReturn[i] = Byte.parseByte(hex.substring(i * 2, (i + 1) * 2), 16);
}
return toReturn;
}
public byte[] hash_hmac(String data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , String data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data.getBytes(/*CHARSET*/));
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(byte[] data, String key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(byte[] data, byte[] key)
{
return hash_hmac("HmacSHA256", data, key);
}
public byte[] hash_hmac(String algorithm , byte[] data , byte[] key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key, algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public byte[] hash_hmac(String algorithm , byte[] data , String key)
{
try
{
SecretKeySpec secret = new SecretKeySpec(key.getBytes(/*CHARSET*/), algorithm);
Mac mac = Mac.getInstance(algorithm);
mac.init(secret);
byte[] digest = mac.doFinal(data);
return digest;
}
catch (Exception e)
{
e.printStackTrace();
}
return null;
}
public String displayBytes(byte[] bytes, boolean rawDisplay)
{
String toReturn = "";
if(rawDisplay)
{
toReturn = new String(bytes/*, CHARSET */);
}
else
{
for (byte b : bytes)
{
toReturn += String.format("%02x", b);
}
}
return toReturn;
}
public String toHex(String toConvert) {
if(toConvert.getBytes().length == 0)
{
return "";
}
return String.format("%04x", new BigInteger(toConvert.getBytes(/*YOUR_CHARSET?*/)));
}
/*
* This creates a string representation that should line up with PHPs serialize.
*/
public String serialize(String toSerialize)
{
return "s:" + toSerialize.length() + ":\"" + toSerialize + "\";";
}
public String unserialize(String toUnserialize)
{
int endIndex = toUnserialize.indexOf("\";");
while (endIndex < toUnserialize.length() && endIndex < toUnserialize.indexOf("\";", endIndex + 1))
{
endIndex = toUnserialize.indexOf("\";", endIndex + 1);
}
return toUnserialize.substring(toUnserialize.indexOf(":\"") + 2, endIndex);
}
}

Categories