I have over 1000 images and videos that need to be encrypted. Nothing over the top just something simple, I was thinking of using AES but what I cannot figure out is how to encrypt on my computer then decrypt the item on the device.
I will be encrypting all the items on my computer probably using python. Then in an on demand fashion will decrypt the item with java (Android app)
Any simple explanation will do pseudo code is fine too.
The main issue im having is how to use the same key to encrypt and decrypt. I've been generating the key and can't get it to port to the other device for decryption.
Thanks
Python Code. Works encrypts and decrypts.
from Crypto.Cipher import AES
import os, random, struct
key = '0123456789abcdef'
mode = AES.MODE_CBC
chunksize = 64*1024
iv = ''.join(chr(random.randint(0,0xFF)) for i in range(16))
encryptor = AES.new(key,mode,iv)
filesize = os.path.getsize('sample.jpg')
with open('sample.jpg','rb') as infile:
with open('sample.enc','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))
## decrypt
with open('sample.enc', 'rb') as infile:
origsize = struct.unpack('<Q', infile.read(struct.calcsize('Q')))[0]
iv = infile.read(16)
decryptor = AES.new(key, AES.MODE_CBC, iv)
with open('sample2.jpg', 'wb') as outfile:
while True:
chunk = infile.read(chunksize)
if len(chunk) == 0:
break
outfile.write(decryptor.decrypt(chunk))
outfile.truncate(origsize)
How would I do the decrypt part in Java? Here is my quick sloppy java code that doesn't work. I think it is the padding that is messing it up.
public void decryptFile(){
String inFile = "sample.enc";
String outFile = "sample.jpg";
String dir = Environment.getExternalStorageDirectory() +"/Android/data/HOT/";
InputStream is ;
byte[] iv = new byte[16];
try {
is = new FileInputStream(dir+inFile);
is.read(iv);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
Log.d("D1","no file found");
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("D-2","no file found");
e.printStackTrace();
}
byte[] k = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
Key key = new SecretKeySpec(k,"AES");
try {
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, key,new IvParameterSpec(iv));
OutputStream outs = new FileOutputStream(dir+outFile);
is = new FileInputStream(dir+inFile);
while(true){
byte[] chunk = new byte[64*1024];
is.read(chunk);
if(chunk.length == 0){
break;
}
outs.write(cipher.doFinal(chunk));
}
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
Log.d("D","1");
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
Log.d("D","2");
e.printStackTrace();
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
Log.d("D","3");
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
// TODO Auto-generated catch block
Log.d("D","4");
e.printStackTrace();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
Log.d("D","5");
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
Log.d("D","6");
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
Log.d("D","7");
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
Log.d("D","8");
e.printStackTrace();
}
ImageView im = (ImageView)findViewById(R.id.imageView2);
Bitmap mainBitmap = BitmapFactory.decodeFile(dir+outFile);
im.setImageBitmap(mainBitmap);
}
In the Java version, you don't seem to be reading in the filesize before reading in the IV, unlike the Python version.
You also open a second FileInputStream and then don't skip the filesize and IV before reading in chunks for the Cipher.
Another thing to check is that the keys are being interpreted the same in Java and Python, i.e. the string in Python results in the same sequence of bytes as the byte array in Java.
Related
I need to do triple DES encryption in GWT client file and need to do decryption of encrypted string in javascript. I have used TripleDesCipher in GWT but while doing decryption in javascript using crypto-js, I am getting blank string. Following is my GWT code.
TripleDesCipher cipher = new TripleDesCipher();
String enc ="";
String key = "579D2D852F2F3BABABBD71B7";
cipher.setKey(key.getBytes());
try {
enc = cipher.encrypt(String.valueOf(value));
} catch (DataLengthException e1) {
e1.printStackTrace();
} catch (IllegalStateException e1) {
e1.printStackTrace();
} catch (InvalidCipherTextException e1) {
e1.printStackTrace();
}
Following is my javascript code for decryption.
var encrypted = urlParams.get('id');
var base64String = encrypted.toString();
alert(base64String);
var key = "579D2D852F2F3BABABBD71B";
var decrypted =
CryptoJS.TripleDES.decrypt(base64String,key);
console.log("DES3 decrypted text:"+ decrypted.toString(CryptoJS.enc.Utf8));
I have this code here which I'm having difficulty converting to VB.NET and hoping someone who give me a hand with it.
I'm having difficulty with the part on the cipher - I have tried Googling but was unable to find a clear resource explaining it in simple terms. (I don't know how to proceed with it as it seems there's no equivalent for it??)
I have almost no knowledge of java hence am trying to google and find out what each part means and convert it after. Hope someone would be able to point me in the right direction!
public static byte[] decryptPDF(String password, String filePath) {
try {
byte[] headerSaltAndCipherText = Base64.decode(IOUtils.toString(new FileInputStream(new File(filePath)), "UTF-8").toString().getBytes("UTF-8"), 0);
byte[] salt = Arrays.copyOfRange(headerSaltAndCipherText, 8, 16);
byte[] encrypted = Arrays.copyOfRange(headerSaltAndCipherText, 16, headerSaltAndCipherText.length);
Cipher aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[][] keyAndIV = EVP_BytesToKey(32, aesCBC.getBlockSize(), MessageDigest.getInstance(CommonUtils.MD5_INSTANCE), salt, password.getBytes("UTF-8"), 1);
aesCBC.init(2, new SecretKeySpec(keyAndIV[0], "AES"), new IvParameterSpec(keyAndIV[1]));
return aesCBC.doFinal(encrypted);
} catch (IOException e) {
e.printStackTrace();
return null;
} catch (NoSuchPaddingException e2) {
e2.printStackTrace();
return null;
} catch (InvalidAlgorithmParameterException e3) {
e3.printStackTrace();
return null;
} catch (NoSuchAlgorithmException e4) {
e4.printStackTrace();
return null;
} catch (IllegalBlockSizeException e5) {
e5.printStackTrace();
return null;
} catch (BadPaddingException e6) {
e6.printStackTrace();
return null;
} catch (InvalidKeyException e7) {
e7.printStackTrace();
return null;
}
}
What I've tried so far is...
Public Shared Function decryptPDF(ByVal password As String, ByVal fileAsString As String) As Byte()
Try
Dim headerSaltAndCipherText() As Byte = System.Convert.FromBase64String(fileAsString)
Dim salt() As Byte = headerSaltAndCipherText.Skip(7).Take(8)
Dim encrypted() As Byte = headerSaltAndCipherText.Skip(15).Take(headerSaltAndCipherText.Length)
Dim aesCBC As Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
Dim keyAndIV() As Byte = EVP_BytesToKey(32, aesCBC.getBlockSize, MessageDigest.getInstance(CommonUtils.MD5_INSTANCE), salt, password.getBytes("UTF-8"), 1)
aesCBC.init(2, New SecretKeySpec(keyAndIV(0), "AES"), New IvParameterSpec(keyAndIV(1)))
Return aesCBC.doFinal(encrypted)
End Try
End Function
Try that
Public Shared Function decryptPDF(ByVal password As String, ByVal filePath As String) As Byte()
Try
Dim headerSaltAndCipherText() As Byte = Base64.decode(IOUtils.toString(New FileInputStream(New File(filePath)), "UTF-8").toString.getBytes("UTF-8"), 0)
Dim salt() As Byte = Arrays.copyOfRange(headerSaltAndCipherText, 8, 16)
Dim encrypted() As Byte = Arrays.copyOfRange(headerSaltAndCipherText, 16, headerSaltAndCipherText.length)
Dim aesCBC As Cipher = Cipher.getInstance("AES/CBC/PKCS5Padding")
Dim keyAndIV(,) As Byte = EVP_BytesToKey(32, aesCBC.getBlockSize, MessageDigest.getInstance(CommonUtils.MD5_INSTANCE), salt, password.getBytes("UTF-8"), 1)
aesCBC.init(2, New SecretKeySpec(keyAndIV(0), "AES"), New IvParameterSpec(keyAndIV(1)))
Return aesCBC.doFinal(encrypted)
Catch e As IOException
e.printStackTrace
Return Nothing
Catch e2 As NoSuchPaddingException
e2.printStackTrace
Return Nothing
Catch e3 As InvalidAlgorithmParameterException
e3.printStackTrace
Return Nothing
Catch e4 As NoSuchAlgorithmException
e4.printStackTrace
Return Nothing
Catch e5 As IllegalBlockSizeException
e5.printStackTrace
Return Nothing
Catch e6 As BadPaddingException
e6.printStackTrace
Return Nothing
Catch e7 As InvalidKeyException
e7.printStackTrace
Return Nothing
End Try
End Function
I am working on decrypting a binary file encrypted in C# using Rijndael encryption method. The file is copied to an android device. The decryption logic works fine when run in a java based desktop test program. But it throws java.io.IOException: last block incomplete when run in android. I am using the code below.
public static void Decrypt(String fileIn, String fileOut, byte[] key, byte[] IV, long offset)
{
// First we are going to open the file streams
FileInputStream fsIn;
try
{
fsIn = new FileInputStream(fileIn);,,
FileOutputStream fsOut = new FileOutputStream(fileOut);
// create cipher object
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key, "AES"), new IvParameterSpec(IV));
// create the encryption stream
CipherInputStream cis = new CipherInputStream(fsIn, cipher);
// set a buffer and keep writing to the stream
int bufferLen = KiloByte;
byte[] buffer = new byte[bufferLen];
int bytesRead = 0;
// read a chunk of data from the input file
while ( (bytesRead = cis.read(buffer, 0, bufferLen)) != -1)
{
// write to file
fsOut.write(buffer, 0, bytesRead);
}
fsOut.flush();
// close streams
fsOut.close();
cis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
The key is generated by using the function
public static byte[] GetKey(String password, byte[] IV, int length)
throws NoSuchAlgorithmException, InvalidKeySpecException
{
// Length is kept 16 to make it compatible with all platforms
SecretKeyFactory f = SecretKeyFactory.getInstance("PBKDF2WithHmacSHA1");
KeySpec ks = new PBEKeySpec(password.toCharArray(), IV, 1000, length*8);
SecretKey s = f.generateSecret(ks);
Key k = new SecretKeySpec(s.getEncoded(),"AES");
return k.getEncoded();
}
I have gone through many posts on internet related to the topic. Based on that, I have made sure that I use byte array rather String. But still getting this issue.
I want to decrpyt the encrypted message digest. i hav this code in my java program:
String bobSignedMsg = SignedMsg;
//At the receiving end, Bob extracts the msg
// length, the msg text, and the digital
// signature from the signed msg.
//Get the message length.
int MsgLen = Integer.parseInt(bobSignedMsg.trim().substring(bobSignedMsg.length()-6));
System.out.println(
"\n12. Bob's calculated msg len: "
+ MsgLen);
//Get the message text.
String bobMsgText = bobSignedMsg.substring(
0,MsgLen);
System.out.println(
"\n13. Bob's extracted msg text: "
+ bobMsgText);
//Bob knows that everything following the msg
// text except for the four characters at the
// end that indicate the message length is
// the encoded and encrypted version of the
// extended digital signature. He extracts
// it.
String bobExtractedSignature =
bobSignedMsg.substring(
MsgLen,bobSignedMsg.length() - 6);
System.out.println(
"\n14. Bob's extracted extended digital "
+ "signature: "
+ bobExtractedSignature);
byte[] strtodecrypt=bobExtractedSignature.getBytes();
byte[] decryptedCardNo = obj.rsaDecrypt(strtodecrypt,PbkeyPath);
String decryptedform = obj.byteArrayToHexStr(decryptedCardNo);
System.out.println("After Decryption: "+decryptedform);
In the above lines of code
byte[] decryptedCardNo = obj.rsaDecrypt(strtodecrypt,PbkeyPath);
calls the function:
public byte[] rsaDecrypt(byte[] sampleText,String pbkeypath) {
PublicKey pubKey = null;
try {
pubKey = readKeyFromFile(pbkeypath);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Cipher cipher = null;
try {
cipher = Cipher.getInstance("RSA");
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
cipher.init(Cipher.DECRYPT_MODE, pubKey);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] cipherData = null;
try {
cipherData = cipher.doFinal(sampleText);
// cipherData = cipher.
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return cipherData;
}
But it gives the following error:
javax.crypto.IllegalBlockSizeException: Data must not be longer than 128 bytes
at com.sun.crypto.provider.RSACipher.a(DashoA13*..)
at com.sun.crypto.provider.RSACipher.engineDoFinal(DashoA13*..)
at javax.crypto.Cipher.doFinal(DashoA13*..)
I dont understand how to resolve the error for block size exception.....Please if anybody can help me with some ideas it wud be a great help in my project.
Block ciphers, such as RSA, can only encrypt no more than blockSize bytes. If you want to encrypt an arbitrary large amount of data with the same key, you would split it to parts of blockSize and encrypt each block individually. The same applies to decryption.
I have following program for encrypting data.
import java.security.Key;
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
public class Test {
private static final String ALGORITHM = "AES";
private static final byte[] keyValue = "ADBSJHJS12547896".getBytes();
public static void main(String args[]) throws Exception {
String encriptValue = encrypt("dude5");
decrypt(encriptValue);
}
/**
* #param args
* #throws Exception
*/
public static String encrypt(String valueToEnc) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.ENCRYPT_MODE, key);
System.out.println("valueToEnc.getBytes().length "+valueToEnc.getBytes().length);
byte[] encValue = c.doFinal(valueToEnc.getBytes());
System.out.println("encValue length" + encValue.length);
byte[] encryptedByteValue = new Base64().encode(encValue);
String encryptedValue = encryptedByteValue.toString();
System.out.println("encryptedValue " + encryptedValue);
return encryptedValue;
}
public static String decrypt(String encryptedValue) throws Exception {
Key key = generateKey();
Cipher c = Cipher.getInstance(ALGORITHM);
c.init(Cipher.DECRYPT_MODE, key);
byte[] enctVal = c.doFinal(encryptedValue.getBytes());
System.out.println("enctVal length " + enctVal.length);
byte[] decordedValue = new Base64().decode(enctVal);
return decordedValue.toString();
}
private static Key generateKey() throws Exception {
Key key = new SecretKeySpec(keyValue, ALGORITHM);
return key;
}
}
Here I am getting the following out put with exception?
valueToEnc.getBytes().length 5
encValue length16
encryptedValue [B#aa9835
Exception in thread "main" javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)
Can some one explain me the cause? Why its only saying when decrypting that length should be 16. Doesn't it convert to 16 as like encrypting with the doFinal method.
And as the exception says "how to decrypting without padded cipher?"
Your Order for encrypt: getBytes, encrypt, encode, toString
Your Order for decrypt(Wrong*): getBytes, decrypt, decode, toString
Two problems:
As someone already mentioned you should reverse the order of operations for decryption. You are not doing that.
encrypt gives you 16 bytes, encode 24 bytes, but toString gives 106 bytes. Something to do with invalid chars taking up additional space.
Note: Also, you don't need to call generateKey() twice.
Fix problem #1 by using the reverse order for decryption.
Correct order for decrypt: getBytes, decode, decrypt, toString
Fix problem #2 by replacing xxx.toString() with new String(xxx). Do this in both the encrypt and decrypt functions.
Your decrypt should look like this:
c.init(Cipher.DECRYPT_MODE, key)
val decodedValue = new Base64().decode(encryptedValue.getBytes())
val decryptedVal = c.doFinal(decodedValue)
return new String(decryptedVal)
This should give you back "dude5"
The line
String encryptedValue = encryptedByteValue.toString();
is the problem. The type of encryptedByteValue is byte[] and calling toString on it isn't what you want to do there. Instead try
String encryptedValue = Base64.getEncoder().encodeToString(encValue);
Then use Base64.decodeBase64(encryptedValue) in decrypt. You must do that prior to attempting to decrypt though. You must undo the operations in the reverse order of the encrypt method.
Fundamentally, there is an asymmetry between your encrypt function and your decrypt function. When you encrypt you perform an AES encrypt and then a base64 encode, when you decrypt you don't first undo the base64 encoding step.
I think that there's something wrong with your base64 encoding as well as [ shouldn't appear in a base64 encoded string.
Looking at the documentation for org.apache.commons.codec.binary.Base64 you should be able to do this on encode:
String encryptedValue = Base64.encodeBase64String(encValue);
and this on decode:
byte[] encValue = Base64.decodeBase64(encryptedValue);
Where are you getting a version of apache codec that has encodeToString or encodeBase64String?
I downloaded 1.5 from the apache site and while it says in the documentation that these methods exist, they don't show up when you do code completion and they create an unknown method when you provide them.
I was able to do:
byte raw[] = md.digest(); //step 4
byte hashBytes[] = Base64.encodeBase64(raw); //step 5
StringBuffer buffer = new StringBuffer();
for( int i=0; i<hashBytes.length; i++ )
buffer.append(hashBytes[i]);
return buffer.toString(); //step 6
And then the string that I obtained was very long, BUT it decrypted correctly.
I don't think this is the "right" way to do things, but can't find the methods that the documentation says are there.
That was alright, you just needed to
1) Use new String instead of toString() since toString() doesn't return what you need here (in both cases, encryption and decryption)
2) you need to decode first since the value is encode in base64.
I came across this thread but it took sometime to find out the actual point..I am posting my code for rest of the people who come across this issue.
public abstract class EncryptionDecryption {
static byte[] key = "!##$!##$%^&**&^%".getBytes();
final static String algorithm="AES";
public static String encrypt(String data){
byte[] dataToSend = data.getBytes();
Cipher c = null;
try {
c = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec k = new SecretKeySpec(key, algorithm);
try {
c.init(Cipher.ENCRYPT_MODE, k);
} catch (InvalidKeyException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encryptedData = "".getBytes();
try {
encryptedData = c.doFinal(dataToSend);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
byte[] encryptedByteValue = new Base64().encode(encryptedData);
return new String(encryptedByteValue);//.toString();
}
public static String decrypt(String data){
byte[] encryptedData = new Base64().decode(data);
Cipher c = null;
try {
c = Cipher.getInstance(algorithm);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SecretKeySpec k =
new SecretKeySpec(key, algorithm);
try {
c.init(Cipher.DECRYPT_MODE, k);
} catch (InvalidKeyException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
byte[] decrypted = null;
try {
decrypted = c.doFinal(encryptedData);
} catch (IllegalBlockSizeException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (BadPaddingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new String(decrypted);
}
public static void main(String[] args){
String password=EncryptionDecryption.encrypt("password123");
System.out.println(password);
System.out.println(EncryptionDecryption.decrypt(password));
}
}
I have replaces line in example:
String encryptedValue = encryptedByteValue.toString();
with next one:
String encryptedValue = new String(encryptedByteValue);
All works fine!