AES decryption is always null - java

I tried using salt to decrypt a AES encrypted message but it always returns null value. Can anyone look at it where am i doing wrong?
public static String decryptMessage(String encryptedMessage, String salt) {
String decryptedMessage = null;
String valueToDecrypt = encryptedMessage;
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
for (int i = 0; i < ITERATIONS; i++) {
byte[] decodedValue = Base64.decodeBase64(valueToDecrypt);
byte[] decVal = c.doFinal(decodedValue);
decryptedMessage = new String(decVal).substring(salt.length());
valueToDecrypt = decryptedMessage;
}
} catch (Exception e) {
e.printStackTrace();
}
return decryptedMessage;
}
**EDIT:**
Here is corresponding encryption method which i assume, works.
private static final String ALGORITHM = "AES";
private static final int ITERATIONS = 5;
private static final byte[] keyValue = new byte[] { '1', '2', '3', '4',
'5', '6', '7', '8', '9', '0', '1', '2', '3', '4', '5', '6' };
public static String encryptMessage(String message, String salt) {
String encMessage = null;
byte[] encVal = null;
String messageWithSalt = null;
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
for (int i = 0; i < ITERATIONS; i++) {
messageWithSalt = salt + encMessage;
encVal = c.doFinal(messageWithSalt.getBytes());
byte[] encryptedValue = new Base64().encode(encVal);
encMessage = new String(encryptedValue);
}
} catch (Exception e) {
e.printStackTrace();
}
return encMessage;
}
PS: ITERATION is NOT 0;

I think your method might be chronically broken or misnamed. You are generating a key each time you decrypt, whereas you should have a pre-existing key that matches the one used for encryption.
You also pass in a "salt" value - note: this is a term normally reserved for hashing - which you then completely ignore, except to use the size as a truncation length on your result.
Certainly what I see above is not decrypting anything in a sensible fashion. If you can describe exactly what you wanted to achieve, we can possibly correct the code or point you at the peer-reviewed method for performing that task (which may already be implemented in the standard libs).

Well, i found the error. It was in the encryption method. encMessage was null before the encryption process begins. String encMessage = message did the trick. So the encryption method is:
public static String encryptMessage(String message, String salt) {
String encMessage = message;
byte[] encVal = null;
String messageWithSalt = null;
try {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
for (int i = 0; i < ITERATIONS; i++) {
messageWithSalt = salt + encMessage;
encVal = c.doFinal(messageWithSalt.getBytes());
byte[] encryptedValue = new Base64().encode(encVal);
encMessage = new String(encryptedValue);
}
} catch (Exception e) {
e.printStackTrace();
}
return encMessage;
}

Related

Limit Size of Encrypted Data using 3DES

