Android javax.io.IOException: last block incomplete in decryption - java

I am trying to make a encryption and decryption app but in decryption method I got javax.crypto.IllegalBlockSizeException: last block incomplete in decryption
byte[] key = ("Sh").getBytes("UTF-8");
MessageDigest sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16);
secretKeySpec = new SecretKeySpec(key, "AES");
cipher = Cipher.getInstance("AES");
public void dec (String dir)
{
try{
cipher.init(Cipher.DECRYPT_MODE, secretKeySpec);
String cleartextFile = dir;
FileInputStream fis = new FileInputStream(cleartextFile);
CipherInputStream cis = new CipherInputStream(fis, cipher);
FileOutputStream fos = new FileOutputStream(dir);
block = new byte[6];
while ((i = cis.read(block)) != -1) {
fos.write(block, 0, i);
}
fos.close();
}
catch(Exception ex)
{
Toast.makeText(MainActivity.this, "Chiper Error"+ex, Toast.LENGTH_LONG).show();
}
}

Related

error:1e000065:Cipher functions:OPENSSL_internal:BAD_DECRYPT

I'm getting the following error when i tried to decrypt a list of ogg files but when i try to decrypt only one it works this is my code.
for (IpstoriResponse ipstori: descargas) {
Executors.newSingleThreadExecutor().execute(() -> {
ipstori.setAudioHistory(getOfflineFile(ipstori.getAudioPath(), ipstori.getAudioCle(), ipstori.getAudioIv(), requireContext(), ipstori.getAudioCle()));
prepareList.add(...);
});
}
}
private String getOfflineFile(String input, String key, String iv, Context context, String name){
String result = null;
try {
File initialFile = new File(input);
InputStream inputStream = new FileInputStream(initialFile);
File outputDir = context.getCacheDir(); // context being the Activity pointer
File outputFile = File.createTempFile(name, ".ogg", outputDir);
FileOutputStream fos = new FileOutputStream(outputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecretKey secretKey = makeKey(key);
IvParameterSpec ivParameterSpec = makeIv(iv);
cipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
CipherInputStream cipherInputStream = new CipherInputStream(inputStream, cipher);
byte[] buffer = new byte[8192];
int nread;
while ((nread = cipherInputStream.read(buffer)) > 0) {
fos.write(buffer, 0, nread);
}
fos.flush();
fos.close();
cipherInputStream.close();
result = outputFile.getPath();
tempFiles.add(result);
} catch (Exception ex) {
...
}
return result;
}
that's really weird cause when you try to decrypt only one element of the list the code works fine

Java Cipher Decryption on large files

I am trying to decrypt files by Java and below codes work. However it will have OutOfMemory exception when decrypting large files. I tried to change to cipher.update but the program will freeze without any responding.
How can I change this from doFinal to update?
public File decryptDataFile(File inputFile, File outputFile, File keyFile, String correlationId) {
try {
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] byteInput = this.getFileInBytes(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
byte[] salt = new byte[8];
System.arraycopy(byteInput, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
cipher.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100)));
byte[] data = cipher.doFinal(byteInput, 16, byteInput.length-16);
OutputStream os = new FileOutputStream(outputFile);
os.write(data);
os.close();
if(outputFile.exists()) {
return outputFile;
} else {
return null;
}
} catch (IOException | NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) {
logger.WriteLog(appConfig.getPlatform(), "INFO", alsConfig.getProjectCode(), correlationId, alsConfig.getFunctionId(), "SCAN_DECRYPT", e.getClass().getCanonicalName() + " - " + e.getMessage() );
return null;
}
}
My non-working version:
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] byteInput = this.getFileInBytes(inputFile);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
byte[] salt = new byte[8];
System.arraycopy(byteInput, 8, salt, 0, 8);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
cipher.init(Cipher.DECRYPT_MODE, fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100)));
FileInputStream fis = new FileInputStream(inputFile);
FileOutputStream fos = new FileOutputStream(outputFile);
CipherInputStream cis = new CipherInputStream(fis, cipher);
int b;
byte[] d = new byte[8];
while((b = cis.read(d)) != -1) {
fos.write(d, 0, b);
}
fos.flush();
fos.close();
cis.close();
if(outputFile.exists()) {
return outputFile;
} else {
return null;
}
Foreword: I couldn't decrypt with your original method a file that was encrypted with your openssl-command
openssl enc -aes-256-cbc -e -salt -in ${tarFile} -out ${encTarFile} -pass file:./${KEY_RANDOM}
but the following method should decode even large files similar to your original method - I tested files up to 1 GB size.
Edit: Regarding the OpenSSL statement, it's worth mentioning that since v1.1.0 the default digest has changed from MD5 to SHA256,
so for higher versions the -md MD5 option must be set explicitly for compatibility with the Java code. (thanks to #Topaco).
Please keep in mind that I don't care about correct file paths for
new FileInputStream(inputFile.toPath().toString())
and
new FileOutputStream(outputFile.toPath().toString())
as I'm working locally and with my folder, maybe you have to change the code to "find" your files. As well there is no exception handling in this example.
The code line
byte[] ibuf = new byte[8096];
is defining the buffer that is used - a larger buffer makes the decryption faster but consumes more memory (8096 means 8096 byte compared to 1 Gbyte when reading the complete file into memory and causing the out of memory error).
public static File decryptDataFileBuffered(File inputFile, File outputFile, File keyFile, String correlationId) throws IOException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, BadPaddingException, IllegalBlockSizeException, InvalidKeyException {
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] salt = new byte[8];
byte[] salted = new byte[8]; // text SALTED__
try (FileInputStream in = new FileInputStream(inputFile.toPath().toString()); // i don't care about the path as all is lokal
FileOutputStream out = new FileOutputStream(outputFile.toPath().toString())) // i don't care about the path as all is lokal
{
byte[] ibuf = new byte[8096]; // thats the buffer used - larger is faster
int len;
in.read(salted);
in.read(salt);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
SecretKey secretKey = fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100));
System.out.println("secretKey length: " + secretKey.getEncoded().length + " data: " + bytesToHex(secretKey.getEncoded()));
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secretKey);
while ((len = in.read(ibuf)) != -1) {
byte[] obuf = cipher.update(ibuf, 0, len);
if (obuf != null)
out.write(obuf);
}
byte[] obuf = cipher.doFinal();
if (obuf != null)
out.write(obuf);
} catch (IOException | BadPaddingException | IllegalBlockSizeException e) {
e.printStackTrace();
}
if (outputFile.exists()) {
return outputFile;
} else {
return null;
}
}
Edit2: As commented by #Topaco the usage of CipherInput/OutputStream shortens the code and makes it better readable, so here is the code:
public static File decryptDataFileBufferedCipherInputStream (File inputFile, File outputFile, File keyFile, String correlationId) throws
IOException, NoSuchPaddingException, NoSuchAlgorithmException, NoSuchProviderException, InvalidKeySpecException, InvalidKeyException
{
Security.addProvider(new BouncyCastleProvider());
String key = new String(Files.readAllBytes(keyFile.toPath())).trim();
byte[] salt = new byte[8];
byte[] salted = new byte[8]; // text SALTED__
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
try (FileInputStream in = new FileInputStream(inputFile.toPath().toString()); // i don't care about the path as all is lokal
CipherInputStream cipherInputStream = new CipherInputStream(in, cipher);
FileOutputStream out = new FileOutputStream(outputFile.toPath().toString())) // i don't care about the path as all is lokal
{
byte[] buffer = new byte[8192];
in.read(salted);
in.read(salt);
SecretKeyFactory fact = SecretKeyFactory.getInstance("PBEWITHMD5AND256BITAES-CBC-OPENSSL", "BC");
SecretKey secretKey = fact.generateSecret(new PBEKeySpec(key.toCharArray(), salt, 100));
System.out.println("secretKey length: " + secretKey.getEncoded().length + " data: " + bytesToHex(secretKey.getEncoded()));
cipher.init(Cipher.DECRYPT_MODE, secretKey);
int nread;
while ((nread = cipherInputStream.read(buffer)) > 0) {
out.write(buffer, 0, nread);
}
out.flush();
}
if (outputFile.exists()) {
return outputFile;
} else {
return null;
}
}

