I'm trying to encrypt something, and decrypt it. I'm failing on the decryption - I get the exception above. I tried changing ctLength and ptLength, but to no avail. What am I doing wrong?
I'm trying to encrypt: 0 0 0 0 0 0 0 0
private Cipher encrypt(byte[] input)
{
try
{
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
// encryption pass
cipher.init(Cipher.ENCRYPT_MODE, key);
byte[] cipherText = new byte[cipher.getOutputSize(input.length)];
int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
FileOutputStream fs = new FileOutputStream(savedScoresFileName);
fs.write(cipherText);
return cipher;
}
catch (Exception e)
{
Log.e("encrtypt", "Exception", e);
}
return null;
}
private String decrypt()
{
try
{
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
byte[] cipherText = new byte[32];
FileInputStream fl = new FileInputStream(savedScoresFileName);
fl.read(cipherText);
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] plainText = new byte[cipher.getOutputSize(32)];
int ptLength = cipher.update(cipherText, 0, 32, plainText, 0);
ptLength += cipher.doFinal(plainText, ptLength);
return new String(plainText).substring(0, ptLength);
}
catch (Exception e)
{
Log.e("decrypt", "Exception", e);
}
return null;
}
This code was copied from this, which worked.
Your code has a number of issues, but your problem is caused by your file reading code and your strange method of performing the encryption and decryption.
Don't use the update() method, just use doFinal() and correct your file writing/reading code. E.g. your decryption method should look something like:
try {
Cipher cipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
SecretKeySpec key = new SecretKeySpec(keyBytes, "AES");
// Here you need to accurately and correctly read your file into a byte
// array. Either Google for a decent solution (there are many out there)
// or use an existing implementation, such as Apache Commons commons-io.
// Your existing effort is buggy and doesn't close its resources.
byte[] cipherText = FileUtils.readFileToByteArray(new File(savedScoresFileName));
cipher.init(Cipher.DECRYPT_MODE, key);
// Just one call to doFinal
byte[] plainText = cipher.doFinal(cipherText);
// Note: don't do this. If you create a string from a byte array,
// PLEASE pass a charset otherwise your result is platform dependent.
return new String(plainText);
} catch (Exception e) {
e.printStackTrace();
}
Related
Currently having issues with the decryption of an AES hash.
When i encrypt using AES256 i get the following result (After base64 encoding)
07sKQfb9dN86XAMxFmVKHQAAAAAAAAAAAAAAAAAAAAA=
I believe my issue is with the AAAAAAAA etc. for some reason I think anyway the padding isn't being removed during decryption.
My code
public String encrypt(String key, String initVector, String value) throws Exception {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"), 0, initVector.getBytes().length);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), 0, key.getBytes().length, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, iv);
byte[] encrypted = new byte[32];
cipher.doFinal(value.getBytes(), 0, value.getBytes().length, encrypted, 0);
System.out.println("Base64: " + Base64.encode(encrypted));
System.out.println("Hex: " + bytesToHex(encrypted));
return Base64.encode(encrypted);
}
public String decrypt(String key, String initVector, String encrypted) {
try {
IvParameterSpec iv = new IvParameterSpec(initVector.getBytes("UTF-8"), 0, initVector.getBytes().length);
SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes("UTF-8"), 0, key.getBytes().length, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PADDING");
cipher.init(Cipher.DECRYPT_MODE, skeySpec, iv);
byte[] decrypted = new byte[64];
cipher.doFinal(Base64.decode(encrypted), 0, Base64.decode(encrypted).length, decrypted, 0);
return new String(decrypted);
} catch (Exception ex) {
ex.printStackTrace();
}
return null;
}
What i am expecting when i encode base64 07sKQfb9dN86XAMxFmVKHQ=
String i am encrypting: Test
Secret key: password12345678password12345678
byte[] decrypted = new byte[64];
you created a 64 byte array but the decrypted value may be shorter (Java doesn't use zero string terminator unlike C does). So you should not make assumption over the parameter length
try using
encrypted = cipher.doFinal(value.getBytes());
and
decrypted = cipher.doFinal(Base64.decode(encrypted));
I am using AES/GCM/NoPadding encryption in java and (I am fairly new to it). If I understand it right GCM should recognize if encrypted message was manipulated, if so it should not decrypt it. As stated in this anwser:
The authentication TAG is an input to the decryption, if someone tampered with your associated data or with your encrypted data, GCM decryption will notice this and will not output any data (or return an error and you should discard the received data without processing it)
However, in my code, if I modify encrypted message (the message part or the tag part), I do not get any errors and the message will be decrypted (It will be different of course). I do not get any errors even when I provide different key, though message will be decrypted incorrectly...
What am I doing wrong? See the code below:
The util class:
public class CryptoUtils {
public static byte[] encrypt(byte[] key, byte[] iv, byte[] input) throws GeneralSecurityException {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
int outputLength = cipher.getOutputSize(input.length);
byte[] output = new byte[outputLength];
int outputOffset = cipher.update(input, 0, input.length, output, 0);
cipher.doFinal(output, outputOffset);
return output;
} catch (NoSuchAlgorithmException e) {
Timber.wtf(e);
}
return null;
}
public static byte[] decrypt(byte[] key, byte[] iv, byte[] encrypted) throws GeneralSecurityException {
try {
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
IvParameterSpec ivspec = new IvParameterSpec(iv);
Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivspec);
return cipher.doFinal(encrypted);
} catch (NoSuchAlgorithmException e) {
Timber.wtf(e);
}
return null;
}
}
The code that throws no errors:
byte[] key = getKey();
byte[] iv = generateIv();
byte[] message = "hello".getBytes();
byte[] encrypted = CryptoUtils.encrypt(key, iv, message);
//Split decrypted message into parts.
byte[] encryptedMessage = new byte[message.length];
System.arraycopy(encrypted, 0, encryptedMessage, 0, message.length);
byte[] tag = new byte[encrypted.length - message.length];
System.arraycopy(encrypted, message.length, tag, 0, tag.length);
//I am modifying the message here.
encryptedMessage[0] = 0;
// I am also modifying the key.
key[2] = 0;
//Put message and tag together.
byte[] toDecrypt = new byte[encrypted.length];
System.arraycopy(encryptedMessage, 0, toDecrypt, 0, encryptedMessage.length);
System.arraycopy(tag, 0, toDecrypt, encryptedMessage.length, tag.length);
//Still not getting any errors here.
byte[] decrypted = CryptoUtils.decrypt(key, iv, encryptedMessage);
byte[] decryptedMessage = new byte[message.length];
System.arraycopy(decrypted, 0, decryptedMessage, 0, message.length);
//Decrypted message is different than original.
Timber.d("Decrypted message: %s", new String(decryptedMessage));
I am working on a file encryption/decryption app. I am using a simple .txt file for testing. When I select the file from within the app and choose to encrypt, the entire file data is encrypted. However, when I decrypt only part of the file data gets decrypted. For some reason the first 16 bytes/characters doesn't get decrypted.
test_file.txt contents: "This sentence is used to check file encryption/decryption results."
encryption result: "¾mÁSTÐÿT:Y„"O¤]ÞPÕµß~ëqrÈb×ßq²¨†ldµJ,O|56\e^-’#þûÝû"
decryption result: "£ÿÒÜÑàh]VÄþ„- used to check file encryption/decryption results."
There aren't any errors in the logcat.
What am I doing wrong?
Method to encrypt file:
public void encryptFile(String password, String filePath) {
byte[] encryptedFileData = null;
byte[] fileData = null;
try {
fileData = readFile(filePath);//method provided below
// 64 bit salt for testing only
byte[] salt = "goodsalt".getBytes("UTF-8");
SecretKey key = generateKey(password.toCharArray(), salt);//method provided below
byte[] keyData = key.getEncoded();
SecretKeySpec sKeySpec = new SecretKeySpec(keyData, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, sKeySpec);
encryptedFileData = cipher.doFinal(fileData);
saveData(encryptedFileData, filePath);//method provided below
}
catch (Exception e) {
e.printStackTrace();
}
}
Method to read file content:
public byte[] readFile(String filePath) {
byte[] fileData;
File file = new File(filePath);
int size = (int) file.length();
fileData = new byte[size];
try {
BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file));
inputStream.read(fileData);
inputStream.close();
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
catch (IOException e) {
e.printStackTrace();
}
return fileData;
}
Method to generate secret key:
private SecretKey generateKey(char[] password, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
// Number of PBKDF2 hardening rounds to use. Larger values increase computation time. You
// should select a value that causes computation to take >100ms.
final int iterations = 1000;
// Generate a 256-bit key
final int outputKeyLength = 256;
SecretKeyFactory secretKeyFactory;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
// Use compatibility key factory -- only uses lower 8-bits of passphrase chars
secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1And8bit");
}
else {
// Traditional key factory. Will use lower 8-bits of passphrase chars on
// older Android versions (API level 18 and lower) and all available bits
// on KitKat and newer (API level 19 and higher).
secretKeyFactory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
}
KeySpec keySpec = new PBEKeySpec(password, salt, iterations, outputKeyLength);
return secretKeyFactory.generateSecret(keySpec);
}
Method to save encrypted/decrypted data to the file:
private void saveData(byte[] newFileData, String filePath) {
File file = new File(filePath);
try {
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
outputStream.write(newFileData);
outputStream.flush();
outputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
Method to decrypt file:
public void decryptFile(String password, String filePath) {
byte[] decryptedFileData = null;
byte[] fileData = null;
try {
fileData = readFile(filePath);
byte[] salt = "goodsalt".getBytes("UTF-8");//generateSalt();
SecretKey key = generateKey(password.toCharArray(), salt);
byte[] keyData = key.getEncoded();
SecretKeySpec sKeySpec = new SecretKeySpec(keyData, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, sKeySpec);
decryptedFileData = cipher.doFinal(fileData);
saveData(decryptedFileData, filePath);
}
catch (Exception e) {
e.printStackTrace();
}
}
This line of code encrypts the file:
//simple password for testing only
encryptor.encryptFile("password", "storage/emulated/0/Download/test_file.txt");
This line decrypts the file:
encryptor.decryptFile("password", "storage/emulated/0/Download/test_file.txt");
Edit: Thanks to DarkSquirrel42 and Oncaphillis. You guys are awesome!
Adding this line of code to both encrypt and decrypt functions solved my problem.
//note: the initialization vector (IV) must be 16 bytes in this case
//so, if a user password is being used to create it, measures must
//be taken to ensure proper IV length; random iv is best and should be
//stored, possibly alongside the encrypted data
IvParameterSpec ivSpec = new IvParameterSpec(password.getBytes("UTF-8"));
and then,
cipher.init(Cipher.XXXXXXX_MODE, sKeySpec, ivSpec);
your problem has something to do with the cipher's mode of operation ... cbc, or cipher block chaining mode
in general CBC is simple ... take whatever the output of your previous encryiption block was, and xor that onto the current input before encrypting it
for the first block we obviously have a problem... there is no previous block ... therefore we introduce something called IV ... an initialisation vector ... a block ength of random bytes ...
now ... as you can imagine, you will need the same IV when you want to decrypt ...
since you don't save that, the AES implementation will give you a random IV every time ...
therefore you don't have all information to decrypt block 1 ... which is the first 16 bytes in case of AES ...
when handling CBC mode data, it's allways a good choice to simply prepend the used IV in your cypertext output ... the IV shall just be random ... it is no secret ...
Like #ÐarkSquirrel42 already points out the en/decrytion routine for CBC seems to interpret the first 16 bytes as an initialisation vector. This worked for me:
// got to be random
byte[] iv = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.init(Cipher.XXXXX_MODE, sKeySpec,ivspec);
I have a password string in my android application. I need to the send the password through the .net web service (i.e. end with .aspx) using the SOAP web service. Before sending the password i need to encrypt the password with AES 128 encryption with the custom key and IV.
They have a encrypt/decrypt tool in .net with the custom key and Iv. The tool ask a custom key with 16 digit and IV 8 digit. If give the string it generate the encrypting string. example
Example:
Key : 1234567812345678
IV : 12345678
String : android
Encrypted string : oZu5E7GgZ83Z3yoK4y8Utg==
I didn't have any idea how to do this in android. Need help.
A complete example may help you:
The encrypt/decrypt functions, using IV
public static byte[] encrypt(byte[] data, byte[] key, byte[] ivs) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] finalIvs = new byte[16];
int len = ivs.length > 16 ? 16 : ivs.length;
System.arraycopy(ivs, 0, finalIvs, 0, len);
IvParameterSpec ivps = new IvParameterSpec(finalIvs);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public static byte[] decrypt(byte[] data, byte[] key, byte[] ivs) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] finalIvs = new byte[16];
int len = ivs.length > 16 ? 16 : ivs.length;
System.arraycopy(ivs, 0, finalIvs, 0, len);
IvParameterSpec ivps = new IvParameterSpec(finalIvs);
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
You can use it as below :
String dataToEncryptDecrypt = "android";
String encryptionDecryptionKey = "1234567812345678";
String ivs = "12345678";
byte[] encryptedData = encrypt(dataToEncryptDecrypt.getBytes(), encryptionDecryptionKey.getBytes(),
ivs.getBytes());
// here you will get the encrypted bytes. Now you can use Base64 encoding on these bytes, before sending to your web-service
byte[] decryptedData = decrypt(encryptedData, encryptionDecryptionKey.getBytes(), ivs.getBytes());
System.out.println(new String(decryptedData));
I don't know the details of AES algorithm in use(ie mode & padding method), bit it should be roughly like this:
public static byte[] encrypt(byte[] data, byte[] key) {
try {
Cipher cipher = Cipher.getInstance("AES/CBC/ZeroBytePadding");
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
byte[] empty = new byte[16]; // For better security you should use a random 16 byte key!!!
IvParameterSpec ivps = new IvParameterSpec(empty);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivps);
return cipher.doFinal(data);
} catch (Exception e) {
// ...
}
return null;
}
Function above could be used like this:
String data = "android";
String key = "1234567812345678";
byte encrypted = encrypt(data.getbytes("UTF-8"), key.getbytes("UTF-8"));
could someone give me any lead to this problem ?
I need to know how to encrypt and decrypt with AES with at least 128 bits with CFB and No Padding.
Some code or links will be very appreciated. (i already look on google, but no lucky tough).
UPDATE:
Works fine!
public byte[] crypt() {
byte[] crypt = null;
try {
final Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "SunJCE");
final SecretKey skeySpec = KeyGenerator.getInstance("AES").generateKey();
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
crypt = cipher.doFinal(new byte[]{0, 1, 2, 3});
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return crypt;
}
Returns null .. why ?
public String decrypt(byte[] text) {
byte[] crypt = null;
String plainText = null;
try {
final Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "SunJCE");
final SecretKey skeySpec = KeyGenerator.getInstance("AES").generateKey();
cipher.init(Cipher.DECRYPT_MODE, skeySpec);
crypt = cipher.doFinal(text);
plainText = new String(crypt);
} catch (Exception ex) {
throw new RuntimeException(ex);
}
return plainText;
}
Best regards,
Valter Henrique.
Give this a go:
final Cipher cipher = Cipher.getInstance("AES/CFB/NoPadding", "SunJCE");
final SecretKey skeySpec = KeyGenerator.getInstance("AES")
.generateKey();
cipher.init(Cipher.ENCRYPT_MODE, skeySpec);
System.out.println(Arrays.toString(cipher.doFinal(new byte[] { 0, 1, 2,
3 })));