I am trying to encrypt and decrypt a string of data using 3DES and it is working fine. However I want that the size of the data after encryption to be limited to length of 16 bits.
This is the code I am referring from https://gist.github.com/riversun/6e15306cd6e3b1b37687a0e5cec1cef1 :
import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class DesedeCrypter {
private static final String CRYPT_ALGORITHM = "DESede";
private static final String PADDING = "DESede/CBC/NoPadding";
private static final String CHAR_ENCODING = "UTF-8";
private static final byte[] MY_KEY = "5oquil2oo2vb63e8ionujny6".getBytes();//24-byte
private static final byte[] MY_IV = "3oco1v52".getBytes();//8-byte
public static void main(String[] args) {
String srcText = "M3A1B2C3D4HHG393";
final DesedeCrypter crypter = new DesedeCrypter();
String encryptedText = crypter.encrypt(srcText);
System.out.println("sourceText=" + srcText + " -> encryptedText=" + encryptedText + "\n");
System.out.println("encrypted-text=" + encryptedText + " -> decrypted-text(source text)="
+ crypter.decrypt(encryptedText));
}
public String encrypt(String text) {
String retVal = null;
try {
final SecretKeySpec secretKeySpec = new SecretKeySpec(MY_KEY, CRYPT_ALGORITHM);
final IvParameterSpec iv = new IvParameterSpec(MY_IV);
final Cipher cipher = Cipher.getInstance(PADDING);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, iv);
final byte[] encrypted = cipher.doFinal(text.getBytes(CHAR_ENCODING));
retVal = new String(encodeHex(encrypted));
} catch (Exception e) {
e.printStackTrace();
}
return retVal;
}
public String decrypt(String text) {
String retVal = null;
try {
final SecretKeySpec secretKeySpec = new SecretKeySpec(MY_KEY, CRYPT_ALGORITHM);
final IvParameterSpec iv = new IvParameterSpec(MY_IV);
final Cipher cipher = Cipher.getInstance(PADDING);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, iv);
final byte[] decrypted = cipher.doFinal(decodeHex(text.toCharArray()));
retVal = new String(decrypted, CHAR_ENCODING);
} catch (Exception e) {
e.printStackTrace();
}
return retVal;
}
private byte[] decodeHex(char[] data) throws Exception {
int len = data.length;
if ((len & 0x01) != 0) {
throw new Exception("Odd number of characters.");
}
byte[] out = new byte[len >> 1];
// two characters form the hex value.
for (int i = 0, j = 0; j < len; i++) {
int f = toDigit(data[j], j) << 4;
j++;
f = f | toDigit(data[j], j);
j++;
out[i] = (byte) (f & 0xFF);
}
return out;
}
private int toDigit(char ch, int index) throws Exception {
int digit = Character.digit(ch, 16);
if (digit == -1) {
throw new Exception("Illegal hexadecimal character " + ch + " at index " + index);
}
return digit;
}
private char[] encodeHex(byte[] data) {
final char[] DIGITS = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
int l = data.length;
char[] out = new char[l << 1];
// two characters form the hex value.
for (int i = 0, j = 0; i < l; i++) {
out[j++] = DIGITS[(0xF0 & data[i]) >>> 4];
out[j++] = DIGITS[0x0F & data[i]];
}
return out;
}
}
Currently this is the output I am getting:
sourceText=M3A1B2C3D4HHG393 -> encryptedText=afc1d48ea5cc703253cbc1a88a198103
encrypted-text=afc1d48ea5cc703253cbc1a88a198103 -> decrypted-text(source text)=M3A1B2C3D4HHG393
Is there any way that the size of the encryptedText be limited to 16 as I want to add the encrypted text back into a message which has 16 digits space for encrypted text.
Please suggest some way or any other change that is required to achieve this. Thanks !
For one, I highly recommend not supporting (3)DES anymore, as it's officially unsecure in favour of AES/ChaCha, which I must say before answering this question.
3DES has a block size of 64 bits (or 8 bytes). With that also comes that encryption ≠ compression. So if you want to encrypt 16 bytes, provide 16 bytes of input, unless:
You apply a padding scheme (which it appears you're not doing)(taken from the DESede/CBC/NoPadding
You apply a (random) initialisation vector (which it appears you're doing)
The latter one should, but I'm not to sure of Android's implementation, create a 64 bits (8 byte) iv, as the iv should be as big as the block size of the cipher (again, 64 bits for 3DES).
So if you want 16 bytes of output, you can, and should, only provide 8 bytes to encrypt. Now, if 8 bytes is not enough, you might choose to drop the iv from being in the ciphertext, which you could do if you use a fixed iv (such as an all zero iv) with random keys, as reusing the same key with iv is not secure.
Now if you do take security in consideration, keep in mind that AES has a block size of 16 bytes. AES and ChaCha come with the same constraints regarding the iv.
Then you might also might want to consider changing the message (protocol) instead, so it can take more than 16 bytes of data or use those 16 bytes in such a way that it indicates that there is more data to handle, as like an attachment to an e-mail.

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;
}

What is the required size of an AES key in this code?

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).

Stringindexoutofboundsexception while decrypting using AES

I am using AES as an encryption technique. While decrypting my encrypted string I am facing this StringIndexOutOfBoundsException String index out of range : -3. Can you tell me why am I facing this? is it related BASE64 encoding that I used?
Code for decryption:
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.DECRYPT_MODE, key);
String salt = "some salt";
String dValue = null;
String valueToDecrypt = encryptedData;
for (int i = 0; i < 2; i++) {
byte[] decordedValue = Base64.decodeBase64(valueToDecrypt);
byte[] decValue = c.doFinal(decordedValue);
dValue = new String(decValue).substring(salt.length());
valueToDecrypt = dValue;
}
Code for Encryption :
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGO);
c.init(Cipher.ENCRYPT_MODE, key);
String salt = "some salt";
String valueToEnc = null;
String eValue = Data;
for (int i = 0; i < 2; i++) {
valueToEnc = salt + eValue;
byte[] encValue = c.doFinal(valueToEnc.getBytes(UNICODE_FORMAT));
eValue =new String(Base64.encodeBase64(encValue));
}
Reference : http://www.digizol.com/2009/10/java-encrypt-decrypt-jce-salt.html

Categories

Resources