How to encrypt text in Java by converting PHP code? - java

On server (PHP code), we have 2 methods to encrypt/decrypt facebook id like this:
private function encryptFacebookId($text)
{
$method = "AES-256-CBC";
$iv_size = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CBC);
$iv = mcrypt_create_iv($iv_size, MCRYPT_RAND);
$encrypted = openssl_encrypt($text, $method, $this->_cryptKey, 0, $iv);
return base64_encode($iv . $encrypted);
}
public function decryptFacebookId($text)
{
$text = base64_decode($text);
$method = "AES-256-CBC";
$iv_size = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CBC);
$iv = substr($text, 0, $iv_size);
$decrypted = openssl_decrypt(substr($text, $iv_size), $method, $this->_cryptKey, 0, $iv);
return $decrypted;
}
with _cryptKey="1231238912389123asdasdklasdkjasd";
It's OK with the same value of input and output at server. But When I'm connecting to server as client (Android/Java) by HTTP request (REST).
I try to convert method of PHP code to Java code at method "encryptFacebookId($text)" and send encryption text to server but the result of method decryptFacebookId($text) at server is not same value with the client.
This is my code at client
String facebookId = "123456789";
String keyCrypt = "1231238912389123asdasdklasdkjasd";
try {
SecretKeySpec skeySpec = new SecretKeySpec(keyCrypt.getBytes(),
"AES");
Cipher enCipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] ivData = new byte[enCipher.getBlockSize()];
IvParameterSpec iv = new IvParameterSpec(ivData);
enCipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encryptedBytes = enCipher.doFinal(facebookId.getBytes());
String ivEncrypted = new String(ivData)
+ new String(encryptedBytes);
String strEncode = Base64
.encodeBase64String(ivEncrypted.getBytes());
System.out.println(strEncode);
} catch (Exception e) {
System.out.println(e.getMessage());
}
Please help me to find the right way.

1) If you want to concat binary byte[] don't transform it to String use for example:
public static byte[] concat(byte[]... args)
{
int fulllength = 0;
for (byte[] arrItem : args) {
fulllength += arrItem.length;
}
byte[] outArray = new byte[fulllength];
int start = 0;
for (byte[] arrItem : args) {
System.arraycopy(arrItem, 0, outArray, start, arrItem.length);
start += arrItem.length;
}
return outArray;
}
byte[] ivEncrypted = concat(ivData, encryptedBytes);
2) You have to be sure that the Base64 encoders are compatible.

Related

Java DES encrypt, C# DES decrypt

