Alternative to PHP Encryption in Java - java

I am having a PHP which is working fine and I want to replicate the same and want to do it using java.
My PHP code uses MCRYPT_RIJNDAEL_256 :
$iv = "42309842389462374623784692423642";
$key = "asfuyjkdhfabcdef";
$text = "0007";
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC);
$padding = $block - (strlen($text) % $block);
$text .= str_repeat(chr($padding), $padding);
$crypttext = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $text, MCRYPT_MODE_CBC, $iv);
$crypttext64=base64_encode($crypttext);
echo $crypttext64;
which returns: KdL2lWUGqy+UqLxbe9VTS6OCgvnJFn1jtMCgkj1434A=
But while encrypting using java :
byte[] sessionKey = "asfuyjkdhfabcdef".getBytes(Charset.forName("ASCII"));
byte[] iv = "42309842389462374623784692423642".getBytes(Charset.forName("ASCII"));
String plaintext="0007";
String data = new String(new char[28]).replace("\0", Character.toString ((char) 28));
String newdata = plaintext+data;
newdata = newdata.substring(0,32);
byte [] dataBytes = newdata.getBytes(Charset.forName("ASCII"));
System.out.println(dataBytes);
PaddedBufferedBlockCipher cipher = new PaddedBufferedBlockCipher(
new CBCBlockCipher(new RijndaelEngine(256)),new PKCS7Padding());
cipher.init(true, new ParametersWithIV(new KeyParameter(sessionKey), iv));
byte[] encrypted = new byte[cipher.getOutputSize(dataBytes.length)];
int oLen = cipher.processBytes(dataBytes, 0, dataBytes.length, encrypted, 0);
cipher.doFinal(encrypted, oLen);
String s = new String(encrypted);
System.out.println(Base64.getEncoder().encodeToString(s.getBytes()));
I am getting below output:
KdL2lWUGqy+UqLxbe9VTS6OCgvnJFn1jtMCgkj1434DMpLehN7ve0AhnMOQtT1fLcZIUfM9rF/iVOKj6UtgwyA==
Both the outputs are different.
Please suggest the way so that I can get the same output in JAVA also.

You seem to try and perform the padding twice:
String data = new String(new char[28]).replace("\0", Character.toString ((char) 28));
String newdata = plaintext+data;
newdata = newdata.substring(0,32);
byte [] dataBytes = newdata.getBytes(Charset.forName("ASCII"));
System.out.println(dataBytes);
seems to be an ill written attempt to perform the PKCS#7 padding, which you already do in your code (new PKCS7Padding()).
Just replace it by:
plaintext.getBytes(StandardCharsets.US_ASCII)
As you can see, the first part of the base 64 is identical in both PHP and Java. Note that PHP doesn't contain PKCS#7 padding, which is why this was coded using str_repeat.
Furthermore the encrypted array should be directly put into the encodeToString method, first converting to String and then back to byte[] again can only loose data. So strip out s in the following code:
String s = new String(encrypted);
System.out.println(Base64.getEncoder().encodeToString(s.getBytes()));

Related

Encoding with C# and Java

