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"
Related
I am trying to covert a c# encryption method to java. It is Triple DES with MD5 hash in ECB mode and I am having a hard time finding the java equivalent. The hashes do not match when I try to run them
Below is the c# code
public string Encrypt(string value, string key)
{
string encrypted;
var hashmd5 = new MD5CryptoServiceProvider();
var des = new TripleDESCryptoServiceProvider();
des.Key = hashmd5.ComputeHash(ASCIIEncoding.ASCII.GetBytes(key));
des.Mode = CipherMode.ECB; //CBC, CFB
var buff = ASCIIEncoding.ASCII.GetBytes(value);
encrypted = Convert.ToBase64String(des.CreateEncryptor().TransformFinalBlock(buff, 0, buff.Length));
return encrypted;
}
Here is the Java Code
public String encryptSession (String session, String sessionEncryptionKey) throws Exception {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] hash = EncodingUtils.getAsciiBytes(sessionEncryptionKey);
byte[] digestOfPassword = md.digest(hash);
byte[] keyBytes = Arrays.copyOf(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
SecretKey key = new SecretKeySpec(keyBytes, "DESede");
Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] sessionBytes = EncodingUtils.getAsciiBytes(session);
byte[] buf = cipher.doFinal(sessionBytes);
byte[] base64Bytes = Base64.getEncoder().encode(buf);
String base64EncryptedString = new String(base64Bytes);
return base64EncryptedString;
}
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;
}
I am working on a feature which require Aes encrypted (AES/CBC/PKCS5padding) cipher text to be sent from client to server which has ASP.Net in backend.
I've a decryption function on the server side as below :
public static string Decrypt(string inputBase64, string passphrase = null)
{
byte[] key, iv = new byte[0];
byte[] base64data = Convert.FromBase64String(inputBase64);
byte[] passphrasedata = RawBytesFromString(passphrase);
byte[] currentHash = new byte[0];
SHA256Managed hash = new SHA256Managed();
currentHash = hash.ComputeHash(passphrasedata);
return DecryptStringFromBytes(base64data, currentHash, null);
}
static string DecryptStringFromBytes(byte[] cipherText, byte[] Key, byte[] IV)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (Key == null || Key.Length <= 0)
throw new ArgumentNullException("Key");
//if (IV == null || IV.Length <= 0)
// throw new ArgumentNullException("Key");
// Declare the string used to hold
// the decrypted text.
string plaintext = null;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var cipher = new RijndaelManaged())
{
cipher.Key = Key;
cipher.IV = new byte[16];
//cipher.Mode = CipherMode.CBC;
//cipher.Padding = PaddingMode.PKCS7;
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = cipher.CreateDecryptor(Key, cipher.IV);
// Create the streams used for decryption.
using (MemoryStream msDecrypt = new MemoryStream(cipherText))
{
using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
var bytes = default(byte[]);
using (StreamReader srDecrypt = new StreamReader(csDecrypt))
{
bytes = srDecrypt.CurrentEncoding.GetBytes(srDecrypt.ReadToEnd());
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
//aintext = srDecrypt.ReadToEnd();
}
plaintext = ASCIIEncoding.UTF8.GetString(bytes, 0, bytes.Count());
}
}
}
return plaintext;
}
I want to implement an angularjs alternative to the following android code :
public static String Encrypt(String input, String passphrase)
{
if (input.equalsIgnoreCase("") || passphrase.equalsIgnoreCase(""))
return "";
else
{
byte[] key, iv;
byte[] passphrasedata = null;
try
{
passphrasedata = passphrase.getBytes("UTF-8");
}
catch (UnsupportedEncodingException e1)
{
e1.printStackTrace();
}
byte[] currentHash = new byte[0];
MessageDigest md = null;
try
{
md = MessageDigest.getInstance("SHA-256");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
currentHash = md.digest(passphrasedata);
iv = new byte[16];
return Base64.encodeToString(EncryptStringToBytes(input, currentHash, iv), Base64.NO_WRAP);
}
}
static byte[] EncryptStringToBytes(String plainText, byte[] Key, byte[] IV)
{
if (plainText == null || plainText.length() <= 0)
{
Log.e("error", "plain text empty");
}
if (Key == null || Key.length <= 0)
{
Log.e("error", "key is empty");
}
if (IV == null || IV.length <= 0)
{
Log.e("error", "IV key empty");
}
byte[] encrypted;
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec myKey = new SecretKeySpec(Key, "AES");
IvParameterSpec IVKey = new IvParameterSpec(IV);
cipher.init(Cipher.ENCRYPT_MODE, myKey, IVKey);
encrypted = cipher.doFinal(plainText.getBytes("UTF-8"));
return encrypted;
}
catch (InvalidKeyException e)
{
e.printStackTrace();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace();
}
catch (InvalidAlgorithmParameterException e)
{
e.printStackTrace();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace();
}
catch (BadPaddingException e)
{
e.printStackTrace();
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return null;
}
The Android code above is working fine. I want to implement the same encryption logic at AngularJs.
I've included CryptoJS library for SHA-256 and AES cipher calculation. Here is the code which I've implemented.
var password = '12345678';
var passwordHash = CryptoJS.SHA256(password).toString(CryptoJS.enc.Latin1);
var iv = CryptoJS.enc.Hex.parse('0000000000000000');
var cipher = CryptoJS.AES.encrypt(plaintext,passwordHash,{
iv: iv,
mode: CryptoJS.mode.CBC,
keySize: 256/32,
padding: CryptoJS.pad.Pkcs7
});
cipherText = cipher.ciphertext.toString(CryptoJS.enc.Base64);
The problem is that, the encoded string cannot be decrypted back to its previous form. I think there is some mismatch in the encryption logic in the client side and decryption logic on the server side.
When I pass the CryptoJS encrypted cipher to java decryption function, it shows errors:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
or sometimes:
javax.crypto.BadPaddingException: Given final block not properly padded
Thanks guys!!!, I got it working with the following code.
function hash (){
return CryptoJS.SHA256(password);
}
var cipher = (function(plaintext, password) {
passwordHash = hash(password);
var iv = CryptoJS.enc.Hex.parse('0000000000000000');
var cipher = CryptoJS.AES.encrypt(plaintext, passwordHash, {
iv: iv,
mode: CryptoJS.mode.CBC,
keySize: 256 / 32,
padding: CryptoJS.pad.Pkcs7
});
return cipher;
})(plaintext, password);
cipherBase64 = cipher.ciphertext.toString().hex2a().base64Encode();
' Encrypts a string using tripple DES
Private Function TripleDESEncrypt(ByVal str As String) As TripleDESEncryptResult
' 3DES Encryption
' Generate KEY/IV pair for your local 3DES encrpytion on xmlCard
' Create a new 3DES CryptoProvider and generate KEY/IV pair for encryption
Dim m_cryptoProvider As New TripleDESCryptoServiceProvider
m_cryptoProvider.GenerateIV()
m_cryptoProvider.GenerateKey()
Dim stream As System.IO.MemoryStream = New System.IO.MemoryStream
Dim cryptoStream As CryptoStream = _
New CryptoStream(stream, m_cryptoProvider.CreateEncryptor, _
CryptoStreamMode.Write)
Dim Input() As Byte = System.Text.Encoding.Default.GetBytes(str)
cryptoStream.Write(Input, 0, Input.Length)
cryptoStream.FlushFinalBlock()
' Convert to base64, so it'll be XML-friendly
Dim encryptedCardString = System.Convert.ToBase64String(stream.ToArray())
cryptoStream.Close()
cryptoStream.Dispose()
Return New TripleDESEncryptResult(encryptedCardString, m_cryptoProvider.Key, m_cryptoProvider.IV)
End Function
Below code is in java for 3DES encryption and decryption. please try with this code. I hope it will help you
private static final String UNICODE_FORMAT = "UTF8";
public static final String DESEDE_ENCRYPTION_SCHEME = "DESede"; //"DESede/ECB/NoPadding";
private KeySpec ks;
private SecretKeyFactory skf;
private Cipher cipher;
byte[] arrayBytes;
private String myEncryptionKey;
private String myEncryptionScheme;
SecretKey key;
public PasswordEncryption_TrippleDES() throws Exception {
myEncryptionKey = "ThisIsSpartaThisIsanilku";
myEncryptionScheme = DESEDE_ENCRYPTION_SCHEME;
arrayBytes = myEncryptionKey.getBytes(UNICODE_FORMAT);
ks = new DESedeKeySpec(arrayBytes);
skf = SecretKeyFactory.getInstance(myEncryptionScheme);
cipher = Cipher.getInstance(myEncryptionScheme);
key = skf.generateSecret(ks);
}
public String encrypt(String unencryptedString) {
String encryptedString = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] plainText = unencryptedString.getBytes(UNICODE_FORMAT);
byte[] encryptedText = cipher.doFinal(plainText);
encryptedString = new String(Base64.encodeBase64(encryptedText));
} catch (Exception e) {
e.printStackTrace();
}
return encryptedString;
}
public String decrypt(String encryptedString) {
String decryptedText=null;
try {
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] encryptedText = Base64.decodeBase64(encryptedString);
byte[] plainText = cipher.doFinal(encryptedText);
decryptedText= new String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
return decryptedText;
}
public static void main(String args []) throws Exception
{
PasswordEncryption_TrippleDES td= new PasswordEncryption_TrippleDES();
String target="data for encyption";
String encrypted=td.encrypt(target);
String decrypted=td.decrypt(encrypted);
System.out.println("String To Encrypt: "+ target);
System.out.println("Encrypted String:" + encrypted);
System.out.println("Decrypted String:" + decrypted);
}
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);