I received an encrypted string from Java, and I can see the Java encrypted source code.
I wrote the decryption code in C#. But always report an error at "FlushFinalBlock". Error message: "System.Security.Cryptography.CryptographicException. Additional information: Incorrect data."
Can any body point out where the problem is in my C# code?
this is java code:
private static byte[] coderByDES(byte[] plainText, String key, int mode)
throws InvalidKeyException, InvalidKeySpecException,
NoSuchAlgorithmException, NoSuchPaddingException,
BadPaddingException, IllegalBlockSizeException,
UnsupportedEncodingException {
SecureRandom sr = new SecureRandom();
byte[] resultKey = makeKey(key);
DESKeySpec desSpec = new DESKeySpec(resultKey);
SecretKey secretKey = SecretKeyFactory.getInstance("DES").generateSecret(desSpec);
Cipher cipher = Cipher.getInstance("DES");
cipher.init(mode, secretKey, sr);
return cipher.doFinal(plainText);
}
private static byte[] makeKey(String key)
throws UnsupportedEncodingException {
byte[] keyByte = new byte[8];
byte[] keyResult = key.getBytes("UTF-8");
for (int i = 0; i < keyResult.length && i < keyByte.length; i++) {
keyByte[i] = keyResult[i];
}
return keyByte;
}
private static String byteArr2HexStr(byte[] arrB) {
int iLen = arrB.length;
StringBuilder sb = new StringBuilder(iLen * 2);
for (int i = 0; i < iLen; i++) {
int intTmp = arrB[i];
while (intTmp < 0) {
intTmp = intTmp + 256;
}
if (intTmp < 16) {
sb.append("0");
}
sb.append(Integer.toString(intTmp, 16));
}
return sb.toString();
}
this is C# code:
public static string DecryptForDES(string input, string key)
{
byte[] inputByteArray = HexStr2ByteArr(input);
byte[] buffArray = null;
using (DESCryptoServiceProvider des = new DESCryptoServiceProvider())
{
des.Key = Encoding.UTF8.GetBytes(key);
des.IV = Encoding.UTF8.GetBytes(key);
des.Mode = System.Security.Cryptography.CipherMode.ECB;
des.Padding = PaddingMode.PKCS7;
System.IO.MemoryStream ms = new System.IO.MemoryStream();
using (CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(), CryptoStreamMode.Write))
{
cs.Write(inputByteArray, 0, inputByteArray.Length);
cs.FlushFinalBlock();//
cs.Close();
}
buffArray = ms.ToArray();
ms.Close();
}
string str = string.Empty;
if (buffArray != null)
{
str = Encoding.UTF8.GetString(buffArray);
}
return str;
}
public static byte[] HexStr2ByteArr(string strIn)
{
byte[] arrB = Encoding.UTF8.GetBytes(strIn);
int iLen = arrB.Length;
byte[] arrOut = new byte[iLen / 2];
byte[] arrTmp = new byte[2];
for (int i = 0; i < iLen; i = i + 2)
{
string strTmp = Encoding.UTF8.GetString(arrB, i, 2);
arrOut[i / 2] = (byte)Convert.ToInt32(strTmp, 16);
}
return arrOut;
}
Both, the Java encryption part and the C# decryption part work on my machine if the passwords match. Otherwise a System.Security.Cryptography.CryptographicException: 'Bad Data' is thrown. To get the password match replace in the C#-method DecryptForDES
des.Key = Encoding.UTF8.GetBytes(key);
with
des.Key = MakeKey(key);
with the C#-method:
private static byte[] MakeKey(String key)
{
byte[] keyByte = new byte[8];
byte[] keyResult = Encoding.UTF8.GetBytes(key);
for (int i = 0; i<keyResult.Length && i<keyByte.Length; i++) {
keyByte[i] = keyResult[i];
}
return keyByte;
}
corresponding to the Java-method makeKey(String key).
Moreover, remove in the C#-method DecryptForDES
des.IV = Encoding.UTF8.GetBytes(key);
since the ECB-mode doesn't use an IV.
In the following testcase
coderByDES("This is a plain text that needs to be encrypted...", "This is the key used for encryption...", Cipher.ENCRYPT_MODE);
returns the byte-array
a47b1b2c90fb3b7a0ab1f51f328ff55aae3c1eb7789c31c28346696a8b1f27c7413c14e68fe977d3235b5a6f63c07d7a95d912ff22f17ad6
and
DecryptForDES("a47b1b2c90fb3b7a0ab1f51f328ff55aae3c1eb7789c31c28346696a8b1f27c7413c14e68fe977d3235b5a6f63c07d7a95d912ff22f17ad6", "This is the key used for encryption...");
returns the correct plain text.
By the way: As Flydog57 already stated DES is insecure (https://en.wikipedia.org/wiki/Data_Encryption_Standard). And also the ECB mode is not secure (https://crypto.stackexchange.com/questions/20941/why-shouldnt-i-use-ecb-encryption).
Better choices are AES (https://en.wikipedia.org/wiki/Advanced_Encryption_Standard) with CBC or GCM mode (https://crypto.stackexchange.com/questions/2310/what-is-the-difference-between-cbc-and-gcm-mode).

Android AES decryption returning rare characters V2.0

Recently i've post a question about this topic but the thing turns a little weird when i tried to decrypt an AES String that was encoded on UTF8
In the following lines i read the String AES encrypted wich returns the following String: RnLObq9hdUDGp9S2pxC1qjQXekuf9g6i/5bQfKilYn4=
public static final String AesKey256 ="ZzRtNDNuY3J5cHRrM3kuLi4=";
//This reads the String and stores on res.getContents()
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
IntentResult res= IntentIntegrator.parseActivityResult(requestCode, resultCode,data);
if(res!=null){
if (res.getContents() == null) {
Toast.makeText(this,"Captura cancelada",Toast.LENGTH_SHORT).show();
}else{
try {
String cadena= decrypt(res.getContents());
out.setText(cadena);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
//provide the res.getContents() to decrypt method, wich its the String i've recently read
private String decrypt(String cadena)throws Exception{
SecretKeySpec keySpec= generateKey(AesKey256); //HERE
Cipher c= Cipher.getInstance(AES_MODE);
c.init(Cipher.DECRYPT_MODE,keySpec);
byte[] decodedValue= Base64.decode(cadena, Base64.DEFAULT);
byte[] decValue= c.doFinal(decodedValue);/* c.doFinal(decodedValue);*/
String decryptedValue= new String((decValue), "UTF-8");
return decryptedValue;
}
private SecretKeySpec generateKey(String password) throws NoSuchAlgorithmException, UnsupportedEncodingException {
final MessageDigest digest= MessageDigest.getInstance("SHA-256");
byte[] bytes= password.getBytes("UTF-8");
digest.update(bytes,0,bytes.length);
byte[] key= digest.digest();
SecretKeySpec secretKeySpec= new SecretKeySpec(key, "AES");
return secretKeySpec;
}
I am only using the decryption method but it still returning this characters:
i've spent hours looking for a solution, but nothing works for now... hope someone can give me a hand!
Best Regards!
EDIT
THIS IS HOW IT WAS ENCRYPTED IN C#
private const string AesIV256 = "IVFBWjJXU1gjRURDNFJGVg==";
private const string AesKey256 = "ZzRtNDNuY3J5cHRrM3kuLi4=";
public static string Encrypt(string text)
{
var sToEncrypt = text;
var rj = new RijndaelManaged()
{
Padding = PaddingMode.Zeros,
Mode = CipherMode.ECB,
KeySize = 256,
BlockSize = 256,
};
var key = Convert.FromBase64String(AesKey256);
var IV = Convert.FromBase64String(AesIV256);
var encryptor = rj.CreateEncryptor(key, IV);
var msEncrypt = new MemoryStream();
var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write);
var toEncrypt = Encoding.UTF8.GetBytes(sToEncrypt);
csEncrypt.Write(toEncrypt, 0, toEncrypt.Length);
csEncrypt.FlushFinalBlock();
var encrypted = msEncrypt.ToArray();
return (Convert.ToBase64String(encrypted));
}
Made it!
After a long time of searching thanks to all you guys who answered this post i used the bouncy castle library and i've decrypt the desired String by doing the following:
public static String decrypt(String valueToDecrypt) throws Exception {
AESCrypt enc = new AESCrypt();
return new String(enc.decryptInternal(valueToDecrypt)).trim();
}
private byte[] decryptInternal(String code) throws Exception {
if (code == null || code.length() == 0) {
throw new Exception("Empty string");
}
byte[] decrypted = null;
try {
byte[] key= SecretKey.getBytes("UTF-8");
PaddedBufferedBlockCipher c = new PaddedBufferedBlockCipher(new RijndaelEngine(256), new ZeroBytePadding());
CipherParameters params= new KeyParameter(key);`
// false because its going to decrypt
c.init(false,params);
decrypted= GetData(c,(Base64.decode(code,Base64.DEFAULT));
} catch (Exception e) {
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
private static byte[] GetData(PaddedBufferedBlockCipher cipher, byte[] data) throws InvalidCipherTextException
{
int minSize = cipher.getOutputSize(data.length);
byte[] outBuf = new byte[minSize];
int length1 = cipher.processBytes(data, 0, data.length, outBuf, 0);
int length2 = cipher.doFinal(outBuf, length1);
int actualLength = length1 + length2;
byte[] cipherArray = new byte[actualLength];
for (int x = 0; x < actualLength; x++) {
cipherArray[x] = outBuf[x];
}
return cipherArray;
}

Encryption in C# and decryption in Java

I am doing Encryption in C# for windows phone 8.1 app and I need to decrypt it using java.
Here is my Encryption code
public static String encrypt(String plaintext, KeyParameter keyParam)
{
byte[] ivData = new byte[AES_NIVBITS / 8];
Random r = new Random();
r.NextBytes(ivData);
IBlockCipherPadding padding = new Pkcs7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new AesEngine()), padding);
ICipherParameters param = new ParametersWithIV(keyParam, ivData);
cipher.Reset();
cipher.Init(true, param);
byte[] bytesDec = Encoding.GetEncoding("iso-8859-1").GetBytes(plaintext);
byte[] bytesEnc = null;
int buflen = cipher.GetOutputSize(bytesDec.Length);
System.Diagnostics.Debug.WriteLine("enc length " + buflen);
bytesEnc = new byte[buflen];
int nBytesEnc = cipher.ProcessBytes(bytesDec, 0, bytesDec.Length, bytesEnc, 0);
nBytesEnc += cipher.DoFinal(bytesEnc, nBytesEnc);
if (nBytesEnc != bytesEnc.Length)
{
throw new Exception("Unexpected behaviour : getOutputSize value incorrect");
}
byte[] bytesAll = new byte[ivData.Length + bytesEnc.Length];
Array.Copy(ivData, 0, bytesAll, 0, ivData.Length);
Array.Copy(bytesEnc, 0, bytesAll, ivData.Length, bytesEnc.Length);
byte[] bytesAllb64 = Base64.Encode(bytesAll);
return Encoding.GetEncoding("iso-8859-1").GetString(bytesAllb64, 0, bytesAllb64.Length);
}
And this is the java code for decryption
public static String decodeBase64Aes(String encodedciphertext, KeyParameter keyParam) throws Exception
{
byte[] bytesEnc = Base64.decode(encodedciphertext.getBytes(ISO8859));
int nIvBytes = AES_NIVBITS / 8;
byte[] ivBytes = new byte[nIvBytes];
System.arraycopy(bytesEnc, 0, ivBytes, 0, nIvBytes);
CipherParameters params = new ParametersWithIV(keyParam, ivBytes);
BlockCipherPadding padding = new PKCS7Padding();
BufferedBlockCipher cipher = new PaddedBufferedBlockCipher(new CBCBlockCipher(new AESEngine()), padding);
cipher.reset();
cipher.init(false, params);
byte[] bytesDec = null;
int buflen = cipher.getOutputSize(bytesEnc.length - nIvBytes);
byte[] workingBuffer = new byte[buflen];
int len = cipher.processBytes(bytesEnc, nIvBytes, bytesEnc.length - nIvBytes, workingBuffer, 0);
len += cipher.doFinal(workingBuffer, len);
bytesDec = new byte[len];
System.arraycopy(workingBuffer, 0, bytesDec, 0, len);
return new String(bytesDec, ISO8859);
}
When I am encrypting it it's working fine but when I test decryption using the encrypted text I got and key, it throws
Exception in thread "main" org.bouncycastle.crypto.DataLengthException: last block incomplete in decryption
I can only change the c# part. Any help would be highly appreciated???
Key -> 8fe3f8b34e87744c175aae43cc52ee13
'Hello World' -> Nb90n51LqK13LzpalV7qTs7YJqe9m+Ni9uA/U7tU06Y=
The Exception Comes on line
len += cipher.doFinal(workingBuffer, len);
When I encrypt "Hello World" from java using the same key from the encryption method I have on my server I get
uWMz8ZIPh+3jnGtwxpuyK9Qht7BJV4RQ/Iet9JeTrTk=
EDIT ------
Updated to working code.
Base 64 does not give same length as the original one and that's why I was gettting that error. I have updated the code with the correct one.

Different AES128 with zero padding encryption result between php and java

I have a different result between java and php method in doing AES128 with zero padding and no IV encryption.
Here PHP code :
<?php
$ptaDataString = "secretdata";
$ptaDataString = encryptData($ptaDataString);
$ptaDataString = base64_encode($ptaDataString);
function encryptData($input) {
$ptaKey = 'secret';
$iv = "\0";
$encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $ptaKey, $input, MCRYPT_MODE_CBC, $iv);
return $encrypted;
}
echo $ptaDataString;
?>
And here is java code:
public static String encrypt() throws Exception {
try {
String data = "secretdata";
String key = "secret0000000000";
String iv = "0000000000000000";
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
byte[] dataBytes = data.getBytes();
int plaintextLength = dataBytes.length;
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(dataBytes, 0, plaintext, 0, dataBytes.length);
SecretKeySpec keyspec = new SecretKeySpec(key.getBytes(), "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv.getBytes());
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
byte[] encrypted = cipher.doFinal(plaintext);
return new sun.misc.BASE64Encoder().encode(encrypted);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
php resulting : kjgE5p/3qrum6ghdjiVIoA==
Java resulting : zLKhVMksRRr1VHQigmPQ2Q==
Any help would be appreciated,
Thanks
In Java, a zero byte expressed as a string is "\0" not "0". If you correct your example as follows, the results match:
String data = "secretdata";
String key = "secret\0\0\0\0\0\0\0\0\0\0";
String iv = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
In the case of the IV, it's probably just easier to write:
byte[] iv = new byte[<block size>];
In the final line of your code, you access sun.misc.BASE64Encoder(). Accessing anything that starts with sun.* is frowned upon, since these are internal classes. Consider instead using:
return DatatypeConverter.printBase64Binary(encrypted);

Cipher / 3DES / CFB / Java and PHP

I have a PHP servor which decrypt data in 3DES with the CFB Mode
I encrypt in PHP :
$montant = "500";
$message_crypte = mcrypt_encrypt(MCRYPT_3DES, "N4y1FRDRJ7wn7eJNnWaahCIS", $montant, ,CRYPT_MODE_CFB, "NCNPJDcR");
$montant = base64_encode($message_crypte);
This script in PHP is OK with other system.
And I want to encrypt in Java :
public class CryptData {
private KeySpec keySpec;
private SecretKey key;
private IvParameterSpec iv;
public CryptData(String keyString, String ivString) {
try {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(Base64
.decodeBase64(keyString.getBytes("ISO-8859-1")));
final byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
//keySpec = new DESedeKeySpec(keyBytes);
keySpec = new DESedeKeySpec(keyString.getBytes());
key = SecretKeyFactory.getInstance("DESede")
.generateSecret(keySpec);
iv = new IvParameterSpec(ivString.getBytes());
} catch (Exception e) {
e.printStackTrace();
}
}
public String encrypt(String value) {
try {
Cipher ecipher = Cipher.getInstance("DESede/CFB/NoPadding");
//"SunJCE");
ecipher.init(Cipher.ENCRYPT_MODE, key, iv);
if (value == null)
return null;
// Encode the string into bytes using utf-8
byte[] valeur = value.getBytes("ISO-8859-1");
//byte[] utf8 = value.getBytes();
// Encrypt
byte[] enc = ecipher.doFinal(valeur);
// Encode bytes to base64 to get a string
return new String(Base64.encodeBase64(enc), "ISO-8859-1");
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
I have not the same result in PHP and in Java
How modify Java treatment to obtain the same result as PHP?
The answer is:
Cipher ecipher = Cipher.getInstance("DESede/CFB8/NoPadding");
I need to use "CFB8"

Categories

Resources