I need to encrypt an audio file while it is being generated. I am encrypting header with dummy data(because I don't know the actual size of audio data) at the starting and encrypting the audio data on the fly. My plan is to update the header at the end with actual data size of audio file.
But, When I tried to overwrite the encrypted header data with newly encrypted header data of same size by using same key and IV and try to decrypt later, I am getting junk data generated.
Why is this happening even though I am using same key and IV? In the below code I tried to simulate what I am doing. Encrypted file of size 64 bytes generated and decrypted file of size 50 bytes generated.
Without updation: abcdabcdab0123456789012345678901234567890123456789
With header updation: ABCDABCDAB÷‹þ#óMCKLZƒÖ^Ô234567890123456789
Expected output: ABCDABCDAB0123456789012345678901234567890123456789
Is this the right approach to achieve partial update of already encrypted data?
protected void Encrypt()
{
byte[] numBytes = {'0','1','2','3','4','5','6','7','8','9','0','1','2','3','4','5','6','7','8','9', '0','1','2','3','4','5','6','7','8','9', '0','1','2','3','4','5','6','7','8','9'};
byte[] smallCase = {'a','b','c','d','a','b','c','d','a','b','c','d','a','b','c','d'};
byte[] capitalCase = {'A','B','C','D','A','B','C','D','A','B','C','D','A','B','C','D'};
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1And8BIT");
KeySpec spec = new PBEKeySpec("junglebook".toCharArray(), "Salt".getBytes(), 65536, 256);
SecretKey tmp = null;
tmp = factory.generateSecret(spec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
/* Encryption cipher initialization. */
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secret);
AlgorithmParameters params = cipher.getParameters();
byte[] iv = params.getParameterSpec(IvParameterSpec.class).getIV();
Log.d("Encryption" + "iv data :", iv.toString());
/*Open two Cipher ouput streams to the same encrypted file*/
FileOutputStream os = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/sample.encrypted");
CipherOutputStream cos = new CipherOutputStream(os,cipher);
FileOutputStream os1 = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/sample.encrypted");
CipherOutputStream cos1 = new CipherOutputStream(os1,cipher);
int offset = 0;
Log.d("Encryption", "Writing cipher text to output file");
//Write 16 bytes header data with smallCase array
cos.write(smallCase, offset, 16);
// write 40 bytes actual data
cos.write(numBytes, offset, 40);
FileOutputStream ivStream = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/iv.dat");
if (ivStream != null) {
Log.d("Encryption", "Writing iv data to output file");
ivStream.write(iv);
}
cos.close();
// Overwrite header data with capitalCase array data
cos1.write(capitalCase, offset, 16);
cos1.close();
ivStream.close();
}catch (Exception e) {
e.printStackTrace();
}
}
protected void Decrypt()
{
byte[] dBytes = new byte[200];
try {
Log.d("Decryption", "Reading iv data ");
File f1 = new File(sdCard.getAbsolutePath()+"/Notes/iv.dat");
byte[] newivtext = new byte[(int)f1.length()];
FileInputStream readivStream = new FileInputStream(sdCard.getAbsolutePath()+"/Notes/iv.dat");
if(readivStream != null) {
readivStream.read(newivtext);
}
// Generate the secret key from same password and salt used in encryption
SecretKeyFactory dfactory = SecretKeyFactory.getInstance("PBKDF2withHmacSHA1And8BIT");
KeySpec dspec = new PBEKeySpec("junglebook".toCharArray(), "Salt".getBytes(), 65536, 256);
SecretKey dtmp = dfactory.generateSecret(dspec);
SecretKey dsecret = new SecretKeySpec(dtmp.getEncoded(), "AES");
// Initialize dcipher
Cipher dcipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
dcipher.init(Cipher.DECRYPT_MODE, dsecret, new IvParameterSpec(newivtext));
FileInputStream inputStream = new FileInputStream(sdCard.getAbsolutePath()+"/Notes/sample.encrypted");
CipherInputStream cis = new CipherInputStream(inputStream,dcipher);
FileOutputStream os = new FileOutputStream(sdCard.getAbsolutePath() + "/Notes/sample.decrypted");
int b = cis.read(dBytes);
while(b != -1) {
Log.d("Decryption","Bytes decrypted" + b);
os.write(dBytes, 0, b);
b = cis.read(dBytes);
}
cis.close();
os.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I suggest you update several things:
you are opening multiple outputstreams to the SAME file, which is very strange, the runtime should not allow you to do that. So - write only with a single output if you want any predictable results.
You may read about the mode of operations see the CRT mode uses no padding and allows you to update only a portion of the ciphertext (assuming you use no authenticated encryption). So AES/CTR/NoPadding could solve your problem. (and there should be no extra bytes if you do it correctly)
you can update a portion of the file using the RandomAccessFile and overwrite portion of the ciphertext what is needed.
I'm trying to create a simple encryption/decryption program, but i'm having problems when decrypting. The way the program works, I get string input from the user, then encrypt using DES, convert to Base64 and give the user the converted secret key. However, when I get the secret key from the user and I try to decrypt, I get either error:
java.security.InvalidKeyException: No installed provider supports this key: (null)
or
javax.crypto.BadPaddingException
I don't know if the fault is at the time of encryption or if it's the decryption. Here's the respective snippets of code:
import javax.xml.bind.DatatypeConverter;
public static boolean encrypt(byte[] text){
Boolean yorn = false;
try{
myDesKey = KeyGenerator.getInstance("DES").generateKey();
//myDeskKey = myDesKey.toString();
Cipher desCipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
desCipher.init(Cipher.ENCRYPT_MODE, myDesKey);
//I felt it would be better seeing the secret key as "woatDnBJLAg=" instead of "com.sun.crypto.provider.DESKey#18765"
if (myDesKey != null) {
stringKey = DatatypeConverter.printBase64Binary(myDesKey.getEncoded());
System.out.println("actual secret_key:" + myDesKey);
byte[] encodedKey = DatatypeConverter.parseBase64Binary(stringKey);
myDesKey = new SecretKeySpec(encodedKey, 0, encodedKey.length,
"DES");
System.out.println("after encode & decode secret_key:"
+ DatatypeConverter.printBase64Binary(myDesKey.getEncoded()));
}
textEncrypted = desCipher.doFinal(text);
yorn = true;
JTextArea textArea = new JTextArea(2,50);
textArea.setText("Your encryption key is: " + stringKey + " . Ensure you store it in a safe place" );// + DatatypeConverter.printBase64Binary(myDesKey.getEncoded()));
textArea.setEditable(false);
JOptionPane.showMessageDialog(null, new JScrollPane(textArea), "RESULT", JOptionPane.INFORMATION_MESSAGE);
}catch(Exception e)
{
System.out.println("There has been an error encrypting the file");
yorn = false;
}
return yorn;
Decryption
public static String decrypt(byte[] cipherText, SecretKey key,String key1)
{
String plainText = "";
try{
SecretKey myDesKey = key;
if(key == null){
JOptionPane.showMessageDialog(null, "We were unable to find your decryption key. Please enter your decryption key below: ");
JTextArea textBox = new JTextArea(1,15);
JOptionPane.showMessageDialog(null, new JScrollPane(textBox),"Enter your decryption key ",JOptionPane.PLAIN_MESSAGE);
//myDesKey = textBox.toSecretKey;
}
Cipher desCipher;
desCipher = Cipher.getInstance("DES");
desCipher.init(Cipher.DECRYPT_MODE, myDesKey);
byte[] textDecrypted = desCipher.doFinal(cipherText);
plainText = new String(textDecrypted);
JOptionPane.showMessageDialog(null, plainText, "DECRYPTED MESSAGE", 0);
}catch(Exception e)
{
System.out.println("There has been an error decrypting the file");
System.out.println(e);
}return plainText;
}
}
I know that I'm probably getting the errors because i've combined so many jumbled bits of code from all over stack and I seem to have lost the plot, but any help will be greatly appreciated.
Thanks!!
You're using two different ciphers. Cipher.getInstance("DES") is not fully specified, so it probably defaults to Cipher.getInstance("DES/ECB/PKCS5Padding") which is different from the CBC mode you're using during encryption.
Secondly, since you're using CBC mode, you need to manage the initialization vector (IV), but you don't do this at all. You can either provide the IV as a third parameter for Cipher#init or let it automatically be generated as you currently do, but then you have to send the IV (desCipher.getIV()) along with the ciphertext to the receiver. The IV doesn't have to be secret. A common way is to prepend it to the ciphertext and slice it off before decryption.
Lastly, the key you're using during decryption is not the same key that you've used during encryption, because you've re-encoded the key after encryption, but didn't decode it back.
I have been given an encrypted file along with a base64 symmetric key and base 64 IV and have been asked to decrypt it using Java. The encryption used on the data file was AES. However, when I run the encrypted file, symmetric key and IV into my code, I get the following error:
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16 when decrypting with padded cipher
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:913)
Here is my code:
String encryptedData = "C:\\EncryptedDataFile.data";
FileInputStream fis = null;
File file = new File(encryptedData);
//Convert file into array of bytes
byte[] encryptedDataBytes = new byte[(int) file.length()];
try
{
// Read in array of bytes
fis = new FileInputStream(file);
fis.read(encryptedDataBytes);
fis.close();
}
catch (FileNotFoundException ex)
{
ex.printStackTrace();
}
catch (IOException ex)
{
ex.printStackTrace();
}
// AES Key
byte[] decodedKey = Base64.getDecoder().decode("50rofsdb0TnQAQCb702wKz8m6XQeLNj6lamEvivKsh8=");
// decode the base64 encoded string
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "AES"); // rebuild key using SecretKeySpec
// IV
byte[] initVecBytes = Base64.getDecoder().decode("OUXLZq4SpyhzNGIei0nerA==");
// Decrypt the cipher text
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
IvParameterSpec ivParameterSpec = new IvParameterSpec(initVecBytes);
cipher.init(Cipher.DECRYPT_MODE, originalKey, ivParameterSpec);
byte[] original = cipher.doFinal(encryptedDataBytes);
String s = new String(original);
System.out.println(s);
If someone could provide some help to me on this matter it would be much appreciated
I have been using BouncyCastle's provider to encrypt files using "AES/GCM/NoPadding" as the transformation. It has worked for lots of smaller files. But, with larger files I am getting the exception:
javax.crypto.AEADBadTagException: Tag mismatch!
Here is the code I am using to encrypt:
try (DataOutputStream os = new DataOutputStream(new FileOutputStream(encryptedFile))) {
os.writeInt(CURRENT_ENCRYPTION_FILE_VERSION);
os.writeInt(CURRENT_RSA_KEY_VERSION);
// Generate a new random symmetric key for the AES encryption cipher
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(128);
SecretKey aesKey = keyGenerator.generateKey();
// Write the RSA encrypted AES key to the file
os.write(doRsaTransformation(aesKey.getEncoded(), publicRsaKey, Cipher.ENCRYPT_MODE));
// Generate an initialization vector (IV)
SecureRandom sr = new SecureRandom();
byte[] iv = new byte[16];
sr.nextBytes(iv);
// Write the RSA encrypted IV to the file
os.write(doRsaTransformation(iv, publicRsaKey, Cipher.ENCRYPT_MODE));
// Write the encrypted file
doAesFileEncryption(fileToEncrypt, aesKey, iv, os);
} catch (NoSuchAlgorithmException | BadPaddingException | IllegalBlockSizeException | InvalidKeyException | NoSuchPaddingException | IOException | InvalidAlgorithmParameterException ex) {
throw new EncryptionException(ex);
}
private void doAesFileEncryption(File fileToEncrypt, SecretKey aesKey, byte[] iv, OutputStream os) {
Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
aesCipher.init(Cipher.ENCRYPT_MODE, aesKey, new GCMParameterSpec(128, iv));
byte[] block = new byte[1024];
int i;
try (FileInputStream fis = new FileInputStream(fileToEncrypt)) {
while ((i = fis.read(block)) != -1) {
byte[] encryptedBlock = aesCipher.update(block, 0, i);
if (encryptedBlock != null) {
os.write(encryptedBlock);
}
}
byte[] encryptedFinal = aesCipher.doFinal();
if (encryptedFinal != null) {
os.write(encryptedFinal);
}
}
}
Here is the code I am using to decrypt:
Cipher aesCipher = Cipher.getInstance("AES/GCM/NoPadding");
aesCipher.init(Cipher.DECRYPT_MODE, aesKey, new GCMParameterSpec(128, iv));
byte[] block = new byte[1073741824];
int i;
try (FileOutputStream fos = new FileOutputStream(decryptedFile)) {
while ((i = is.read(block)) != -1) {
byte[] decryptedBlock = aesCipher.update(block, 0, i);
if (decryptedBlock != null) {
fos.write(decryptedBlock);
}
}
byte[] decryptedFinal = aesCipher.doFinal();
if (decryptedFinal != null) {
fos.write(decryptedFinal);
}
}
UPDATE:
I have been trying to figure this out for days now. Luckily, I have at least figured out how to decrypt a file that I desperately needed!
The file was being encrypted on a server that was running Java 7 update 51. (I know I'm bad for not keeping it up to date.) Now I'm trying to decrypt it on my local computer (and other local computers) that are running Java 8. I always get the above exception for the larger files, not the smaller ones. If I decrypt the large file with Java 7, then it decrypts with no errors.
Is this behavior expected? It seems to me that Java 8 should be able to decrypt large files that were encrypted with Java 7.
If I can't rely on the newer versions of Java decrypting files that were encrypted with older versions of Java, then how do I move forward? Do I have to decrypt all of my files with the old version so that I can then encrypt them with the new version?
Thank you very much! Any help is greatly appreciated!
How to encrypt a folder from android sdcard and the encrypted folder should be in filename.des. Is it possible?. I am using below code to encrypt a folder
try {
File root_sd = Environment.getExternalStorageDirectory();
//original is a folder to encrypt
file = new File(root_sd + "/myfile/original");
String filename = file.getAbsolutePath();
System.out.println("name of file for encryption ===>"+file.toString());
fis = new FileInputStream(filename);
//encrypted folder should be in filename.des
fos = new FileOutputStream("/mnt/sdcard/myfile/filename" + ".des");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i("Encrypt ACtivity", "file io exception");
}
// Use PBEKeySpec to create a key based on a password.
// The password is passed as a character array
PBEKeySpec keySpec = new PBEKeySpec(password.toCharArray());
SecretKeyFactory keyFactory;
try {
keyFactory = SecretKeyFactory
.getInstance("PBEWithMD5AndDES");
SecretKey passwordKey = keyFactory.generateSecret(keySpec);
// PBE = hashing + symmetric encryption. A 64 bit random
// number (the salt) is added to the password and hashed
// using a Message Digest Algorithm (MD5 in this example.).
// The number of times the password is hashed is determined
// by the interation count. Adding a random number and
// hashing multiple times enlarges the key space.
byte[] salt = new byte[8];
Random rnd = new Random();
rnd.nextBytes(salt);
int iterations = 100;
// Create the parameter spec for this salt and interation
// count
PBEParameterSpec parameterSpec = new PBEParameterSpec(salt,iterations);
// Create the cipher and initialize it for encryption.
Cipher cipher = Cipher.getInstance("PBEWithMD5AndDES");
cipher.init(Cipher.ENCRYPT_MODE, passwordKey, parameterSpec);
// Need to write the salt to the (encrypted) file. The
// salt is needed when reconstructing the key for
// decryption.
fos.write(salt);
// Read the file and encrypt its bytes.
byte[] input = new byte[64];
int bytesRead;
while ((bytesRead = fis.read(input)) != -1) {
byte[] output = cipher.update(input, 0, bytesRead);
if (output != null)
fos.write(output);
}
byte[] output = cipher.doFinal();
if (output != null)
fos.write(output);
fis.close();
fos.flush();
but it is giving me FileNotFoundException. open failed : EISDIR (Is a directory). Cany anyone tell me how to ecrypt a folder. I am able to encrypt a file but not folder.
Thanks