Java encryption won't decrypt on Android

Okay, so when I encrypt anything, lets say in this case a file, with my computer. It works fine encrypting and decrypting said file. However if encrypt the file with my computer then send it too my android and run the same decryption code I wrote it wont decrypt the file properly. It doesn't show any errors, however the file is clearly not decrypted properly.
So I've learned that Bouncy Castle is quite different than JVM/JDK standard encryption library, so I'm not 100% sure if that's the problem. However it would make sense. The issue is that if it is I don't know how to use the JVM/JDK library for encryption on my android. I don't want too use the Bouncy Castle library on my computer.
public static void encrypt(File source, File dest, String password){
try{
FileInputStream inFile = new FileInputStream(source.getPath());
FileOutputStream outFile = new FileOutputStream(dest.getPath());
byte[] salt = new byte[8], iv = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] input = new byte[64];
int bytesRead;
while((bytesRead = inFile.read(input)) != -1){
byte[] output = cipher.update(input, 0, bytesRead);
if(output != null){
outFile.write(output);
}
}
byte[] output = cipher.doFinal();
if(output != null){
outFile.write(output);
}
inFile.close();
outFile.flush();
outFile.close();
}catch(Exception e){
e.printStackTrace();
}
}
public static void decrypt(File source, File dest, String password){
try{
byte[] salt = new byte[8], iv = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
FileInputStream fis = new FileInputStream(source.getPath());
FileOutputStream fos = new FileOutputStream(dest.getPath());
byte[] in = new byte[64];
int read;
while((read = fis.read(in)) != -1){
byte[] output = cipher.update(in, 0, read);
if(output != null){
fos.write(output);
}
}
byte[] output = cipher.doFinal();
if(output != null){
fos.write(output);
}
fis.close();
fos.flush();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
The outcome would be too be able too encrypt any file with my computer using the standard JVM/JDK encryption library and being able too decrypt the same file with my android.
However if there is a different library other than Bouncy Castle that would work with android I'm open for ideas.
I've faced similar issue. First check if your encryption and decryption is setup properly.
If those are okay, then you should convert the encrypted text to Base64 or similar encoding.
Then decode the Base64 encoding first on the mobile and then decrypt the file.
The issue occurs because, some characters are not suitable for saving or transfering between mediums. They also gets affected by the underlying OS. Even if a bit is changed, your whole decrypted text will be changed, that might be the case here
ANDROID CODE
public static void decrypt(File source, File dest, String password){
try{
Base64InputStream fis = new Base64InputStream(new DataInputStream(new FileInputStream(source.getPath())), Base64.DEFAULT);
FileOutputStream fos = new FileOutputStream(dest.getPath());
byte[] salt = new byte[8], iv = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] in = new byte[64];
int read;
while((read = fis.read(in)) != -1){
byte[] output = cipher.update(in, 0, read);
if(output != null){
fos.write(output);
}
}
byte[] output = cipher.doFinal();
if(output != null){
fos.write(output);
}
fis.close();
fos.flush();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}
Regular JVM
public static void encrypt(File source, File dest, String password){
try{
FileInputStream inFile = new FileInputStream(source.getPath());
OutputStream outFile = Base64.getEncoder().wrap(new FileOutputStream(dest.getPath()));
byte[] salt = new byte[8], iv = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] input = new byte[64];
int bytesRead;
while((bytesRead = inFile.read(input)) != -1){
byte[] output = cipher.update(input, 0, bytesRead);
if(output != null){
outFile.write(output);
}
}
byte[] output = cipher.doFinal();
if(output != null){
outFile.write(output);
}
inFile.close();
outFile.flush();
outFile.close();
}catch(Exception e){
e.printStackTrace();
}
}
public static void decrypt(File source, File dest, String password){
try{
InputStream fis = Base64.getDecoder().wrap(new FileInputStream(source.getPath()));
//FileInputStream fis = new FileInputStream(source.getPath());
FileOutputStream fos = new FileOutputStream(dest.getPath());
byte[] salt = new byte[8], iv = new byte[16];
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 65536, 256);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
byte[] in = new byte[64];
int read;
while((read = fis.read(in)) != -1){
byte[] output = cipher.update(in, 0, read);
if(output != null){
fos.write(output);
}
}
byte[] output = cipher.doFinal();
if(output != null){
fos.write(output);
}
fis.close();
fos.flush();
fos.close();
}catch(Exception e){
e.printStackTrace();
}
}