I have got to make the same function in Java and C#, but the result are not the same.
My code in C# :
string xmlString = System.IO.File.ReadAllText(#"crc.xml");
byte[] bytes = Encoding.ASCII.GetBytes(xmlString);
// step 1, calculate MD5 hash from input
MD5 md5 = System.Security.Cryptography.MD5.Create();
byte[] hash = md5.ComputeHash(bytes);
// step 2, convert byte array to hex string
StringBuilder sb = new StringBuilder();
for (int i = 0; i < hash.Length; i++)
{
sb.Append(hash[i].ToString("X2"));
}
Console.WriteLine(sb.ToString());
And my code in Java :
string xmlstring = Files.readString(Paths.get("crc.xml"));
MessageDigest m = MessageDigest.getInstance("MD5");
byte[] digest = m.digest(xmlstring.getbytes());
String hash = new BigInteger(1, digest).toString(16);
System.out.println(hash);
In C# I have this result :
F5F8B2F361FEA6EA30F24BEBAA5BDE3A
But in Java I have this result :
8fb40aad49fbf796b82a2faa11cda764
What I'm doing wrong?
Codebrane say it. Use
byte[] bytes = Encoding.UFT8.GetBytes(xmlString);
instead of
byte[] bytes = Encoding.ASCII.GetBytes(xmlString);

IllegalArgumentException: IV buffer too short for given offset/length combination

I have one application which is in PHP encrypting text using openssl_encrypt with following method. (Using same value for salt and iv as '239422ae7940144f')
function encrypt_password($password) {
define('AES_256_CBC', 'aes-256-cbc');
$sessionId = $password;
//random number for encrtyption(salt)
$salt = '239422ae7940144f';
$iv = $salt; //cipher length
$encryptedSession = openssl_encrypt($sessionId, AES_256_CBC, $salt, 0, $iv);
return array('encryptedPassword' => $encryptedSession, 'salt' => $salt);
}
function decrypt_password($result) {
define('AES_256_CBC', 'aes-256-cbc');
$vPassword = 'xUP9PwhcXm5xbKIfiSxMCA==';
//random number for descrypt(salt)
$salt = '239422ae7940144f';
$iv = $salt; //cipher length.
$decrypted = openssl_decrypt($vPassword, AES_256_CBC, $salt, 0, $iv);
return $decrypted;
}
Encrypt of password 'abc123' provides 'xUP9PwhcXm5xbKIfiSxMCA==' and decrypting it gives back 'abc123'.
How to find equivalent java program which would do the same. I tried using the example on Using Java to decrypt openssl aes-256-cbc using provided key and iv, but it fails with
java.lang.IllegalArgumentException: IV buffer too short for given
offset/length combination.
Following are the secretKey and initVector lines in java program I am using.
final byte[] secretKey = javax.xml.bind.DatatypeConverter.parseHexBinary("239422ae7940144f");
final byte[] initVector = javax.xml.bind.DatatypeConverter.parseHexBinary("239422ae7940144f");

What is the correct .Net method to decrypt an android AES encrypted file

I have encrypted a zip file in android using this method:
String s_InitKey = "1612211310164660";
String s_IvSpec = "MySecreteBytes00";
IvParameterSpec iv = new IvParameterSpec(s_IvSpec.getBytes("UTF-8"));
SecretKeySpec key = new SecretKeySpec(s_InitKey.getBytes("UTF-8"), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
I need to decrypt the file using windows, I have tried the following method:
Private Sub LicenceEncryptOrDecrypt(LizenzDatei As String, EncryptOrDecrypt As String)
Dim Rijndael As RijndaelManaged = New RijndaelManaged
Dim passPhrase As String = "SuperPassword"
Dim hashAlgorithm As String = "SHA1"
Dim passwordIterations As Integer = 3
Dim keySize As Integer = 128
Dim initVector As String = "16charLongString"
Rijndael.IV = Encoding.ASCII.GetBytes(initVector)
Dim saltValue As String = "DoYouWantSomeSalt"
Dim saltValueBytes As Byte() = Encoding.ASCII.GetBytes(saltValue)
Dim password As Rfc2898DeriveBytes = New Rfc2898DeriveBytes(passPhrase, saltValueBytes)
Rijndael.Key = password.GetBytes(keySize / 8)
Rijndael.Padding = PaddingMode.None
Dim transform As ICryptoTransform
Dim tempFile As String
Select Case EncryptOrDecrypt
Case "Encrypt"
transform = Rijndael.CreateEncryptor(Rijndael.Key, Rijndael.IV)
tempFile = LizenzDatei + ".enc"
Case "Decrypt"
transform = Rijndael.CreateDecryptor(Rijndael.Key, Rijndael.IV)
tempFile = LizenzDatei + ".dec"
Case Else
Debug.Print(">< EncryptOrDecrypt: Falshes parameter. Ende Sub.")
Success = False
End Select
Using inFS As FileStream = New FileStream(LizenzDatei, FileMode.Open)
Dim data() As Byte = New Byte(inFS.Length - 1) {}
Using outFS As FileStream = New FileStream(tempFile, FileMode.Create)
Using outStreamEncrypted As CryptoStream = New CryptoStream(outFS, transform, CryptoStreamMode.Write)
outStreamEncrypted.Write(data, 0, data.Length)
outStreamEncrypted.FlushFinalBlock()
outStreamEncrypted.Close()
End Using
outFS.Close()
End Using
inFS.Close()
End Using
File.Delete(LizenzDatei)
File.Move(tempFile, LizenzDatei)
End Sub
I am generating the zip file in android then I export it to a folder in the android sub system. From there I copy it over to windows and it is here that I need to decrypt the file.
EDIT - Modified VB Code
Private Sub LicenceEncryptOrDecrypt(EncryptedFile As SimpleFile, Direction As CryptoAction)
Dim Rijndael As RijndaelManaged = New RijndaelManaged
Dim hashAlgorithm As String = "AES"
Rijndael.Padding = PaddingMode.None
Dim s_Temp As String = EncryptedFile.Name.Substring(9, EncryptedFile.Name.Length - 9)
Dim c_Date As New SimpleDate(s_Temp)
'c_Date.getKey translates 16bit key'
Dim Key As Byte() = System.Text.Encoding.UTF8.GetBytes(c_Date.getKey)
Dim IV As Byte() = System.Text.Encoding.UTF8.GetBytes("MySecreteBytes00")
Rijndael.IV = IV
Rijndael.Key = Key
Dim transform As ICryptoTransform
Dim tempFile As String
Select Case Direction
Case CryptoAction.ActionEncrypt
transform = Rijndael.CreateEncryptor(Rijndael.Key, Rijndael.IV)
tempFile = EncryptedFile.FullPath
Case CryptoAction.ActionDecrypt
transform = Rijndael.CreateDecryptor(Rijndael.Key, Rijndael.IV)
tempFile = EncryptedFile.Path + "\" + EncryptedFile.Name + ".zip""
End Select
Dim data() As Byte = System.IO.File.ReadAllBytes(EncryptedFile.FullPath)
Using outFS As FileStream = New FileStream(tempFile, FileMode.Create)
Using outStreamEncrypted As CryptoStream = New CryptoStream(outFS, transform, CryptoStreamMode.Write)
outStreamEncrypted.Write(data, 0, data.Length)
outStreamEncrypted.FlushFinalBlock()
outStreamEncrypted.Close()
End Using
outFS.Close()
End Using
End Sub
You should use padding unless the data is always a multiple of the block size. You need to use the same padding mode for both encryption and decryption.
Removing non-essential code in test cases is best.
If you want to verify the encryption ad decryption you can use the online AES service by Cryptomathic.

Converting PHP hmac signature to java

I'm converting a php script to java (for android) but find myself stuck converting the hmac signature process.
PHP which gives correct sign:
$secret = "lT4fhviR7ILvwGeiBJgolfYji1uz/f7B6HQWaWQWVl/sWEz3Kwt4QjzCHWE+MBENOmtgBS6PlN87s+1d7/8bRw==";
$nonce = "1388256620813308";
$postdata = "nonce=1388256620813308";
$path = "/0/private/Balance";
$sign = hash_hmac('sha512', $path . hash('sha256', $nonce . $postdata, true), base64_decode($this->secret), true);
echo $sign;
Hmac = 2IVoBCoadCEivxKVRB/4quJET4DoZV4JdY6bMC2oEYJZuygF5JiAhGrxVMyw2yPhz+KdiwvbzV43cicGamzr2A==
Which is correct and accepted signature
Java (with invalid sign):
String secret = "lT4fhviR7ILvwGeiBJgolfYji1uz/f7B6HQWaWQWVl/sWEz3Kwt4QjzCHWE+MBENOmtgBS6PlN87s+1d7/8bRw==";
String nonce = "1388256620813308";
String postdata = "nonce=1388256620813308";
String path = "/0/private/Balance";
// hash nonce + data
MessageDigest md = MessageDigest.getInstance("SHA-256");
md.update((nonce+postdata).getBytes());
byte[] digest = md.digest();
String baseString = path + new String(digest); //this is probably root of evil
// HMAC
Mac mac = Mac.getInstance("HmacSHA512");
SecretKey secretKey = new SecretKeySpec(Base64.decode(secret, Base64.DEFAULT), "HmacSHA512");
mac.init(secretKey);
String sign = new String(Base64.encodeToString(mac.doFinal(baseString.getBytes()), Base64.DEFAULT)).trim();
Log.d(TAG, sign);
Hmac = 7ZQfn+fqMpMEFN5Z/T5UwcqP1uo0JOyAVSn4HEBeE/KotnEf4a5bPOWriiC//gdoEg2kOe60EIr3Lv7irXuejw==
The problem is in the java string conversion of the bytes (even if I add "UTF-8" as characted encoding in getBytes). I know this because if I don add path to the hmac, and just feed it with digest without the string conversion the signature matches.
After posting question I did a quick and dirty test to add bytes from path manually to a new bytes array
byte[] digest = md.digest();
byte[] pBytes = path.getBytes();
int L = digest.length + pBytes.length;
byte[] message = new byte[L];
for (int i=0;i<pBytes.length;i++) {
message[i] = pBytes[i];
}
for (int i=pBytes.length,n=0; n<digest.length; n++) {
message[i+n] = digest[n];
}
String sign = new String(Base64.encodeToString(mac.doFinal(message), Base64.NO_WRAP));
And voilĂ ; the hmac sign matches!
I have solved my problem but keeping question unanswered for some day to say if a better answer is provided that sheds light on this.

Implementing AES Encryption/Decryption around existing PHP System on Android

I'm expanding an iOS project over to Android. My existing application communicates with a server via PHP using an AES encryption system.
Here are the functions that I am using on the PHP side:
Encrypt
function cryptAESEncrypt($string,$key) {
$key = md5($key);
$iv = "1234567890123436"; //IV isn't needed if MCRYPT_MODE is ECB (What we are using)
$data = $data = base64_encode($string);
$algorythm = MCRYPT_RIJNDAEL_128;
$mode = MCRYPT_MODE_ECB;
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128,$key,$data,MCRYPT_MODE_ECB,$iv);
return base64_encode($encrypted);
}
Decrypt
function cryptAESDecrypt($string,$key) {
$key = md5($key);
$iv = "1234567890123436"; //IV isn't needed if MCRYPT_MODE is ECB (What we are using)
$data = base64_decode($string);
$algorythm = MCRYPT_RIJNDAEL_128;
$mode = MCRYPT_MODE_ECB;
$decrypted = mcrypt_decrypt(MCRYPT_RIJNDAEL_128,$key,$data,MCRYPT_MODE_ECB,$iv);
return base64_decode($decrypted);
}
The general flow of the process is:
md5 hash the $key (brings it down to 16 characters regardless)
Base64 Encode the $string
Encrypt the Base64'ed using 128Bit AES/RIJNDAEL in ECB mode (no IV)
Base64 the encrypted data and returns it as a string.
The decryption works the same but in reverse.
Now I'm just playing with samples but don't seem to be having much luck. I've encrypted the string "test" in PHP using that function ("test" was the key too - MD5'ed to 098f6bcd4621d373cade4e832627b4f6) and I am given the output of "ijzLe/2WgbaP+n3YScQSgQ==".
Now what I tried in Java didn't work as I get an incorrect key length error but I had more luck with a previous snippet earlier. Here's what I had anyway:
String key = "test";
String in = "ijzLe/2WgbaP+n3YScQSgQ==";
SecretKeySpec skeySpec = new SecretKeySpec(md5(key).getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
byte[] encryptedByteArray = Base64.decode(in.getBytes(),0);
byte[] decryptedByteArray = cipher.doFinal(encryptedByteArray);
String decryptedData = new String(Base64.decode(decryptedByteArray, 0));
Log.v("NOTE","Data: "+decryptedData);
As I said though, that doesn't work. Now my question is, is there anybody that can help me make my Java code work with the supplied PHP code as I can't change that (had other code working using different PHP snippets).
Thanks to Duncan in the comments I found out the issue was with my MD5 hash function..
Found a working version for reference:
public String md5(String s) {
if (s != null)
{
try { // Create MD5 Hash
MessageDigest digest = java.security.MessageDigest .getInstance("MD5");
digest.update(s.getBytes());
byte messageDigest[] = digest.digest();
// Create Hex String
StringBuffer hexString = new StringBuffer();
for (int i = 0; i < messageDigest.length; i++) {
String h = Integer.toHexString(0xFF & messageDigest[i]);
while (h.length() < 2)
h = "0" + h;
hexString.append(h);
}
return hexString.toString();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
}
return "";
}
return "";
}

Categories

Resources