In Java code, i have source work well, this is use for encrypt:
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
public class HelloWorld{
private static final String hexKey = "B8EE12E123C0E300A202074A153CC0D27D739357480FFFFFFFFFFFFFFFFFFFEF";
public static void main(String []args){
System.out.println("Encryt ==== ");
String textToEncrypt = "From=ABC&Key=FootID1234&Value=ResultValue2324";
String encryptedText = encrypt(textToEncrypt);
System.out.println(encryptedText);
System.out.println("Decrypt ==== ");
String decryptedText = decrypt(encryptedText);
System.out.println(decryptedText);
}
public static String encrypt (String plainText) {
String encryptedText = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(hexToBytes(hexKey), "AES");
IvParameterSpec ivparameterspec = new IvParameterSpec(hexKey.getBytes(), 0, 16);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = cipher.doFinal(plainText.getBytes("UTF8"));
encryptedText = bytesToHex(cipherText);
} catch (Exception E) {
System.out.println("Encrypt Exception : " + E.getMessage());
}
return encryptedText;
}
public static String decrypt(String encryptedText) {
String decryptedText = null;
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
SecretKeySpec secretKey = new SecretKeySpec(hexToBytes(hexKey), "AES");
IvParameterSpec ivparameterspec = new IvParameterSpec(hexKey.getBytes("UTF8"), 0, 16);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivparameterspec);
byte[] cipherText = hexToBytes(encryptedText);
byte[] dcrbyte = cipher.doFinal(cipherText);
decryptedText = new String(dcrbyte, "UTF-8");
} catch (Exception E) {
System.out.println("Encrypt Exception : " + E.getMessage());
}
return decryptedText;
}
private static byte[] hexToBytes(String hexStr) {
byte[] val = new byte[hexStr.length() / 2];
for (int i = 0; i < val.length; i++) {
int idx = i * 2;
int j = Integer.parseInt(hexStr.substring(idx, idx + 2), 16);
val[i] = (byte) j;
}
return val;
}
private static String bytesToHex(byte[] hashInBytes) {
char[] hexArray = "0123456789ABCDEF".toCharArray();
char[] hexChars = new char[hashInBytes.length * 2];
for (int i = 0; i < hashInBytes.length; i++) {
int v = hashInBytes[i] & 0xFF;
hexChars[i * 2] = hexArray[v >>> 4];
hexChars[i * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
}
And in c#, i try to write decryptAes() function like this:
public static class Encryption
{
// use these parameters to test decryptAes()
//string key = "B8EE12E123C0E300A202074A153CC0D27D739357480FFFFFFFFFFFFFFFFFFFEF";
//string textToDecrypt = "756AD4D80E2CF1E289D55A23E092F012E8D5F372A343A419BC87F77B6335F04EFB41C3B56F5CDA167F90F67CD672A186";
public static string decryptAes(string key, string textToDecrypt)
{
RijndaelManaged rijndaelCipher = new RijndaelManaged();
// Assumed Mode and padding values.
rijndaelCipher.Mode = CipherMode.CBC;
rijndaelCipher.Padding = PaddingMode.PKCS7;
// AssumedKeySize and BlockSize values.
rijndaelCipher.KeySize = 0x80; //128
rijndaelCipher.BlockSize = 0x80;
// Convert Hex keys to byte Array.
byte[] encryptedData = HexToBytes(textToDecrypt);
//byte[] pwdBytes = System.Text.Encoding.GetEncoding("UTF-8").GetBytes(key);
byte[] pwdBytes = HexToBytes(key);
byte[] keyBytes = new byte[0x10]; //16
int len = pwdBytes.Length;
if (len > keyBytes.Length)
{
len = keyBytes.Length;
}
Array.Copy(pwdBytes, keyBytes, len);
rijndaelCipher.Key = keyBytes;
rijndaelCipher.IV = keyBytes;
// Decrypt data
byte[] plainText = rijndaelCipher.CreateDecryptor()
.TransformFinalBlock(encryptedData, 0, encryptedData.Length);
return Encoding.UTF8.GetString(plainText);
}
public static byte[] HexToBytes(string str)
{
if (str.Length == 0 || str.Length % 2 != 0)
return new byte[0];
byte[] buffer = new byte[str.Length / 2];
char c;
for (int bx = 0, sx = 0; bx < buffer.Length; ++bx, ++sx)
{
// Convert first half of byte
c = str[sx];
buffer[bx] = (byte)((c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0')) << 4);
// Convert second half of byte
c = str[++sx];
buffer[bx] |= (byte)(c > '9' ? (c > 'Z' ? (c - 'a' + 10) : (c - 'A' + 10)) : (c - '0'));
}
return buffer;
}
public static string ByteToHex(byte[] ba)
{
StringBuilder hex = new StringBuilder(ba.Length * 2);
foreach (byte b in ba)
hex.AppendFormat("{0:x2}", b);
return hex.ToString().ToUpper();
}
}
But the c# decryptAes() function does not work as i expect. An error
System.Security.Cryptography.CryptographicException: 'Padding is invalid and cannot be removed.'
has occured at line rijndaelCipher.Padding = PaddingMode.PKCS7;
When i change to rijndaelCipher.Padding = PaddingMode.None, it does not work as i expect, the c# result is not the same as the result of java.
Please help, any advice would be appreciated!
Thanks!
You need to explicitly set the padding for both encryption and decryption. Unless you have a reason to do otherwise, use PKCS#7 padding.
rijndaelCipher.Padding=PaddingMode.none;
Related
var get = function(a) {
var b = CryptoJS.MD5('contentWindowHig');
var c = CryptoJS.enc.Utf8.parse(b);
var d = CryptoJS.enc.Utf8.parse('contentDocuments');
var e = CryptoJS.AES.encrypt(a, c, {
iv: d,
mode: CryptoJS.mode.CBC
pad: CryptoJS.pad.ZeroPadding
});
return e.toString()
}
}
java output is not the same
input plain text: 8d3fj5T7lPMjMfMTyzdbl6Aq95zSUrmuChBFf/ex3lF23jHweq9ABJmEbd7+4z5DmjmhvTVyXWoeoFWCv6xCPFw7CAx7n9RZ9x9fOVrY3Cy+Nm1TAThsjgOjjK+M1S3XIim39NiRp55ai/dm2+E+NzRGPN0wW1bc9Q
js output data:
a: 8d3fj5T7lPMjMfMTyzdbl6Aq95zSUrmuChBFf/ex3lF23jHweq9ABJmEbd7+4z5DmjmhvTVyXWoeoFWCv6xCPFw7CAx7n9RZ9x9fOVrY3Cy+Nm1TAThsjgOjjK+M1S3XIim39NiRp55ai/dm2+E+NzRGPN0wW1bc9Q
b: a165f267f74aba5ded7563ebae2c5ac0
c: 6131363566323637663734616261356465643735363365626165326335616330
d: 636f6e74656e74446f63756d656e7473
e(output): YzYv1oDPuHMyvtt8dgHUOdKaTev3rDtDXu9O%2BBlnCt4X118BroqK7nDjc%2Bo6cb6aoik6KAvIhZwENjkmrMvF26xhhWATh0TrlK0ZWPotNWI9mXWW1FgZtRrFkQGn6%2F4BWY8D%2BAfLxePup4rAw%2BekHjpkFsSZcY6rlL37uUKU%2F6OTdN4rrjG3FOEmN8yDZ9sMNAXu%2FdmAqgFRJ77gvWjgKZEXvhqYqaH1Ukb9eZYMRAE%3D
base64 utf-8 aes iv key confused me...
java output data:
b: a165f267f74aba5ded7563ebae2c5ac0
c: 6131363566323637663734616261356465643735363365626165326335616330
d: 636F6E74656E74446F63756D656E7473
enc_data: fPkNBugoCDHtBLO4tv9VcfGNCWxbqdWryrOWPXrsqN2I0IzNfTN+Smh5PQX5fKsGuHtGWFv7Lryh
jEgOSUJNskH/JD1agfWfzDClSWA7eF4bpKmTg3ch8mrHHI7nwDm4t6jQEeCfDGcQ3Sa8s0UPipOR
wcOTdGVl7RmgJ5gIERQ45m34fm8tveMYrXyTgvDKbvqO7toqshcg6IOxNgB5OCr/DH4xQibnYPnk
0Z4EBy8=
encoded_str: fPkNBugoCDHtBLO4tv9VcfGNCWxbqdWryrOWPXrsqN2I0IzNfTN%2BSmh5PQX5fKsGuHtGWFv7Lryh%0D%0AjEgOSUJNskH%2FJD1agfWfzDClSWA7eF4bpKmTg3ch8mrHHI7nwDm4t6jQEeCfDGcQ3Sa8s0UPipOR%0D%0AwcOTdGVl7RmgJ5gIERQ45m34fm8tveMYrXyTgvDKbvqO7toqshcg6IOxNgB5OCr%2FDH4xQibnYPnk%0D%0A0Z4EBy8%3D
import com.pplive.common.util.LogUtil;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import sun.misc.BASE64Encoder;
public static void main(String[] args) {
// key: 8d3fj5T7lPMjMfMTyzdbl6Aq95zSUrmuChBFf/ex3lF23jHweq9ABJmEbd7+4z5DmjmhvTVyXWoeoFWCv6xCPFw7CAx7n9RZ9x9fOVrY3Cy+Nm1TAThsjgOjjK+M1S3XIim39NiRp55ai/dm2+E+NzRGPN0wW1bc9Q
// b: a165f267f74aba5ded7563ebae2c5ac0
// c: 6131363566323637663734616261356465643735363365626165326335616330
// d: 636f6e74656e74446f63756d656e7473
//ss: YzYv1oDPuHMyvtt8dgHUOdKaTev3rDtDXu9O%2BBlnCt4X118BroqK7nDjc%2Bo6cb6aoik6KAvIhZwENjkmrMvF26xhhWATh0TrlK0ZWPotNWI9mXWW1FgZtRrFkQGn6%2F4BWY8D%2BAfLxePup4rAw%2BekHjpkFsSZcY6rlL37uUKU%2F6OTdN4rrjG3FOEmN8yDZ9sMNAXu%2FdmAqgFRJ77gvWjgKZEXvhqYqaH1Ukb9eZYMRAE%3D
//int end = html.indexOf("\")", start);
//String plaintext = html.substring(start + "encodeURIComponent(get(\"".length(), end);
String plaintext = "8d3fj5T7lPMjMfMTyzdbl6Aq95zSUrmuChBFf/ex3lF23jHweq9ABJmEbd7+4z5DmjmhvTVyXWoeoFWCv6xCPFw7CAx7n9RZ9x9fOVrY3Cy+Nm1TAThsjgOjjK+M1S3XIim39NiRp55ai/dm2+E+NzRGPN0wW1bc9Q";
System.out.println("plaintext: " + plaintext);
try {
String b = EncoderByMd5("contentWindowHig");
System.out.println("b: " + b);
String c = byteToHexString(b.getBytes("utf-8"));
System.out.println("c: " + c);
String d = byteToHexString("contentDocuments".getBytes("utf-8"));
System.out.println("d: " + d);
String enc_data = AES_CBC_Encrypt_nopadding(
plaintext.getBytes("utf-8"),
b.getBytes(),
"contentDocuments".getBytes());
System.out.println("enc_data: " + enc_data);
String encoded_str = URLEncoder.encode(enc_data, "utf-8");
System.out.println("encoded_str: " + encoded_str);
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
}
public static String AES_CBC_Encrypt_nopadding(byte[] content, byte[] keyBytes, byte[] iv){
try{
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom(keyBytes));
SecretKey key = keyGenerator.generateKey();
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
int blockSize = cipher.getBlockSize();
// process plain text
int plaintextLength = content.length;
if (plaintextLength % blockSize != 0) {
plaintextLength = plaintextLength + (blockSize - (plaintextLength % blockSize));
}
byte[] plaintext = new byte[plaintextLength];
System.arraycopy(content, 0, plaintext, 0, content.length);
for (int i=content.length;i<plaintextLength;i++) {
plaintext[i] = (byte)0;
}
cipher.init(Cipher.ENCRYPT_MODE, key, new IvParameterSpec(iv));
byte[] encrypted = cipher.doFinal(plaintext);
BASE64Encoder base64en = new BASE64Encoder();
return base64en.encode(encrypted);
}catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("exception:"+e.toString());
}
return null;
}
public static String EncoderByMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
MessageDigest md5=MessageDigest.getInstance("MD5");
md5.update(str.getBytes());
return new BigInteger(1, md5.digest()).toString(16);
}
public static String AES_CBC_Decrypt(byte[] content, byte[] keyBytes, byte[] iv){
try{
KeyGenerator keyGenerator=KeyGenerator.getInstance("AES");
keyGenerator.init(128, new SecureRandom(keyBytes));//key长可设为128,192,256位,这里只能设为128
SecretKey key=keyGenerator.generateKey();
Cipher cipher=Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(iv));
byte[] result = cipher.doFinal(content);
BASE64Encoder base64en = new BASE64Encoder();
return base64en.encode(result);
}catch (Exception e) {
// TODO Auto-generated catch block
System.out.println("exception:"+e.toString());
}
return null;
}
//Converting a string of hex character to bytes
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 String byteToHexString(byte[] bytes) {
StringBuffer sb = new StringBuffer(bytes.length);
String sTemp;
for (int i = 0; i < bytes.length; i++) {
sTemp = Integer.toHexString(0xFF & bytes[i]);
if (sTemp.length() < 2)
sb.append(0);
sb.append(sTemp.toUpperCase());
}
return sb.toString();
}
so easy .
js convert to java
// var b = CryptoJS.MD5('contentWindowHig');
String b = org.apache.commons.codec.digest.DigestUtils.md5Hex("contentWindowHig");
// var c = CryptoJS.enc.Utf8.parse(b);
byte[] c = b.getByte("UTF-8");
// var d = CryptoJS.enc.Utf8.parse('contentDocuments');
byte[] d = "contentDocuments".getByte("UTF-8");
/* var e = CryptoJS.AES.encrypt(a, c, {
iv: d,
mode: CryptoJS.mode.CBC
pad: CryptoJS.pad.ZeroPadding
});
return e.toString()
*/
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(c, "AES"), new IvParameterSpec(d));
Base64.getEncoder().encodeToString(cipher.doFinal(a.getBytes("utf-8")));
a is encrypt str
i try to decrypt a encrypted text and use this code but get this error to me:
Exception in thread "main" java.security.InvalidKeyException: Illegal key size
and decryption code is:
String key = "ffce885876a617e7";
String vector = "9ee153a3df56965e7baf13a7fa1075cc";
IvParameterSpec ivSpec = new IvParameterSpec(key.getBytes());
SecretKeySpec keySpec = new SecretKeySpec(vector.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec); //error occured in this line
.getBytes() will not automagically convert a "hex string" to the matching bytes.
Instead, try this utility method:
private static byte[] hexStringToBytes(final String input)
{
final int len = input.length();
if (len % 2 != 0)
throw new IllegalArgumentException();
final byte[] ret = new byte[len / 2];
int offset = 0;
for (int i = 0; i < ret.length; i++) {
ret[i] = (byte) Integer.parseInt(input.substring(offset, offset+2), 16);
offset += 2;
}
return ret;
}
Then in your code use hexStringToBytes(key) etc.
I uses this one to decrypt AES. But in Android env instead of Java vanila.
public String decrypt(String enc) throws Exception {
try {
String key = "ffce885876a617e7";
String vector = "9ee153a3df56965e7baf13a7fa1075cc";
IvParameterSpec ivSpec = new IvParameterSpec(key.getBytes());
SecretKeySpec keySpec = new SecretKeySpec(vector.getBytes(),
"AES");
Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
return new String(cipher.doFinal(hexToByte(enc)), "UTF-8");
} catch (Exception localException) {
throw new Exception("[decrypt] " + localException.getMessage());
}
}
private static byte[] hexToByte(String enc) {
int j = enc.length() / 2;
byte[] arrayOfByte = new byte[j];
if (j >= 2) {
for (int i = 0; i < j; i++) {
arrayOfByte[i] = ((byte) Integer.parseInt(
enc.substring(i * 2, 2 + i * 2), 16));
}
}
return arrayOfByte;
}
I have a requirement to AES Encrypt (with initial vector) an NSString value.But it gives different output on comparing with the java code provided below.In Java it is delivering the correct result.What could be the reason?
For that I have used the code below:
iOS
- (NSData *)AES256EncryptWithKey:(NSString *)key
{
// 'key' should be 32 bytes for AES256, will be null-padded otherwise
char keyPtr[kCCKeySizeAES128+1]; // room for terminator (unused)
bzero(keyPtr, sizeof(keyPtr)); // fill with zeroes (for padding)
// fetch key data
[key getCString:keyPtr maxLength:sizeof(keyPtr) encoding:NSUTF8StringEncoding];
NSUInteger dataLength = [self length];
//See the doc: For block ciphers, the output size will always be less than or
//equal to the input size plus the size of one block.
//That's why we need to add the size of one block here
size_t bufferSize = dataLength + kCCBlockSizeAES128;
void *buffer = malloc(bufferSize);
size_t numBytesEncrypted = 0;
CCCryptorStatus cryptStatus = CCCrypt(kCCEncrypt, kCCAlgorithmAES128, kCCOptionPKCS7Padding,
keyPtr, kCCKeySizeAES128 ,
INTIAL_VECTOR /* initialization vector (optional) */,
[self bytes], dataLength, /* input */
buffer, bufferSize, /* output */
&numBytesEncrypted);
if (cryptStatus == kCCSuccess) {
//the returned NSData takes ownership of the buffer and will free it on deallocation
return [NSData dataWithBytesNoCopy:buffer length:numBytesEncrypted];
}
free(buffer); //free the buffer;
return nil;
}
- (NSString*)hexStringFromData:(NSData *)data
{
unichar* hexChars = (unichar*)malloc(sizeof(unichar) * (data.length*2));
unsigned char* bytes = (unsigned char*)data.bytes;
for (NSUInteger i = 0; i < data.length; i++) {
unichar c = bytes[i] / 16;
if (c < 10) c += '0';
else c += 'a' - 10;
hexChars[i*2] = c;
c = bytes[i] % 16;
if (c < 10) c += '0';
else c += 'a' - 10;
hexChars[i*2+1] = c;
}
NSString* retVal = [[NSString alloc] initWithCharactersNoCopy:hexChars
length:data.length*2
freeWhenDone:YES];
return [retVal autorelease];
}
The implementation snippet is :
NSData *InputData = [#"mahi" dataUsingEncoding:NSUTF8StringEncoding];
NSData *encryptedData = [InputData AES256EncryptWithKey:ENCRYPTION_KEY];
NSString *encryptedHexString = [self hexStringFromData:encryptedData];
NSLog(#"Encrypted HexString : %#",encryptedHexString);
Java
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 = "0123456789abcdef";
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));
} 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;
}
}
I have to encrypt a string in my iPhone app. The encryption scheme is 3DES/CBC/PKCS5 padding and I have to convert in objective-c this Java code:
public class MessageEncrypt {
public String encryptString(String message, String seckey) throws Exception{
byte[] encData = encrypt(message, seckey);
return this.getHexString(encData, "");
}
public String decryptString(String message, String seckey) throws Exception{
return decrypt(this.getBArray(message), seckey);
}
private byte[] encrypt(String message, String seckey) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(seckey.getBytes("utf-8"));
final byte[] keyBytes = acopyof(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
final byte[] plainTextBytes = message.getBytes("utf-8");
final byte[] cipherText = cipher.doFinal(plainTextBytes);
// final String encodedCipherText = new sun.misc.BASE64Encoder()
// .encode(cipherText);
return cipherText;
}
private String decrypt(byte[] message, String seckey) throws Exception {
final MessageDigest md = MessageDigest.getInstance("md5");
final byte[] digestOfPassword = md.digest(seckey.getBytes("utf-8"));
final byte[] keyBytes = acopyof(digestOfPassword, 24);
for (int j = 0, k = 16; j < 8;) {
keyBytes[k++] = keyBytes[j++];
}
final SecretKey key = new SecretKeySpec(keyBytes, "DESede");
final IvParameterSpec iv = new IvParameterSpec(new byte[8]);
final Cipher decipher = Cipher.getInstance("DESede/CBC/PKCS5Padding");
decipher.init(Cipher.DECRYPT_MODE, key, iv);
final byte[] plainText = decipher.doFinal(message);
return new String(plainText, "UTF-8");
}
private String getHexString(byte[] barray, String delim) {
StringBuffer buffer = new StringBuffer();
for (int i = 0; i < barray.length; i++) {
int ii = barray[i] & 0xFF;
String bInt = Integer.toHexString(ii);
if (ii < 16) {
bInt = "0" + bInt.toUpperCase();
}
buffer.append(bInt);
if (i < barray.length - 1) {
buffer.append(delim);
}
}
return buffer.toString().toUpperCase();
}
private byte[] getBArray(String bString) {
byte[] retBytes;
if (bString.length() % 2 != 0) {
return new byte[0];
}
retBytes = new byte[bString.length() / 2];
for (int i = 0; i < bString.length() / 2; i++) {
retBytes[i] = (byte) ((Character.digit(bString.charAt(2 * i), 16) << 4) + Character.digit(bString.charAt(2 * i + 1), 16));
}
return retBytes;
}
public static byte[] acopyof(byte[] orig, int newlength){
byte[] copya = new byte[newlength];
for(int i=0;i< orig.length;i++){
copya[i]=orig[i];
}
for(int i=orig.length;i<newlength;i++){
copya[i]=0x0;
}
return copya;
}
}
I made this objective-c method to match those specs:
+(NSString*)doCipher:(NSString*)sTextIn:(CCOperation)encryptOrDecrypt {
// const void *vplainText;
// size_t plainTextBufferSize;
NSMutableData *dTextIn;
if (encryptOrDecrypt == kCCDecrypt)
{
}
else
{
dTextIn = [[sTextIn dataUsingEncoding: NSASCIIStringEncoding]mutableCopy];
}
NSLog(#"************** Init encrypting **********************************");
NSLog(#"This is data to encrypt %#",dTextIn);
CCCryptorStatus ccStatus;
uint8_t *bufferPtr = NULL;
size_t bufferPtrSize = 0;
size_t movedBytes = 0;
// uint8_t ivkCCBlockSize3DES;
bufferPtrSize = ([dTextIn length] + kCCBlockSize3DES) & ~(kCCBlockSize3DES - 1);
bufferPtr = malloc( bufferPtrSize * sizeof(uint8_t));
memset((void *)bufferPtr, 0x00, bufferPtrSize);
// Initialization vector; in this case 8 bytes.
uint8_t iv[kCCBlockSize3DES];
memset((void *) iv, 0x8, (size_t) sizeof(iv));
UserAndPassword *userPass = [[UserAndPassword alloc]init];
NSString *userPassword = userPass.password;
NSLog(#"This is my password %#",userPassword);
NSString *key = [userPassword MD5String];
NSLog(#"This is MD5 key %#",key);
NSMutableData *_keyData = [[key dataUsingEncoding:NSASCIIStringEncoding]mutableCopy];
unsigned char *bytePtr = (unsigned char *)[_keyData bytes];
NSLog(#"Bytes of key are %s ", bytePtr);
NSLog(#"******** This is my key length %d *******",[_keyData length]);
[_keyData setLength:24];
unsigned char *bytePtr1 = (unsigned char *)[_keyData bytes];
NSLog(#"******** Bytes of key are %s ************", bytePtr1);
NSLog(#"********* This is key length %d ***********",[_keyData length]);
ccStatus = CCCrypt(encryptOrDecrypt, // CCoperation op
kCCAlgorithm3DES, // CCAlgorithm alg
kCCOptionPKCS7Padding, // CCOptions
[_keyData bytes], // const void *key
kCCKeySize3DES, // 3DES key size length 24 bit
iv, //const void *iv,
[dTextIn bytes], // const void *dataIn
[dTextIn length], // size_t dataInLength
(void *)bufferPtr, // void *dataOut
bufferPtrSize, // size_t dataOutAvailable
&movedBytes); // size_t *dataOutMoved
if (ccStatus == kCCParamError) return #"PARAM ERROR";
else if (ccStatus == kCCBufferTooSmall) return #"BUFFER TOO SMALL";
else if (ccStatus == kCCMemoryFailure) return #"MEMORY FAILURE";
else if (ccStatus == kCCAlignmentError) return #"ALIGNMENT";
else if (ccStatus == kCCDecodeError) return #"DECODE ERROR";
else if (ccStatus == kCCUnimplemented) return #"UNIMPLEMENTED";
NSString *result;
if (encryptOrDecrypt == kCCDecrypt)
{
// result = [[NSString alloc] initWithData: [NSData dataWithBytes:(const void *)bufferPtr length:[(NSUInteger)movedBytes] encoding:NSASCIIStringEncoding]];
result = [[[NSString alloc] initWithData:[NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes] encoding:NSUTF8StringEncoding] autorelease];
}
else
{
NSData *myData = [NSData dataWithBytes:(const void *)bufferPtr length:(NSUInteger)movedBytes];
NSLog(#"This is my encrypted bytes %#", myData);
result = [NSString dataToHex:myData];
NSLog(#"This is my encrypted string %#", result);
NSLog(#"********************** Encryption is finished ************");
}
return result;
}
I didn't manage to match the 3DES encryption obtained with Java code and I don't understand which is the problem.
Thank you in advance,
Pier
The Java version is using an IV of 0s, while the Objective-C version uses 8s.
Deriving a key from a password using one round of MD5 and no salt is not secure. Use a key derivation algorithm like PBKDF2.
I haven't looked through all your code, but the first thing that jumps out is that the character encoding schemes for your input strings are different. In your Java algorithm you are encoding all strings as UTF-8, but in your ObjC algorithm you encoded the strings as ASCII, which is a potential problem for anything but the simplest of input strings.
It looks like you have a character encoding problem. Your Objective-C code is based on ASCII (8 bit) characters but you need to switch (16 bit) UNICODE character decoding while parsing Java Strings into bytes. On the other hand, It may be a good idea to consider byte ordering in your arrays depending on the CPU architecture you are working on (Little or Big Endianness).
I'm trying to encrypt data between my android application and a PHP webservice.
I found the next piece of code in this website: http://schneimi.wordpress.com/2008/11/25/aes-128bit-encryption-between-java-and-php/
But when I try to decrypt I get the Exception of the title "data not block size aligned"
This are the method in my MCrypt class
public String encrypt(String text) throws Exception
{
if(text == null || text.length() == 0)
throw new Exception("Empty string");
Cipher cipher;
byte[] encrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, keyspec, ivspec);
encrypted = cipher.doFinal(padString(text).getBytes());
} catch (Exception e)
{
throw new Exception("[encrypt] " + e.getMessage());
}
return new String( encrypted );
}
public String decrypt(String code) throws Exception
{
if(code == null || code.length() == 0)
throw new Exception("Empty string");
Cipher cipher;
byte[] decrypted = null;
try {
cipher = Cipher.getInstance("AES/CBC/NoPadding");
cipher.init(Cipher.DECRYPT_MODE, keyspec, ivspec);
decrypted = cipher.doFinal(hexToBytes(code));
} catch (Exception e)
{
throw new Exception("[decrypt] " + e.getMessage());
}
return new String( decrypted );
}
private static byte[] hexToBytes(String hex) {
String HEXINDEX = "0123456789abcdef";
int l = hex.length() / 2;
byte data[] = new byte[l];
int j = 0;
for (int i = 0; i < l; i++) {
char c = hex.charAt(j++);
int n, b;
n = HEXINDEX.indexOf(c);
b = (n & 0xf) << 4;
c = hex.charAt(j++);
n = HEXINDEX.indexOf(c);
b += (n & 0xf);
data[i] = (byte) b;
}
return data;
}
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;
}
And this is how I'm using it in my activity to test:
String encrypted = mcrypt.encrypt(jsonUser.toString());
String decrypted = mcrypt.decrypt(encrypted);
the encrypt method works fine, but the second throws an exception.
At last! I made it work! Thanks for all your suggestion. I would like to share the code just in case somebody get stuck like me:
JAVA
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";//Dummy iv (CHANGE IT!)
private IvParameterSpec ivspec;
private SecretKeySpec keyspec;
private Cipher cipher;
private String SecretKey = "0123456789abcdef";//Dummy secretKey (CHANGE IT!)
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));
} 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;
}
}
HOW TO USE IT (JAVA)
mcrypt = new MCrypt();
/* Encrypt */
String encrypted = MCrypt.bytesToHex( mcrypt.encrypt("Text to Encrypt") );
/* Decrypt */
String decrypted = new String( mcrypt.decrypt( encrypted ) );
====================================================
PHP
<?php
class MCrypt
{
private $iv = 'fedcba9876543210'; #Same as in JAVA
private $key = '0123456789abcdef'; #Same as in JAVA
function __construct()
{
}
function encrypt($str) {
//$key = $this->hex2bin($key);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$encrypted = mcrypt_generic($td, $str);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return bin2hex($encrypted);
}
function decrypt($code) {
//$key = $this->hex2bin($key);
$code = $this->hex2bin($code);
$iv = $this->iv;
$td = mcrypt_module_open('rijndael-128', '', 'cbc', $iv);
mcrypt_generic_init($td, $this->key, $iv);
$decrypted = mdecrypt_generic($td, $code);
mcrypt_generic_deinit($td);
mcrypt_module_close($td);
return utf8_encode(trim($decrypted));
}
protected function hex2bin($hexdata) {
$bindata = '';
for ($i = 0; $i < strlen($hexdata); $i += 2) {
$bindata .= chr(hexdec(substr($hexdata, $i, 2)));
}
return $bindata;
}
}
HOW TO USE IT (PHP)
<?php
$mcrypt = new MCrypt();
#Encrypt
$encrypted = $mcrypt->encrypt("Text to encrypt");
#Decrypt
$decrypted = $mcrypt->decrypt($encrypted);
I'm guessing your keyspec and ivspec are not valid for decryption. I've typically transformed them into PublicKey and PrivateKey instances and then use the private key to decrypt.
I looked at the comments in the other answer. I ran into a similar problem trying to encrypt a large block of text using open SSL in php (on both sides). I imagine the same issue would come up in Java.
If you have a 1024 bit RSA key, you must split the incoming text into 117 byte chunks (a char is a byte) and encrypt each (you can concatenate them together). On the other end, you must split the encrypted data into 128 byte chunks and decrypt each. This should give you your original message.
Also note that http may not play friendly with the non-ASCII encrypted data. I base64 encode/decode it before and after transmission (plus you have to worry about additional urlencoding for the base64 change, but it is easy).
I'm not sure of your AES key length, but if it's 1024 bits the chunk length is probably the same. If it's not, you will have to divide the bits by 8 to find the byte chunk length coming out. I'm actually not sure how to get it coming in, unfortunately (maybe multiply by 117/128 ?)
Here's some php code:
class Crypto {
public function encrypt($key, $data) {
$crypto = '';
foreach (str_split($data, 117) as $chunk) {
openssl_public_encrypt($chunk, $encrypted, $key);
$crypto .= $encrypted;
}
return $crypto;
}
//Decrypt omitted. Basically the same, change 117 to 128.
/**##+
* Update data for HTTP transmission and retrieval
* Must be used on encrypted data, but also useful for any binary data
* (e.g. zip files).
*/
public function base64_encode($value) {
return rtrim(strtr(base64_encode($value), '+/', '-_'), '=');
}
//String length must be padded for decoding for some reason
public function base64_decode($value) {
return base64_decode(str_pad(strtr($value, '-_', '+/')
, strlen($value) % 4, '=', STR_PAD_RIGHT));
}
/**##-*/
}