Decrypt Video File and save to internal storage

I have an encrypted video with the key and I want to decrypt that video file with Key but I am not able to decrypt the video file. I try 2 3 methods but Non of these works for me.
Crypto.Class
public class Crypto {
static void fileProcessor(int cipherMode,String key,File inputFile,File outputFile){
try {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
SecureRandom secureRandom = new SecureRandom();
secureRandom.setSeed(key.getBytes("UTF-8"));
keyGenerator.init(128, secureRandom);
SecretKey secretKey = keyGenerator.generateKey();
// Key secretKey = new SecretKeySpec(key.getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES");
cipher.init(cipherMode, secretKey);
FileInputStream inputStream = null;
byte[] inputBytes = new byte[0];
try {
inputStream = new FileInputStream(inputFile);
inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
} catch (IOException e) {
e.printStackTrace();
}
byte[] outputBytes = cipher.doFinal(inputBytes);
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
} catch (NoSuchPaddingException | NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException e) {
e.printStackTrace();
}
}
public static String Decrypt(String filePath) {
String key = "my_encrypted_key";
// File inputFile = new File("text.txt");
File encryptedFile = new File(filePath);
String decryptedFilePath="";
//check special guid folder if not exist create
//get the selected video file path with settings path if exist decrypt if not exist show message
File decryptedFile = new File(decryptedFilePath);
try {
//Crypto.fileProcessor(Cipher.ENCRYPT_MODE,key,inputFile,encryptedFile);
Crypto.fileProcessor(Cipher.DECRYPT_MODE,key,encryptedFile,decryptedFile);
Log.d("success", "Decrypt: success");
return decryptedFile.getAbsolutePath();
} catch (Exception ex) {
System.out.println(ex.getMessage());
ex.printStackTrace();
}
return "";
}
}
But this does not work for me and I try another one.
public static void TEST2(String orgFile) {
try {
String password = "estudies741852963#123";
File outFile_dec = new File(Environment.getExternalStorageDirectory()+"/testVideo/abc.mp4");
if(!outFile_dec.isDirectory()) {
outFile_dec.mkdir();
}
if(!outFile_dec.exists()){
outFile_dec.createNewFile();
}
// reading the salt
// user should have secure mechanism to transfer the
// salt, iv and password to the recipient
FileInputStream saltFis = new FileInputStream(orgFile);
byte[] salt = new byte[8];
saltFis.read(salt);
saltFis.close();
// reading the iv
FileInputStream ivFis = new FileInputStream(orgFile);
byte[] iv = new byte[16];
ivFis.read(iv);
ivFis.close();
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(), salt, 1000,
256);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
// file decryption
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, new IvParameterSpec(iv));
InputStream fis = new FileInputStream(orgFile);
OutputStream fos = new FileOutputStream(outFile_dec);
// byte[] in = new byte[1024];
// int read;
// while ((read = fis.read(in)) != -1) {
// byte[] output = cipher.update(in, 0, read);
// if (output != null)
// fos.write(output);
// }
//
// byte[] output = cipher.doFinal();
// if (output != null)
// fos.write(output);
// fis.close();
// fos.flush();
// fos.close();
// System.out.println("File Decrypted.");
fos = new CipherOutputStream(fos, cipher);
int count = 0;
byte[] buffer = new byte[1024];
while ((count = fis.read(buffer)) >= 0) {
fos.write(buffer, 0, count);
}
fis.close();
fos.flush();
fos.close();
} catch (Exception e) {
e.printStackTrace();
}
}
In this method, its always shows on exception saying no such directory. And I try another method also But none of these works for me.
Tried this solution to decrypt my video
Java 256-bit AES Password-Based Encryption
How do i decrypt a file in Android with AES?

