I want to encrypt / decrypt files ( of reasonable size ). I have my code working corrects using AES/CBC/PKCS5Padding . The problem is that it takes really long time to encrypt big files. SO now I am planning to use openSSL.
Is there a link that explains how to use openssl from a java app? How can I integrate it to my java app?
Thanks a lot for any links / points in this regard.
Thanks for your help and time
My code using BC:
public class BouncyCastleProvider_AES_CBC {
public Cipher encryptcipher, decryptCipher;
String TAG = "DataEncryptDecrypt";
private static final String RANDOM_ALGORITHM = "SHA1PRNG";
// The default block size
public static int blockSize = 16;
// Buffer used to transport the bytes from one stream to another
byte[] buf = new byte[blockSize]; //input buffer
byte[] obuf = new byte[512]; //output buffer
// The key
byte[] key = null;
// The initialization vector needed by the CBC mode
byte[] IV = null;
public BouncyCastleProvider_AES_CBC(String passwd){
//for a 192 key you must install the unrestricted policy files
// from the JCE/JDK downloads page
key =passwd.getBytes();
key = "SECRETSECRET_1SE".getBytes();
Log.i( "SECRETSECRET_1SECRET_2", "length"+ key.length);
//default IV value initialized with 0
IV = new byte[blockSize];
InitCiphers();
}
public BouncyCastleProvider_AES_CBC(String pass, byte[] iv){
//get the key and the IV
IV = new byte[blockSize];
System.arraycopy(iv, 0 , IV, 0, iv.length);
}
public BouncyCastleProvider_AES_CBC(byte[] pass, byte[]iv){
//get the key and the IV
key = new byte[pass.length];
System.arraycopy(pass, 0 , key, 0, pass.length);
IV = new byte[blockSize];
System.arraycopy(iv, 0 , IV, 0, iv.length);
}
public void InitCiphers()
{
try {
//1. create the cipher using Bouncy Castle Provider
encryptcipher =
Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
//2. create the key
SecretKey keyValue = new SecretKeySpec(key,"AES");
//3. create the IV
AlgorithmParameterSpec IVspec = new IvParameterSpec(IV);
//4. init the cipher
encryptcipher.init(Cipher.ENCRYPT_MODE, keyValue, IVspec);
encryptcipher.getOutputSize(100);
//1 create the cipher
decryptCipher =
Cipher.getInstance("AES/CBC/PKCS5Padding", "BC");
//2. the key is already created
//3. the IV is already created
//4. init the cipher
decryptCipher.init(Cipher.DECRYPT_MODE, keyValue, IVspec);
}
catch(Exception ex) {
ex.printStackTrace();
}
}
public String encryptData(String inputFileName) {
String outFilename = null;
File inputFile = new File(inputFileName);
try {
// step 3 - not needed, as we have all the blocks on hand
// step 4 - call doFinal()
outFilename = ".".concat(CommonUtils.getHash(inputFile.getName()));
InputStream fis;
OutputStream fos;
fis = new BufferedInputStream(new FileInputStream(inputFileName));
fos = new BufferedOutputStream(new FileOutputStream(
inputFile.getParent() + "/" + outFilename));
Log.i(TAG, "Output path:" + inputFile.getParent() + "/" + outFilename);
int bufferLength = (inputFile.length()>10000000?10000000:1000);
byte[] buffer = new byte[bufferLength];
int noBytes = 0;
byte[] cipherBlock = new byte[encryptcipher
.getOutputSize(buffer.length)];
int cipherBytes;
while ((noBytes = fis.read(buffer)) != -1) {
cipherBytes = encryptcipher.update(buffer, 0, noBytes,
cipherBlock);
fos.write(cipherBlock, 0, cipherBytes);
}
// always call doFinal
cipherBytes = encryptcipher.doFinal(cipherBlock, 0);
fos.write(cipherBlock, 0, cipherBytes);
// close the files
fos.close();
fis.close();
Log.i("encrpty", "done");
inputFile.delete();
}
catch (Exception ex) {
ex.printStackTrace();
}
return inputFile.getParent() + "/" + outFilename;
}
public void decryptData(String inputFileName, String outputFileName) {
InputStream fis;
OutputStream fos;
try {
fis = new BufferedInputStream(new FileInputStream(
inputFileName));
fos = new BufferedOutputStream(new FileOutputStream(
outputFileName));
byte[] buffer = new byte[blockSize*100];
int noBytes = 0;
byte[] cipherBlock = new byte[decryptCipher
.getOutputSize(buffer.length)];
int cipherBytes;
while ((noBytes = fis.read(buffer)) != -1) {
cipherBytes = decryptCipher.update(buffer, 0, noBytes,
cipherBlock);
fos.write(cipherBlock, 0, cipherBytes);
}
// allways call doFinal
cipherBytes = decryptCipher.doFinal(cipherBlock, 0);
fos.write(cipherBlock, 0, cipherBytes);
// close the files
fos.close();
fis.close();
new File(inputFileName).delete();
Log.i("decrypt", "done");
} catch (Exception ex) {
ex.printStackTrace();
}
}
public byte[] generateSalt() {
byte[] salt = new byte[16];
try {
SecureRandom random = SecureRandom.getInstance(RANDOM_ALGORITHM);
random.nextBytes(salt);
}
catch(Exception ex) {
ex.printStackTrace();
}
return salt;
}
}
The Guardian Project has build files for Android. Once you build it, you need write a simple JNI wrapper that does the encryption/decryption using OpenSSL APIs (EVP, etc), then call this from your app. You need to include he openssl and your JNI wrapper in the app and load them on startup using System.loadLibrary().
https://github.com/guardianproject/openssl-android
Additionally:
don't derive a password from a string directly, use a proper derivation algorithm.
don't use a fixed IV, especially all zeros
Related
I am trying to get File Decryption working in Android. The file i have has been encrypted from python using Crypto.Cipher AES: full code:
import os, binascii, struct
from Crypto.Cipher import AES
def encrypt_file():
chunksize=64*1024
iv = "96889af65c391c69"
k1 = "cb3a44cf3cb120cc7b8b3ab777f2d912"
file = "tick.png"
out_filename = "entick.png"
dir = os.path.dirname(__file__)+"\\"
print(iv)
encryptor = AES.new(key, AES.MODE_CBC, iv)
in_filename = dir+file
filesize = os.path.getsize(in_filename)
with open(in_filename, 'rb') as infile:
with open(out_filename, 'wb') as outfile:
outfile.write(struct.pack('<Q', filesize))
outfile.write(iv)
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += ' ' * (16 - len(chunk) % 16)
outfile.write(encryptor.encrypt(chunk))
if __name__ == "__main__":
encrypt_file()
Android Decryption function (main):
private static File main(String fname, File enfile, String IV, String key) {
try {
byte[] bkey = key.getBytes("UTF-8");
byte[] bIV = IV.getBytes("UTF-8");
Log.d("ByteLen","bkey:"+Integer.toString(bkey.length));
Log.d("ByteLen","bIV:"+ Integer.toString(bIV.length));
File aesFile;
aesFile = enfile;
Log.d("AESFILELENGTH", "aes length: " + aesFile.length());
File aesFileBis = new File(String.valueOf(Environment.getExternalStorageDirectory().toPath()), "tick.png"); //to be replaced with fname
FileInputStream fis;
FileOutputStream fos;
CipherInputStream cis;
SecretKeySpec secretKey = new SecretKeySpec(bkey, "AES");
Cipher decrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(bIV);
decrypt.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
fis = new FileInputStream(aesFile);
cis = new CipherInputStream(fis, decrypt);
fos = new FileOutputStream(aesFileBis);
try {
byte[] mByte = new byte[8];
int i = cis.read(mByte);
Log.i("MBYTE", "mbyte i: " + i);
while (i != -1) {
fos.write(mByte, 0, i);
i = cis.read(mByte);
}
} catch (IOException e) {
e.printStackTrace();
}
fos.flush();
fos.close();
cis.close();
fis.close();
return aesFileBis;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
The Crypto.Cipher module inserts the IV into the file as bytes 8-24 so i created this method to extract them:
private String IV(File enfile) throws UnsupportedEncodingException, FileNotFoundException {
int size = 24;
byte bytes[] = new byte[size];
byte tmpBuff[] = new byte[size];
if(enfile.canRead()){
//run decryption code
FileInputStream fis= new FileInputStream(enfile);
try {
int read = fis.read(bytes, 0, size);
if (read < size) {
int remain = size - read;
while (remain > 0) {
read = fis.read(tmpBuff, 0, remain);
System.arraycopy(tmpBuff, 0, bytes, size - remain, read);
remain -= read;
}
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
String IV = new String(bytes, "US-ASCII");
IV = IV.substring(8,24);
return IV;
}
From the Decrypt function i have checked and verified the key is 32 bytes long and the iv is 16 bytes long and both are the correct IV and Key. I know I am switching from a byte array to string and back again but that's just for testing.
I have looked at a few posts regarding this issue and so far have only found posts relating to the key being the wrong byte size or for decrpyting Strings and not files and therefor switching base64 encoding doesn't seem to apply. I think the issue is to do with the way Crypto.Cipher is padding the files as the first 8 byes look like junk (SO and NULL bytes) then there are 16 bytes of IV.
Thanks to the comment i added the Padding module from crypto: https://github.com/dlitz/pycrypto/blob/master/lib/Crypto/Util/Padding.py
im my python code i added:
from Crypto.Util.py3compat import * #solves bchr error
i also copied the pad() function from the Padding.py to the end of my code.
in the file writing function:
with open(in_filename, 'rb') as infile:
with open(out_filename, 'wb') as outfile:
outfile.write(iv) ##IV becomes the first 16 bytes, not using struct.pack() anymore
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
elif len(chunk) % 16 != 0:
chunk += ' ' * (16 - len(chunk) % 16)
outfile.write(encryptor.encrypt(pad(chunk, 16))) ##added padding here
Finally in the Java code i removed the IV finder function and updated the main function:
private static File main(String fname, File enfile, String key) {
try {
FileInputStream fis;
File aesFile;
aesFile = enfile;
byte[] bkey = key.getBytes("UTF-8");
fis = new FileInputStream(aesFile);
byte[] IV = new byte[16];
for(Integer i =0; i < 16; i++){
IV[i] = (byte) fis.read();
}
Log.e("IV:",""+new String(IV, "US-ASCII"));
Log.d("ByteLen","bkey:"+Integer.toString(bkey.length));
Log.d("ByteLen","bIV:"+ Integer.toString(IV.length));
aesFile = enfile;
Log.d("AESFILELENGTH", "aes length: " + aesFile.length());
File aesFileBis = new File(String.valueOf(Environment.getExternalStorageDirectory().toPath()), "file.png"); //to be replaced with fname
FileOutputStream fos;
CipherInputStream cis;
SecretKeySpec secretKey = new SecretKeySpec(bkey, "AES");
Cipher decrypt = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivSpec = new IvParameterSpec(IV);
decrypt.init(Cipher.DECRYPT_MODE, secretKey, ivSpec);
cis = new CipherInputStream(fis, decrypt);
fos = new FileOutputStream(aesFileBis);
try {
byte[] mByte = new byte[8];
int i = cis.read(mByte);
Log.i("MBYTE", "mbyte i: " + i);
while (i != -1) {
fos.write(mByte, 0, i);
i = cis.read(mByte);
}
} catch (IOException e) { e.printStackTrace();}
fos.flush();
fos.close();
cis.close();
fis.close();
return aesFileBis;
}catch(Exception e) {e.printStackTrace(); }
return null;
}
The new parts of the code take the first 16 bytes from the FileInputStream and puts them into a byte array to be used as the IV, the rest are then decrypted using CBC/PKCS5Padding.
Hope this answer can be useful for anyone else.
I am encrypting my videos using this link and store it in my application folder. But for large videos say, 2GB, it takes much time to decrypt and then play. so user has to wait for 1.5-2 minutes to decrypt selected video and then play it.
For that, I searched for offline video streaming. And I found this. I have same scenario but instead of downloading, I am encrypting videos from gallery. and I have used different encryption alogithm.
When I tried above link, my connection is lost everytime it goes in while loop. In catch, I get Connection is reset error. Also I didn't get some variables there. like, total, readbyte and pos variables. can anybody please explain?
I really want to decrypt and play videos at the same time. so user experience will be good.
Thank you.
EDIT
Here is my sample code :
using Android.App;
using Android.Widget;
using Android.OS;
using Android.Support.V7.App;
using Java.IO;
using Javax.Crypto;
using Javax.Crypto.Spec;
using System;
using System.IO;
using Java.Net;
using System.Threading.Tasks;
namespace SecretCalc
{
[Activity(Label = "#string/app_name", Theme = "#style/AppTheme",
MainLauncher = true)]
public class MainActivity : AppCompatActivity
{
VideoView video;
Button encrypt, decrypt;
private string sKey = "0123456789abcdef";//key,
private string ivParameter = "1020304050607080";
string path = "/sdcard/Download/";
string destpath = "/sdcard/test/";
string filename = "video1.mp4";
Stream outputStream;
string date = "20180922153533.mp4"; // Already Encrypted File Name
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.activity_main);
video = FindViewById<VideoView>(Resource.Id.videoView);
encrypt = FindViewById<Button>(Resource.Id.btnEncrypt);
decrypt = FindViewById<Button>(Resource.Id.btnDecrypt);
encrypt.Click += Encrypt_Click;
decrypt.Click += Decrypt_ClickAsync;
}
private async void Decrypt_ClickAsync(object sender, EventArgs e)
{
video.SetVideoPath("http://0.0.0.0:9990/");
video.Prepared += Video_Prepared;
await Task.Run(() =>
{
try
{
ServerSocket serverSocket = new ServerSocket();
serverSocket.Bind(new InetSocketAddress("0.0.0.0", 9990));
// this is a blocking call, control will be blocked until client sends the request
Socket finalAccept = serverSocket.Accept();
outputStream = finalAccept.OutputStream;
}
catch (Exception ex)
{
}
});
await Task.Run(() => DecryptThroughSocket());
}
private void Video_Prepared(object sender, EventArgs e)
{
video.Start();
}
private bool DecryptThroughSocket()
{
try
{
byte[] raw = System.Text.Encoding.Default.GetBytes(sKey);
byte[] iv = System.Text.Encoding.Default.GetBytes(ivParameter);
int count = 0, pos = 0, total = 0, readbyte;
byte[] data = new byte[1024 * 1024];
readbyte = data.Length;
long lenghtOfFile = new Java.IO.File(Path.Combine(path, date)).Length();
FileInputStream inputStream = new FileInputStream(Path.Combine(destpath, date));
while ((count = inputStream.Read(data, 0, readbyte)) != -1)
{
if (count < readbyte)
{
if ((lenghtOfFile - total) > readbyte)
{
while (true)
{
int seccount = inputStream.Read(data, pos, (readbyte - pos));
pos = pos + seccount;
if (pos == readbyte)
{
break;
}
}
}
}
// encrypt data read before writing to output stream
byte[] decryptedData = decryptFun(raw, iv, data);
outputStream.Write(decryptedData,0,decryptedData.Length);
}
}
catch (Exception ex)
{
return false;
}
return true;
}
private void Encrypt_Click(object sender, EventArgs e)
{
try
{
FileInputStream inputStream = new FileInputStream(System.IO.Path.Combine(path, filename));
date = DateTime.Now.ToString("yyyyMMddHHmmss") + ".mp4";
DirectoryInfo dir = new DirectoryInfo(destpath);
if (!dir.Exists)
{
Directory.CreateDirectory(destpath);
}
FileOutputStream outputStream = new FileOutputStream(System.IO.Path.Combine(destpath, date));
byte[] raw = System.Text.Encoding.Default.GetBytes(sKey);
byte[] iv = System.Text.Encoding.Default.GetBytes(ivParameter);
int count = 0, pos = 0, total = 0, readbyte;
byte[] data = new byte[1024 * 1024];
readbyte = data.Length;
long lenghtOfFile = new Java.IO.File(Path.Combine(path, filename)).Length();
while ((count = inputStream.Read(data, 0, readbyte)) != -1)
{
if (count < readbyte)
{
if ((lenghtOfFile - total) > readbyte)
{
while (true)
{
int seccount = inputStream.Read(data, pos, (readbyte - pos));
pos = pos + seccount;
if (pos == readbyte)
{
break;
}
}
}
}
total += count;
// encrypt data read before writing to output stream
byte[] encryptedData = encryptFun(raw, iv, data);
outputStream.Write(encryptedData);
}
}
catch (Exception ex)
{
}
}
public static byte[] encryptFun(byte[] key, byte[] iv, byte[] clear)
{
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.GetInstance("AES/CTR/NoPadding");
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.Init(CipherMode.EncryptMode, skeySpec, ivspec);
byte[] encrypted = cipher.DoFinal(clear);
return encrypted;
}
public static byte[] decryptFun(byte[] key, byte[] iv, byte[] encrypted)
{
SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
Cipher cipher = Cipher.GetInstance("AES/CTR/NoPadding");
IvParameterSpec ivspec = new IvParameterSpec(iv);
cipher.Init(CipherMode.DecryptMode, skeySpec, ivspec);
byte[] decrypted = cipher.DoFinal(encrypted);
return decrypted;
}
}
}
I tried to encrypt plaintext using the below code. The code seems encrypt the text but it doesnt decrypt to plaintext back. What am I doing wrong ?
The code:
Entity entity = new Entity("password");
byte[] ciphertext = crypto.encrypt(("data to encrypt").getBytes(),entity);
plaintext = crypto.decrypt(ciphertext,entity)
Output:
Ecrypted text:[B#417a110
Decrypted text:[B#417df20
The following code can encrypt/decrypt string
KeyChain keyChain = new SharedPrefsBackedKeyChain(context, CryptoConfig.KEY_256);
crypto = AndroidConceal.get().createDefaultCrypto(keyChain);
public static String encrypt(String key, String value) throws KeyChainException, CryptoInitializationException, IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
OutputStream cryptoStream = crypto.getCipherOutputStream(bout, Entity.create(key));
cryptoStream.write(value.getBytes("UTF-8"));
cryptoStream.close();
String result = Base64.encodeToString(bout.toByteArray(), Base64.DEFAULT);
bout.close();
return result;
}
public static String decrypt(String key, String value) throws KeyChainException, CryptoInitializationException, IOException {
ByteArrayInputStream bin = new ByteArrayInputStream(Base64.decode(value, Base64.DEFAULT));
InputStream cryptoStream = crypto.getCipherInputStream(bin, Entity.create(key));
ByteArrayOutputStream bout = new ByteArrayOutputStream();
int read = 0;
byte[] buffer = new byte[1024];
while ((read = cryptoStream.read(buffer)) != -1) {
bout.write(buffer, 0, read);
}
cryptoStream.close();
String result = new String(bout.toByteArray(), "UTF-8");
bin.close();
bout.close();
return result;
}
I have found the answer.
The reason is we were printing the byte array instead of the String.
The array is going to comprise of a set of bytes so that's what we saw when we printed them out in the logcat.
To see the actual String, we just need to put the byte[] into a new String(byte[]) - this is taken from the official facebook examples with my modifications:
Crypto crypto = new Crypto(
new SharedPrefsBackedKeyChain(getActivity()),
new SystemNativeCryptoLibrary());
if (!crypto.isAvailable()) {
Log.e("Crypto","Crypto is missing");
}
String password = "Password";
Entity entity = new Entity("TEST");
byte[] encryptedPass = new byte[0];
byte[] b = password.getBytes(Charset.forName("UTF-8"));
try {
encryptedPass = crypto.encrypt(b, entity);
Log.e("Crypto Encrypted", new String(encryptedPass));
byte[] decryptedPass = crypto.decrypt(encryptedPass, entity);
Log.e("Crypto Decrypted ", new String(decryptedPass));
} catch (KeyChainException e) {
e.printStackTrace();
} catch (CryptoInitializationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Results:
08-02 19:31:11.237 29364-29364/? E/Crypto Encrypted﹕
0��&�?B�6���H���`��"�1��xx� 08-02 19:31:11.237 29364-29364/?
E/Crypto Decrypted﹕ Password
Base64.encodeToString(cipherText, Base64.DEFAULT); then store it.
It might be a little too late but I had the same issue and managed to get the plain text after the decryption.
What you really need to do is to use ByteArrayOutputStream like the following code:
Entity entity = new Entity("password");
byte[] ciphertext = crypto.encrypt(("data to encrypt").getBytes(),entity);
byte[] plainText = crypto.decrypt(ciphertext,entity);
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(plainText, 0, plainText.length);
String decryptedPassword = out.toString();
out.close();
Hope this helps.
Hi I am working on AES encryption and decryption in my project.
I have a .mp4 file which is encrypted using "AES/CBC/pkcs5padding".
I have the key and iv values which is used to encrypt the first 256 bytes of the audio file.
I need to decrypt the file's first 256 bytes using the same algorithm , key and iv values.
I have followed some links (link1,link2).
I got a audio player demo and tried to implement my part(AES encryption and decryption) as demo.
Below I explained the code what I have done.
This method reads the data from encrypted file which is under res/raw folder.
private void readFile() throws IOException, InvalidKeyException,
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidAlgorithmParameterException, IllegalBlockSizeException,
BadPaddingException {
Context context = getApplicationContext();
/*
* InputStream is = getResources().openRawResource(
* getResources().getIdentifier("raw/encrypted", "raw",
* getPackageName())); String text = "";
*
* int size = is.available(); byte[] buffer = new byte[size];
* is.read(buffer);
*/
InputStream inStream = context.getResources().openRawResource(
R.raw.encrypted);
// get string from file
byte[] music = new byte[256];
for (int i = 0; i <= inStream.available(); i = i + 255) {
music = convertStreamToByteArray(inStream, i);
byte[] bytesToWrite = new byte[256];
bytesToWrite = music;
if (i == 0) {
bytesToWrite = AES256Cipher.decrypt(iv.getBytes("UTF-8"),
key.getBytes("UTF-8"), music);
// writeFirstSetOfBytes("decrypted.mp4");
}
writeFirstSetOfBytes(bytesToWrite);
}
}
the decrypt method got from the link1. Here I passed the key and iv values mentioned above.
public static byte[] decrypt(byte[] ivBytes, byte[] keyBytes,
byte[] textBytes) throws java.io.UnsupportedEncodingException,
NoSuchAlgorithmException, NoSuchPaddingException,
InvalidKeyException, InvalidAlgorithmParameterException,
IllegalBlockSizeException, BadPaddingException {
AlgorithmParameterSpec ivSpec = new IvParameterSpec(ivBytes);
// SecretKeySpec newKey = new SecretKeySpec(keyBytes, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE,
new SecretKeySpec(keyBytes, "AES"), ivSpec);
return cipher.doFinal(textBytes);
}
This method used to get the byte array from the input stream.
public static byte[] convertStreamToByteArray(InputStream is, int size)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[256];
int i = Integer.MAX_VALUE;
while ((i = is.read(buff, size, buff.length)) > 0) {
baos.write(buff, 0, i);
}
return baos.toByteArray(); // be sure to close InputStream in calling
// function
}
This method writes the received byte array into a destination file(decrypted.mp4)
private void writeFirstSetOfBytes(byte[] byteToWrite) {
File file = new File(
Environment
.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS),
"/decrypted.mp4");
FileOutputStream stream = null;
if (!file.exists()) {
try {
file.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
// writing data into file
try {
stream = new FileOutputStream(file);
stream.write(byteToWrite);
stream.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
I am getting the following error.
javax.crypto.IllegalBlockSizeException: error:0606506D:digital envelope routines:EVP_DecryptFinal_ex:wrong final block length
How can I achieve my requirement ?
How do I decrypt the first 256 bytes of data only?
Is there any code behaves wrongly ?
Is there any third party library avilable ?
If need more clarification, kindly let me know.
According to Wikipedia, PKCS#5 is a special variant of PKCS#7 that is defined for exactly 64-bit blocks (while PKCS#7 works for any block size), but AES uses 128-bit blocks only (or larger, but this was not included in the standard), thus the mismatch. Try another padding scheme.
I've never worked with encryption before. Actually I know nothing about encryption. I have a file encrypted with openssl tool using params:
openssl aes-256-cbc -nosalt -in fileIn -out fileOUT -p -k KEY
I need to decrypt it into memory but I don't know how. Can anyone provide me the code related to encryption?
Here's class I have written to decrypt a string encoded with params above (if I remmeber it correct):
public class CipherUtils {
public static byte[] getKey(String password, byte[] salt) {
try {
byte[] passwordSalt = EncodingUtils.getAsciiBytes(password);
passwordSalt = concatenateByteArrays(passwordSalt, salt);
byte[] hash1 = getHashForHash(null, passwordSalt);
byte[] hash2 = getHashForHash(hash1, passwordSalt);
byte[] key = concatenateByteArrays(hash1, hash2);
return key;
} catch (Exception e) {
return null;
}
}
public static byte[] getIV(String password, byte[] salt) {
try {
byte[] passwordSalt = EncodingUtils.getAsciiBytes(password);
passwordSalt = concatenateByteArrays(passwordSalt, salt);
byte[] hash1 = getHashForHash(null, passwordSalt);
byte[] hash2 = getHashForHash(hash1, passwordSalt);
byte[] hash3 = getHashForHash(hash2, passwordSalt);
return hash3;
} catch (Exception e) {
return null;
}
}
private static byte[] getHashForHash(byte[] hash, byte[] passwordSalt) {
try {
byte[] hashMaterial = concatenateByteArrays(hash, passwordSalt);
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(hashMaterial);
} catch (Exception e) {
return null;
}
}
private static byte[] concatenateByteArrays(byte[] a, byte[] b) {
if (a == null)
return b;
if (b == null)
return a;
byte[] result = new byte[a.length + b.length];
System.arraycopy(a, 0, result, 0, a.length);
System.arraycopy(b, 0, result, a.length, b.length);
return result;
}
}
Salt is an empty bytearray in this case. It uses apache-commons-compress.jar.
Here's usage example:
byte[] key = CipherUtils.getKey(password, null);
byte[] IV = CipherUtils.getIV(password, null);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"),
new IvParameterSpec(IV));
cis = new CipherInputStream(is, cipher);
Where is is an InputStream of encrypted data.
this may helps you
public void encrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
// Here you read the cleartext.
FileInputStream fis = new FileInputStream("data/cleartext");
// This stream write the encrypted text. This stream will be wrapped by
// another stream.
FileOutputStream fos = new FileOutputStream("data/encrypted");
// Length is 16 byte
SecretKeySpec sks = new SecretKeySpec("yourkey".getBytes(), "AES");
// Create cipher
Cipher cipher = Cipher.getInstance("AES/CBC");
cipher.init(Cipher.ENCRYPT_MODE, sks);
// Wrap the output stream
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
// Write bytes
int b;
byte[] d = new byte[8];
while ((b = fis.read(d)) != -1) {
cos.write(d, 0, b);
}
// Flush and close streams.
cos.flush();
cos.close();
fis.close();
}
Decrypt
public void decrypt() throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
FileInputStream fis = new FileInputStream("data/encrypted");
FileOutputStream fos = new FileOutputStream("data/decrypted");
SecretKeySpec sks = new SecretKeySpec("yourkey".getBytes(), "AES");
Cipher cipher = Cipher.getInstance("AES/CBC");
cipher.init(Cipher.DECRYPT_MODE, sks);
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();
}