Related
I have one java code that needs to be converted to c# code.
Java Util class
public class EncryptorDecryptorUtil {
private int keySize;
private Cipher cipher;
public EncryptorDecryptorUtil(int keySize)
{
this.keySize = keySize;
try
{
this.cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace();
}
}
public String decrypt(String salt, String iv, String passphrase, String EncryptedText)
{
String decryptedValue = null;
try
{
byte[] saltBytes = hexStringToByteArray(salt);
SecretKeySpec sKey = (SecretKeySpec)generateKeyFromPassword(
passphrase, saltBytes);
byte[] ivBytes = hexStringToByteArray(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(ivBytes);
this.cipher.init(2, sKey, ivParameterSpec);
byte[] decordedValue = new BASE64Decoder()
.decodeBuffer(EncryptedText);
byte[] decValue = this.cipher.doFinal(decordedValue);
decryptedValue = new String(decValue);
}
catch (Exception e)
{
e.printStackTrace();
}
return decryptedValue;
}
public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes)
throws GeneralSecurityException
{
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes,
100, 128);
SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(secretKey.getEncoded(), "AES");
}
public static byte[] hexStringToByteArray(String s)
{
System.out.println("s:::::::"+s);
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[(i / 2)] =
((byte)((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)));
}
return data;
}
}
Java Main methods
public class EncryptionDecryption {
#SuppressWarnings("unchecked")
public static void main(String[] args) {
JSONObject json = new JSONObject();
json.put("applicationNo","PNB00000000000004016");
json.put("custID","PNB000000004016");
String input = json.toJSONString();
String password = "46ea428a97ba4c3094fc66e112d1d678";
EncryptionDecryption enc = new EncryptionDecryption();
String encryptMessage= enc.encryptMessage(input, password);
System.out.println("Encrypted Message :"+encryptMessage);
String encrypt2Message = "8b7a1e90d701f55c49e22135eed31c94 89f9af1e83e8c83bdf603f5428ba6f14 0R2A2JDkY8tFR1FZojY7Su9CVI9zjw4yjr/lRElwU75MF5e0LxgOb+Y/DOyVFNd89Ra4YADIZdopLZ5a59Z2BgEjMpSn27tqnGfFvWtfm+eh+A/aVcB2YwfD9rdsd67x6xUb8kmfL7qnO/uxaHyQtqlvwpNRBVjyfRlk1wPfaxyOQa0oEiWRmUXYxEoJ651EhYtHeHKmII7qzDgcioIYUlsBgZUjOu0sNEdiwSvvHbw=";
String decryptMessage = enc.decryptMessage(encrypt2Message, password);
System.out.println("decryptMessage Message :"+decryptMessage);
}
public String encryptMessage(String txtToEncrypt, String passphrase)
{
System.out.println("encryptMessage :txtToEncrypt :"+txtToEncrypt);
String combineData = "";
try
{
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
String saltHex = getRandomHexString(32);
String ivHex = getRandomHexString(32);
byte[] salt = hexStringToByteArray(saltHex);
byte[] iv = hexStringToByteArray(ivHex);
SecretKeySpec sKey = (SecretKeySpec)generateKeyFromPassword(
passphrase, salt);
cipher.init(1, sKey, new IvParameterSpec(iv));
byte[] utf8 = txtToEncrypt.getBytes("UTF-8");
byte[] enc = cipher.doFinal(utf8);
combineData = saltHex + " " + ivHex + " " +
new BASE64Encoder().encode(enc);
}
catch (Exception e)
{
e.printStackTrace();
}
combineData = combineData.replaceAll("\n", "").replaceAll("\t", "").replaceAll("\r", "");
return combineData;
}
public String decryptMessage(String str, String myKey)
{
String decrypted = null;
try
{
if ((str != null) && (str.contains(" ")))
{
String salt = str.split(" ")[0];
String iv = str.split(" ")[1];
String encryptedText = str.split(" ")[2];
EncryptorDecryptorUtil dec = new EncryptorDecryptorUtil(128);
decrypted = dec.decrypt(salt, iv, myKey, encryptedText);
}
else
{
decrypted = str;
}
}
catch (Exception e)
{
e.printStackTrace();
}
return decrypted;
}
public static String getRandomHexString(int numchars)
{
Random r = new Random();
StringBuilder sb = new StringBuilder();
while (sb.length() < numchars) {
sb.append(Integer.toHexString(r.nextInt()));
}
return sb.toString().substring(0, numchars);
}
public static byte[] hexStringToByteArray(String s)
{
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[(i / 2)] =
((byte)((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i + 1), 16)));
}
return data;
}
public static SecretKey generateKeyFromPassword(String password, byte[] saltBytes)
throws GeneralSecurityException
{
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), saltBytes,
100, 128);
SecretKeyFactory keyFactory =
SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
SecretKey secretKey = keyFactory.generateSecret(keySpec);
return new SecretKeySpec(secretKey.getEncoded(), "AES");
}
}
I have tried below code in .net
public static byte[] hexStringToByteArray(string hexString)
{
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < data.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return data;
}
public string generateKey(String password, byte[] saltBytes)
{
int iterations = 100;
var rfc2898 =
new System.Security.Cryptography.Rfc2898DeriveBytes(password, saltBytes, iterations);
byte[] key = rfc2898.GetBytes(16);
String keyB64 = Convert.ToBase64String(key);
return keyB64;
}
Decrypt method in c#
public string DecryptAlter(string salt, string iv, string passphrase, string EncryptedText)
{
string decryptedValue = null;
try
{
byte[] saltBytes = hexStringToByteArray(salt);
string sKey = generateKey(passphrase, saltBytes);
byte[] ivBytes = hexStringToByteArray(iv);
byte[] keyBytes = System.Convert.FromBase64String(sKey);
AesManaged aesCipher = new AesManaged();
aesCipher.IV = ivBytes;
aesCipher.KeySize = 128;
aesCipher.BlockSize = 128;
aesCipher.Mode = CipherMode.ECB;
aesCipher.Padding = PaddingMode.PKCS7;
byte[] b = System.Convert.FromBase64String(EncryptedText);
ICryptoTransform decryptTransform = aesCipher.CreateDecryptor(keyBytes, ivBytes);
byte[] plainText = decryptTransform.TransformFinalBlock(b, 0, b.Length);
var res = System.Text.Encoding.UTF8.GetString(plainText);
return res;
}
catch (Exception e)
{
var k = e.Message;
}
return "";
}
Its not working. Please help me
The Encryption password is “46ea428a97ba4c3094fc66e112d1d678”
Encrypted Text - 4cdf7b17b7db00d7911498dec913d3e4 1e55c4e950b772685ccfdb831c82fede SCQXvM7GeKxP0jLtX5xbuF0WvBC/C81wwxtYNduUe9lVzaYztaJ8ifivjaCBWd7O2zSa+/A+vtFfdSWSnN5+RcjWka42QQl4f+yZ8C1Y/efIsUlDVXBXmSEjSUp/4sflXNz7qg62Ka+atpj0aiG6QvU+T5tnafmsDhx/M3zE+Tg=
Now need to decrypt it.
This is what I got so far to guide you towards a final solution. The encrypted message contains a salt and iv that need to be extracted then used to decrypt the message.
using System;
using System.Globalization;
using System.Security.Cryptography;
public class Program
{
public static void Main()
{
string password = "46ea428a97ba4c3094fc66e112d1d678";
string encrypt2Message = "8b7a1e90d701f55c49e22135eed31c94 89f9af1e83e8c83bdf603f5428ba6f14 0R2A2JDkY8tFR1FZojY7Su9CVI9zjw4yjr/lRElwU75MF5e0LxgOb+Y/DOyVFNd89Ra4YADIZdopLZ5a59Z2BgEjMpSn27tqnGfFvWtfm+eh+A/aVcB2YwfD9rdsd67x6xUb8kmfL7qnO/uxaHyQtqlvwpNRBVjyfRlk1wPfaxyOQa0oEiWRmUXYxEoJ651EhYtHeHKmII7qzDgcioIYUlsBgZUjOu0sNEdiwSvvHbw=";
string[] pieces = encrypt2Message.Split(' ');
string salt = pieces[0];
string iv = pieces[1];
string encmessage = pieces[2];
string decryptMessage = DecryptAlter( salt, iv, password, encmessage);
Console.WriteLine("decryptMessage Message :"+decryptMessage);
}
public static byte[] hexStringToByteArray(string hexString)
{
byte[] data = new byte[hexString.Length / 2];
for (int index = 0; index < data.Length; index++)
{
string byteValue = hexString.Substring(index * 2, 2);
data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture);
}
return data;
}
public static string generateKey(String password, byte[] saltBytes)
{
int iterations = 100;
var rfc2898 =
new System.Security.Cryptography.Rfc2898DeriveBytes(password, saltBytes, iterations);
byte[] key = rfc2898.GetBytes(16);
String keyB64 = Convert.ToBase64String(key);
return keyB64;
}
public static string DecryptAlter(string salt, string iv, string passphrase, string EncryptedText)
{
string decryptedValue = null;
try
{
byte[] saltBytes = hexStringToByteArray(salt);
string sKey = generateKey(passphrase, saltBytes);
byte[] ivBytes = hexStringToByteArray(iv);
byte[] keyBytes = System.Convert.FromBase64String(sKey);
AesManaged aesCipher = new AesManaged();
aesCipher.IV = ivBytes;
aesCipher.KeySize = 128;
aesCipher.BlockSize = 128;
aesCipher.Mode = CipherMode.CBC;
aesCipher.Padding = PaddingMode.PKCS7;
byte[] b = System.Convert.FromBase64String(EncryptedText);
ICryptoTransform decryptTransform = aesCipher.CreateDecryptor(keyBytes, ivBytes);
byte[] plainText = decryptTransform.TransformFinalBlock(b, 0, b.Length);
var res = System.Text.Encoding.UTF8.GetString(plainText);
return res;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.WriteLine(e.StackTrace);
}
return "";
}
}
public string decryptMessage()
{
string str="some encrypted message";
string myKey = "46ea428a97ba4c3094fc66e112d1d678";
string decrypted = null;
try
{
if ((str != null) && (str.Contains(' ')))
{
string salt = str.Split(' ')[0];
string iv = str.Split(' ')[1];
String encryptedText = str.Split(' ')[2];
decrypted = DecryptAlter(salt, iv, myKey, encryptedText);
return decrypted;
}
else
{
decrypted = str;
return decrypted;
}
}
catch (Exception e)
{
}
return decrypted;
}
public string DecryptAlter(string salt, string iv, string passphrase, string EncryptedText)
{
string decryptedValue = null;
try
{
byte[] saltBytes = hexStringToByteArray(salt);
string sKey = generateKey(passphrase, saltBytes);
byte[] ivBytes = hexStringToByteArray(iv);
byte[] keyBytes = System.Convert.FromBase64String(sKey);
AesManaged aesCipher = new AesManaged();
aesCipher.IV = ivBytes;
aesCipher.KeySize = 128;
aesCipher.BlockSize = 128;
aesCipher.Mode = CipherMode.CBC;
aesCipher.Padding = PaddingMode.PKCS7;
byte[] b = System.Convert.FromBase64String(EncryptedText);
ICryptoTransform decryptTransform = aesCipher.CreateDecryptor(keyBytes, ivBytes);
byte[] plainText = decryptTransform.TransformFinalBlock(b, 0, b.Length);
var res = System.Text.Encoding.UTF8.GetString(plainText);
return res;
}
catch (Exception e)
{
var k = e.Message;
}
return "";
}
I want to encrypt data from a client and send it to a server over a socket. The client is written in Java and the server is written in C. However, the result is not the same as my expected.
The C program as follows:
#define MAX_BUFF 1024
#define MAX_LENGTH_DATA 1024
static void decrypt128(unsigned char intput[], unsigned char output[]) {
mbedtls_aes_context context_out;
unsigned char key1[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P'};
unsigned char iv1[16] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
unsigned char decrypt[128];
mbedtls_aes_init(&context_out);
mbedtls_aes_setkey_dec(&context_out, key1, 128);
mbedtls_aes_crypt_cbc(&context_out, MBEDTLS_AES_DECRYPT, 16, iv1, intput,decrypt);
printf("\nInside of decrypt128 function:\n");
for (unsigned index = 0; index < 128; ++index)
printf("%c", (char) decrypt[index]);
strcpy(output, decrypt);
}
int main(int argc, char * argv[]){
int socket_desc, client_sock, c, read_size, rc, option = 1, ret,
encrypt_size, counter_data_receive;
struct sockaddr_in server, client;
int opt = 1;
struct timeval timeout_receive;
unsigned char encrypt_bufferr[MAX_LENGTH_DATA] = { 0 };
unsigned char decrypt_bufferr[MAX_LENGTH_DATA] = { 0 };
// Creating socket file descriptor
printf("Creating socket...!!!!!\n");
if ((socket_desc = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 4434
if (setsockopt(socket_desc, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
sizeof(opt))) {
perror("setsockopt");
exit(EXIT_FAILURE);
}
server.sin_family = AF_INET;
server.sin_addr.s_addr = INADDR_ANY;
server.sin_port = htons(4434);
// Forcefully attaching socket to the port 4434
if (bind(socket_desc, (struct sockaddr *) &server, sizeof(server)) < 0) {
perror("bind failed");
exit(EXIT_FAILURE);
}
c = sizeof(struct sockaddr_in);
printf("Start waiting for incoming connections!\n");
listen(socket_desc, 1);
client_sock = accept(socket_desc, (struct sockaddr*) &client,
(socklen_t*) &c);
if (client_sock < 0) {
printf("Failed: accept connection");
exit(EXIT_FAILURE);
}
printf("Connection accepted\n");
timeout_receive.tv_sec = 5;
timeout_receive.tv_usec = 0;
setsockopt(client_sock, SOL_SOCKET, SO_RCVTIMEO,
(const void*) &timeout_receive, sizeof(struct timeval));
memset(encrypt_bufferr, 0x00, sizeof(encrypt_bufferr));
memset(decrypt_bufferr, 0x00, sizeof(decrypt_bufferr));
ret = recv(client_sock, encrypt_bufferr, sizeof(encrypt_bufferr), 0);
printf("\n+++++++++++++byte receive: %d\n", ret);
printf("\n+++++++++++++received buff: %s\n", encrypt_bufferr);
decrypt128(encrypt_bufferr, decrypt_bufferr);
printf("\nFinal decrypted data = %s", decrypt_bufferr);
}
output
Creating socket...!!!!!
Start waiting for incoming connections!
Connection accepted
+++++++++++++byte receive: 24
+++++++++++++received buff: 8+4c4xcMC1FPhdJabnl/4w==
Inside of decrypt128 function:
R�V͵2�Q���˵��
For the client-side, I wrote it using Java:
public class EncryptDecryptString {
private static final String cipherTransformation = "AES/CBC/PKCS5PADDING";
private static final String aesEncryptionAlgorithem = "AES";
public static String encrypt(String plainText) {
String encryptedText = "";
byte iv1[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
byte[] key = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
SecretKeySpec secretKey = new SecretKeySpec(key, aesEncryptionAlgorithem);
IvParameterSpec ivparameterspec = new IvParameterSpec(iv1);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF-8"));
Base64.Encoder encoder = Base64.getEncoder();
encryptedText = encoder.encodeToString(cipherText);
} catch (Exception E) {
System.err.println("Encrypt Exception : "+E.getMessage());
}
return encryptedText;
}
public static String decrypt(String encryptedText) {
String decryptedText = "";
byte iv1[] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };
try {
Cipher cipher = Cipher.getInstance(cipherTransformation);
byte[] key = { 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P' };//encryptionKey.getBytes(characterEncoding);
SecretKeySpec secretKey = new SecretKeySpec(key, aesEncryptionAlgorithem);
IvParameterSpec ivparameterspec = new IvParameterSpec(iv1);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivparameterspec);
Base64.Decoder decoder = Base64.getDecoder();
byte[] cipherText = decoder.decode(encryptedText.getBytes("UTF8"));
decryptedText = new String(cipher.doFinal(cipherText), "UTF-8");
} catch (Exception E) {
System.err.println("decrypt Exception : "+E.getMessage());
}
return decryptedText;
}
public static void main(String[] args) {
//System.out.println("Enter String : ");
System.out.println("Running.... ");
String plainString = "Hello world!";//sc.nextLine();
String encyptStr = encrypt(plainString);
String decryptStr = decrypt(encyptStr);
Socket socketOfClient;
try {
socketOfClient = new Socket("127.0.0.1", 4434);
BufferedWriter os = new BufferedWriter(new OutputStreamWriter(socketOfClient.getOutputStream()));
BufferedReader is = new BufferedReader(new InputStreamReader(socketOfClient.getInputStream()));
os.write(encyptStr);
os.flush();
System.out.printf("\nSent data to server....\n");
//os.flush();
} catch (UnknownHostException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Plain String : "+plainString);
System.out.println("Encrypt String : "+encyptStr);
System.out.println("Decrypt String : "+decryptStr);
}
}
Output
Running....
Sent data to server....
Plain String : Hello world!
Encrypt String : 8+4c4xcMC1FPhdJabnl/4w==
Decrypt String : Hello world!
The received encrypted data is the same between the two sides, but when I used mbedtl to decrypt this data in the server-side, the result is not the same. Please help me to resolve the problem. Thank you!!!!
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 attempting to translate the following code in PHP to Java.
private function _aes256_cbc_encrypt($key, $data, $iv) {
if (32 !== strlen($key))
$key = hash('SHA256', $key, true);
if (16 !== strlen($iv))
$iv = hash('MD5', $iv, true);
$padding = 16 - (strlen($data) % 16);
$data .= str_repeat(chr($padding), $padding);
return mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $data, MCRYPT_MODE_CBC, $iv);
}
So far this is what I have in Java.
private String aes256_cbc_encrypt(String key, String data, String iv) throws Exception {
if (32 != key.length())
key = sha256(key);
if (16 != iv.length())
iv = md5(iv);
char padding = (char) (16-(data.length() % 16));
char[] paddingArray = new char[padding];
Arrays.fill(paddingArray, padding);
data = data + new String(paddingArray);
String mcryptData = data;
MCrypt mcrypt = new MCrypt();
String encrypted = mcrypt.bytesToHex(mcrypt.encrypt(mcryptData));
return encrypted;
}
The sha256 and md5 methods are:
public static String md5(String input) throws NoSuchAlgorithmException{
String result = input;
if(input != null) {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.getBytes());
BigInteger hash = new BigInteger(1, md.digest());
result = hash.toString(16);
while(result.length() < 32) {
result = "0" + result;
}
}
return result;
}
public static String sha256(String input) throws NoSuchAlgorithmException{
String result = input;
if(input != null) {
MessageDigest md = MessageDigest.getInstance("MD5");
md.update(input.getBytes());
BigInteger hash = new BigInteger(1, md.digest());
result = hash.toString(16);
while(result.length() < 32) {
result = "0" + result;
}
}
return result;
}
And the mcrypt class I am using (which I found here https://github.com/serpro/Android-PHP-Encrypt-Decrypt/blob/master/Java/src/com/serpro/library/String/MCrypt.java) is
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
class MCrypt {
static char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
private String iv = "{Yr5xwjQp0:\\EC4L";
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "m78gLMbPQ";
public MCrypt()
{
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
//Remove trailing zeroes
if( decrypted.length > 0)
{
int trim = 0;
for( int i = decrypted.length - 1; i >= 0; i-- ) if( decrypted[i] == 0 ) trim++;
if( trim > 0 )
{
byte[] newArray = new byte[decrypted.length - trim];
System.arraycopy(decrypted, 0, newArray, 0, decrypted.length - trim);
decrypted = newArray;
}
}
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] buf)
{
char[] chars = new char[2 * buf.length];
for (int i = 0; i < buf.length; ++i)
{
chars[2 * i] = HEX_CHARS[(buf[i] & 0xF0) >>> 4];
chars[2 * i + 1] = HEX_CHARS[buf[i] & 0x0F];
}
return new String(chars);
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private static String padString(String source)
{
char paddingChar = 0;
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
}
However the two codes give me different results. Can anyone please explain why this might be.
In the code below I'm initializing the security key from an external class. Is it necessary to use the security key length of 16? Any possibility to use the smaller length byte?
import java.security.NoSuchAlgorithmException;
import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class MCrypt {
private String iv = "fedcba9876543210";
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey ;
public MCrypt(String s)
{
SecretKey=s;
ivspec = new IvParameterSpec(iv.getBytes());
keyspec = new SecretKeySpec(SecretKey.getBytes(), "AES");
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public byte[] encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
byte[] encrypted = null;
try {
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return encrypted;
}
public byte[] decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
byte[] decrypted = null;
try {
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return decrypted;
}
public static String bytesToHex(byte[] data)
{
if (data==null)
{
return null;
}
int len = data.length;
String str = "";
for (int i=0; i<len; i++) {
if ((data[i]&0xFF)<16)
str = str + "0" + java.lang.Integer.toHexString(data[i]&0xFF);
else
str = str + java.lang.Integer.toHexString(data[i]&0xFF);
}
return str;
}
public static byte[] hexToBytes(String str) {
if (str==null) {
return null;
} else if (str.length() < 2) {
return null;
} else {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i=0; i<len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i*2,i*2+2),16);
}
return buffer;
}
}
private static String padString(String source)
{
char paddingChar = ' ';
int size = 16;
int x = source.length() % size;
int padLength = size - x;
for (int i = 0; i < padLength; i++)
{
source += paddingChar;
}
return source;
}
}
Your key must match one of the permitted lengths for the AES algorithm: 16, 24 or 32 bytes. You cannot use a key smaller than 16 bytes.
Some other comments on your code:
Use camelCase for all variables (e.g. secretKey).
Avoid using a fixed IV. Generate a random IV each time and store it with the ciphertext.
Consider using a padding mode (e.g. AES/CBC/PKCS5Padding) otherwise your input must always be a multiple of 16 bytes.
You are calling getBytes() on a string without supplying a charset. This could result in different results on different platforms. Always specify a character set.
In addition to Duncan's suggested improvements:
Never ever use a password/String directly as a key!
If you want to create a key based on a password use a "Password based key derivation function" - e.g. the standard is PBKDF2 (see for example this question: PBKDF2 with bouncycastle in Java).