PBEWithHmacSHA256AndAES_128 ciphers but doesn't decipher

I'm able to cipher using PBEWithHmacSHA256AndAES_128 , but when i try to decipher it doesnt do anything, my encrypt code is:
PBEKeySpec keySpec = new PBEKeySpec(passwordServer.toCharArray());
SecretKeyFactory kf;
kf = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_128");
secretKey = kf.generateSecret(keySpec);
byte[] ivBytes = {0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,
0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20};
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
PBEParameterSpec spec = new PBEParameterSpec(salt, 20, ivSpec);
c = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
c.init(Cipher.ENCRYPT_MODE, secretKey, spec);
params = c.getParameters();
and my decrypt code is the following:
Cipher c = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
c.init(Cipher.DECRYPT_MODE, secretKey, params);
FileInputStream fis = new FileInputStream("repositorios/login.cif");
FileOutputStream fos = new FileOutputStream("repositorios/login2.txt");
CipherOutputStream cos = new CipherOutputStream(fos, c);
byte[] b = new byte[16];
int i = fis.read(b);
while (i != -1) {
cos.write(b, 0, i);
i = fis.read(b);
}
cos.close();
fis.close();
After i run the code, the file "login2.txt" is empty.
Am I doing something wrong while using this algorithm?
Thank you!
EDIT:
1. where i store the salt:
BufferedWriter out = new BufferedWriter
(new FileWriter("repositorios/salt.txt",true));
BufferedReader in=new BufferedReader
(new FileReader("repositorios/salt.txt"));
byte[]salt;
String l = in.readLine();
if(l != null){
salt = l.getBytes();
} else {
salt = new byte[16];
RANDOM.nextBytes(salt);
out.write(new String (salt, "UTF-8"));
}
my chiper code:
FileOutputStream fos = new FileOutputStream("repositorios/login.cif");
CipherOutputStream cos = new CipherOutputStream(fos, c);
out = new BufferedWriter(new FileWriter("repositorios/login.txt",true));
String aEncriptar = user + ":" + passwd +"\n";
byte[] b= aEncriptar.getBytes();
cos.write(b, 0, b.length);
cos.close();

Categories

Resources