I tried to encrypt and decrypt a .txt file. The encryption worked fine but when I decrypt it the .txt file is empty. Here is my code:
package crypto;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class MyCrypto
{
SecretKeySpec key;
Cipher cipher;
byte[] iv = {0,0,0,0,0,0,0,0};
IvParameterSpec ivspec = new IvParameterSpec(iv);
MyCrypto() throws NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException
{
key =new SecretKeySpec("22042016".getBytes(), "DES");
cipher = Cipher.getInstance("DES/CBC/PKCS5Padding");
}
public void encrypt(File file) throws InvalidKeyException, IOException
{
cipher.init(Cipher.ENCRYPT_MODE, key);
FileInputStream fis = new FileInputStream(file);
FileOutputStream fos = new FileOutputStream(file);
CipherOutputStream cos = new CipherOutputStream(fos, cipher);
byte[] block = new byte[8];
int i;
while ((i = fis.read(block)) != -1) {
cos.write(block, 0, i);
}
cos.close();
fis.close();
}
public void decrypt(File file) throws IOException, InvalidKeyException, InvalidAlgorithmParameterException
{
cipher.init(Cipher.DECRYPT_MODE, key, ivspec);
FileInputStream fis = new FileInputStream(file);
CipherInputStream cis = new CipherInputStream(fis, cipher);
FileOutputStream fos = new FileOutputStream(file);
byte[] block = new byte[8];
int i;
while ((i = cis.read(block)) != -1) {
fos.write(block, 0, i);
}
cis.close();
fos.close();
}
public static void main(String[] args) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, InvalidAlgorithmParameterException
{
MyCrypto crypto = new MyCrypto();
File cryptoFile = new File(".../crypto.txt");
crypto.encrypt(cryptoFile);
crypto.decrypt(cryptoFile);
}
}
I know that DES isn't very safe. But it's just for my trying to mess around with de- and encryption.
Try replacing the code in your decrypt method with this:
// write decrypted bytes
fos.write(cipher.doFinal(Files.readAllBytes(file.toPath())));
// close the output file
fos.flush();
fos.close();
Related
I am doing a project to learn about encryption and decryption. I encrypt a file (input file) and encrypt the symmetric key using RSA public. Then I decrypt the symmetric key using RSA private key and then decrypt the file(output file).
here below is the code:
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.spec.EncodedKeySpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import javax.crypto.spec.IvParameterSpec;
public class Main {
public static SecretKey generateKey(int n) throws NoSuchAlgorithmException {
KeyGenerator keyGenerator = KeyGenerator.getInstance("AES");
keyGenerator.init(n);
SecretKey key = keyGenerator.generateKey();
return key;
}
public static IvParameterSpec generateIv() {
byte[] iv = new byte[128/8];
new SecureRandom().nextBytes(iv);
return new IvParameterSpec(iv);
}
public static void encryptFile(String algorithm, SecretKey key, IvParameterSpec iv,
File inputFile, File outputFile) throws IOException, NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.ENCRYPT_MODE, key, iv);
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[64];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byte[] output = cipher.update(buffer, 0, bytesRead);
if (output != null) {
outputStream.write(output);
}
}
byte[] outputBytes = cipher.doFinal();
if (outputBytes != null) {
outputStream.write(outputBytes);
}
inputStream.close();
outputStream.close();
}
public static void decryptFile(String algorithm, SecretKey key, IvParameterSpec iv,
File inputFile, File outputFile) throws IOException, NoSuchPaddingException,
NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
BadPaddingException, IllegalBlockSizeException {
Cipher cipher = Cipher.getInstance(algorithm);
cipher.init(Cipher.DECRYPT_MODE, key, iv);
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[64];
int bytesRead;
while ((bytesRead = inputStream.read(buffer)) != -1) {
byte[] output = cipher.update(buffer, 0, bytesRead);
if (output != null) {
outputStream.write(output);
}
}
byte[] outputBytes = cipher.doFinal();
if (outputBytes != null) {
outputStream.write(outputBytes);
}
inputStream.close();
outputStream.close();
}
public static byte[] encryptSymmetricKey(SecretKey secKey) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] key = Files.readAllBytes(Paths.get("publicKey.key"));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(key);
PublicKey publicKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.PUBLIC_KEY, publicKey);
byte[] encryptedKey = cipher.doFinal(secKey.getEncoded());
return encryptedKey;
}
public static SecretKey decryptSymmetricKey(SecretKey secKey) throws NoSuchAlgorithmException, IOException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] encryptedKey= encryptSymmetricKey(secKey);
byte[] key = Files.readAllBytes(Paths.get("publicKey.key"));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key);
PrivateKey privateKey = keyFactory.generatePrivate(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.PRIVATE_KEY, privateKey);
byte[] decryptedKey = cipher.doFinal(encryptedKey);
SecretKey originalKey = new SecretKeySpec(decryptedKey , 0, decryptedKey .length, "AES");
return originalKey;
}
public static void main(String[] args) throws NoSuchAlgorithmException, IOException, RuntimeException, InvalidKeySpecException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, NoSuchPaddingException, InvalidAlgorithmParameterException {
SecretKey secKey=generateKey(128);
IvParameterSpec iv=generateIv();
File inputFile=new File("C:/Users/nm-ca/IdeaProjects/RSA/src/inputFile.txt");
File outputFile=new File("C:/Users/nm-ca/IdeaProjects/RSA/src/outputFile.txt");
encryptFile("AES/CBC/PKCS5Padding",secKey,iv,inputFile,outputFile);
//Decrypt the cipher text using decrypted symmetric key
decryptFile("AES/CBC/PKCS5Padding", decryptSymmetricKey(secKey),iv,outputFile,inputFile);
}
}
The Error:
Exception in thread "main" java.security.spec.InvalidKeySpecException: java.security.InvalidKeyException: invalid key format
When I encrypt the symmetric key and then decrypt it, I produce an invalid key I guess. How can I solve this problem?
I am facing the following issue while working with Java cryptography.
error decrjavax.crypto.BadPaddingException: Given final block not
properly padded. Such issues can arise if a bad key is used during
decryption.
I have checked all possible answers, but couldn't find the exact reason behind this.
One observation that when i use AES/CBC/NoPadding in place of AES/CBC/PKCS5Padding, i can execute it successfully.
here is my code snippet.
package demo;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
public class TestEncryption {
private static final int BUFFER_SIZE = 32;
private static final int KEY_ITERATIONS = 65535;
private static final int DEFAULT_KEY_BITS = 128;
private static final String ALGORITHM = "AES/CBC/PKCS5Padding";
private static final String TRANSFORMATION = "AES";
private static final String PBKDF_2_WITH_HMAC_SHA_256 = "PBKDF2WithHmacSHA256";
private static final int IV_SIZE = 16;
private final Cipher ecipher;
private final Cipher dcipher;
private SecretKey secretKey;
/**
* Initialize the ciphers using the given key.
* #param key
* #param keyBits
*/
public TestEncryption(String key, int keyBits) {
byte[] salt = new byte[8];
if (key.length() < 8) {
throw new IllegalArgumentException("key must contain 8 characters or more");
}
for (int i = 0; i < 8; i = i + 1) {
salt[i] = ((byte) key.charAt(i));
}
char[] password = key.toCharArray();
int keyLength = DEFAULT_KEY_BITS;
try {
SecretKeyFactory factory = SecretKeyFactory.getInstance(PBKDF_2_WITH_HMAC_SHA_256);
if (keyBits == 256) {
keyLength = 256;
}
KeySpec spec = new PBEKeySpec(password, salt, KEY_ITERATIONS, keyLength);
secretKey = new SecretKeySpec(factory.generateSecret(spec).getEncoded(), TRANSFORMATION);
ecipher = Cipher.getInstance(ALGORITHM);
dcipher = Cipher.getInstance(ALGORITHM);
} catch (InvalidKeySpecException | NoSuchPaddingException | NoSuchAlgorithmException e) {
throw new RuntimeException("Failed to initialize encryption.", e);
}
}
public void encryptFile(File src, File dest){
try {
InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest);
CipherOutputStream cipherOutputStream= new CipherOutputStream(outputStream, ecipher);
// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);
System.out.println("key " + secretKey);
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) > 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}
public void decryptFile(File srcFile, File destFile) {
try (
InputStream is = new FileInputStream(srcFile);
OutputStream out = new FileOutputStream(destFile);
CipherInputStream cis = new CipherInputStream(is, dcipher)
) {
// Extract IV
byte[] iv = new byte[IV_SIZE];
is.read(iv, 0, IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = cis.read(buffer)) > 0) {
out.write(buffer, 0, bytesRead);
}
} catch ( InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}
}
package demo;
import java.io.*;
public class Client {
public static void main(String [] args){
File tempFile =null, src = null, dest = null;
try {
tempFile = new File("temp.txt");
src = new File("C:\\Users\\x\\Desktop\\test.txt");
dest = new File("C:\\Users\\x\\Desktop\\out.txt");
TestEncryption encryption = new TestEncryption("helloworld", 256);
encryption.encryptFile(src, tempFile);
encryption.decryptFile(tempFile, dest);
}
finally {
tempFile.delete();
//src.delete();
//dest.delete();
}
}
}
Your error is the way to use your streams when encrypting:
For a CipherOutputStream it is essential to be closed at the end because only when it is closed the final padding can be written.
In your code however the cipherOutputStream instance is never closed. hence the padding is never written to the encrypted file.
Of course when decrypting the file there is no padding where a padding should be and you are getting the BadPaddingException.
Therefore you should change the encyrption to this:
public void encryptFile(File src, File dest) {
try (InputStream inputStream = new FileInputStream(src);
OutputStream outputStream = new FileOutputStream(dest)) {
try (CipherOutputStream cipherOutputStream = new CipherOutputStream(outputStream, ecipher)) {
// Generating IV.
byte[] iv = new byte[IV_SIZE];
SecureRandom random = new SecureRandom();
random.nextBytes(iv);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// First write the IV at the beginning of the encrypted file.
outputStream.write(iv, 0, IV_SIZE);
System.out.println("key 0x" + new BigInteger(1, secretKey.getEncoded()).toString(16));
// Initialize cipher with IV
ecipher.init(Cipher.ENCRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
// Encrypt input file and write in to output
while ((bytesRead = inputStream.read(buffer)) >= 0) {
cipherOutputStream.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error encryption" + e.getMessage());
e.printStackTrace();
}
}
public void decryptFile(File srcFile, File destFile) {
try (InputStream is = new FileInputStream(srcFile); OutputStream out = new FileOutputStream(destFile)) {
try (CipherInputStream cis = new CipherInputStream(is, dcipher)) {
// Extract IV
byte[] iv = is.readNBytes(IV_SIZE);
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
// Initialize cypher with IV
dcipher.init(Cipher.DECRYPT_MODE, secretKey, ivParameterSpec);
byte[] buffer = new byte[BUFFER_SIZE];
int bytesRead;
while ((bytesRead = cis.read(buffer)) >= 0) {
out.write(buffer, 0, bytesRead);
}
}
} catch (InvalidKeyException | InvalidAlgorithmParameterException | IOException e) {
System.out.println("error decr" + e.getMessage());
e.printStackTrace();
}
}
There is another reason that probably the content which you need to description, but the arguments is null when passed to the mathod, it will be throw you a badpaddedException as well.
I wanted to try out the code from Java In A Nutshell book (3rd edition), but when I'm trying to run it, I'm getting java.lang.ArrayIndexOutOfBoundsException: 1 error. I found that info:
Thrown to indicate that an array has been accessed with an illegal index. The index is either negative or greater than or equal to the size of the array.
but unfortunately I am still not able to find and fix it
package tripledes;
import javax.crypto.*;
import javax.crypto.spec.*;
import java.security.*;
import java.security.spec.*;
import java.io.*;
public class TripleDES {
public static void main(String[] args) {
try {
try {
Cipher c = Cipher.getInstance("DESede");
} catch (Exception e) {
System.err.println("Installing SunJCE provicer");
Provider sunjce = new com.sun.crypto.provider.SunJCE();
Security.addProvider(sunjce);
}
File keyfile = new File(args[1]);
if (args[0].equals("-g")) {
System.out.println("Generating key. This may take some time...");
System.out.flush();
SecretKey key = generateKey();
writeKey(key, keyfile);
System.out.println("Done");
System.out.println("Secret key written to " + args[1] + ". Protect that file!");
} else if (args[0].equals("-e")) {
SecretKey key = readKey(keyfile);
encrypt(key, System.in, System.out);
} else if (args[0].equals("-d")) {
SecretKey key = readKey(keyfile);
decrypt(key, System.in, System.out);
}
} catch (Exception e) {
System.err.println(e);
System.err.println("Usage: java " + TripleDES.class.getName() + "-d|-e|-g <keyfile>");
}
}
public static SecretKey generateKey() throws NoSuchAlgorithmException {
KeyGenerator keygen = KeyGenerator.getInstance("DESede");
return keygen.generateKey();
}
public static void writeKey(SecretKey key, File f) throws IOException, NoSuchAlgorithmException, InvalidKeySpecException {
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
DESedeKeySpec keyspec = (DESedeKeySpec) keyfactory.getKeySpec(key, DESedeKeySpec.class);
byte[] rawkey = keyspec.getKey();
FileOutputStream out = new FileOutputStream(f);
out.write(rawkey);
out.close();
}
public static SecretKey readKey(File f) throws IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidKeySpecException {
DataInputStream in = new DataInputStream(new FileInputStream(f));
byte[] rawkey = new byte[(int) f.length()];
in.readFully(rawkey);
in.close();
DESedeKeySpec keyspec = new DESedeKeySpec(rawkey);
SecretKeyFactory keyfactory = SecretKeyFactory.getInstance("DESede");
SecretKey key = keyfactory.generateSecret(keyspec);
return key;
}
public static void encrypt(SecretKey key, InputStream in, OutputStream out)
throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IOException {
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.ENCRYPT_MODE, key);
CipherOutputStream cos = new CipherOutputStream(out, cipher);
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
cos.write(buffer, 0, bytesRead);
}
cos.close();
java.util.Arrays.fill(buffer, (byte) 0);
}
public static void decrypt(SecretKey key, InputStream in, OutputStream out)
throws NoSuchAlgorithmException, InvalidKeyException, IOException, IllegalBlockSizeException,
NoSuchPaddingException, BadPaddingException {
Cipher cipher = Cipher.getInstance("DESede");
cipher.init(Cipher.DECRYPT_MODE, key);
byte[] buffer = new byte[2048];
int bytesRead;
while ((bytesRead = in.read(buffer)) != -1) {
out.write(cipher.update(buffer, 0, bytesRead));
}
out.write(cipher.doFinal());
out.flush();
}
}
Could be when you access the args array. Such as:
File keyfile = new File(args[1]);
If you have no arguments to your program then this would be an ArrayIndexOutOfBoundsException.
I have been trying for two days to decrypt a file whith the private key containing 'lolilol' after having encrypted it with the public key rsa 4096. I then get padding errors, I tried everything to do, I get the error Javax.crypto.BadPaddingException: Decryption error.
Even after reading the doc on the padding I did not succeed: encryption works fine, but decryption contains an error.
Here is my code:
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import javax.crypto.Cipher;
import sun.misc.BASE64Encoder;
public class GenerateRSAKeys{
private Key pubKey;
private Key privKey;
public static void main(String[] args)
{
String input = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext";
String output = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext.enc";
String dec = "C:\\Users\\toto\\Desktop\\nomFichier_entrant.ext.dec";
String publicKeyFilename = "C:\\Users\\toto\\Desktop\\HR_pubkey_prd.pem";
String privateKeyFilename = "C:\\Users\\toto\\Desktop\\PE_privkey_prd.pem";
GenerateRSAKeys generateRSAKeys = new GenerateRSAKeys();
/* if (args.length < 2)
{
System.err.println("Usage: java "+ generateRSAKeys.getClass().getName()+
" Public_Key_Filename Private_Key_Filename");
System.exit(1);
}
publicKeyFilename = args[0].trim();
privateKeyFilename = args[1].trim(); */
generateRSAKeys.generate(publicKeyFilename, privateKeyFilename);
//generateRSAKeys.encrypt(input, output);
generateRSAKeys.encrypt(input, output);
generateRSAKeys.decrypt(output, dec);
}
private void generate (String publicKeyFilename, String privateFilename){
try {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
// Create the public and private keys
KeyPairGenerator generator = KeyPairGenerator.getInstance("RSA", "BC");
BASE64Encoder b64 = new BASE64Encoder();
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
/* SecureRandom random = new SecureRandom();
keyGen.initialize(4096, random);
KeyPair pair = keyGen.generateKeyPair();
pubKey = pair.getPublic();
privKey = pair.getPrivate(); */
SecureRandom random = createFixedRandom();
generator.initialize(4096, random);
KeyPair pair = generator.generateKeyPair();
pubKey = pair.getPublic();
privKey = pair.getPrivate();
System.out.println("publicKey : " + b64.encode(pubKey.getEncoded()));
System.out.println("privateKey : " + b64.encode(privKey.getEncoded()));
BufferedWriter out = new BufferedWriter(new FileWriter(publicKeyFilename));
out.write(b64.encode(pubKey.getEncoded()));
out.close();
out = new BufferedWriter(new FileWriter(privateFilename));
out.write(b64.encode(privKey.getEncoded()));
out.close();
}
catch (Exception e) {
System.out.println(e);
}
}
public static SecureRandom createFixedRandom()
{
return new FixedRand();
}
private static class FixedRand extends SecureRandom {
MessageDigest sha;
byte[] state;
FixedRand() {
try
{
this.sha = MessageDigest.getInstance("SHA-1");
this.state = sha.digest();
}
catch (NoSuchAlgorithmException e)
{
throw new RuntimeException("can't find SHA-1!");
}
}
public void nextBytes(byte[] bytes){
int off = 0;
sha.update(state);
while (off < bytes.length)
{
state = sha.digest();
if (bytes.length - off > state.length)
{
System.arraycopy(state, 0, bytes, off, state.length);
}
else
{
System.arraycopy(state, 0, bytes, off, bytes.length - off);
}
off += state.length;
sha.update(state);
}
}
}
public void encrypt(String input, String output) {
File outputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
outputFile = new File(output);
inputStream = new FileInputStream(input);
outputStream = new FileOutputStream(outputFile);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
inputBytes = new byte[(int) input.length()];
inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes);
outputStream.write(outputBytes);
// System.out.println(new String(inputBytes, "UTF-8"));
System.out.println("encrypt");
System.out.println(new String(outputBytes, "UTF-8"));
System.out.println("fin encrypt");
} catch (Exception e) {
e.printStackTrace();
}
}
public void decrypt(String input, String output) {
File outputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
outputFile = new File(output);
inputStream = new FileInputStream(input);
outputStream = new FileOutputStream(outputFile);
cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privKey);
inputBytes = new byte[(int) input.length()];
inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes);
outputStream.write(outputBytes);
// System.out.println(new String(inputBytes, "UTF-8"));
System.out.println("decrypt");
System.out.println(new String(outputBytes, "UTF-8"));
System.out.println("fin decrypt");
} catch (Exception e) {
e.printStackTrace();
}
}
}
You have multiple issues in your code:
You're never closing the file streams. If you don't do that, it might happen that no data is actually written. If the ciphertext is not (fully) written then the decryption will obviously fail.
A FileInputStream doesn't give an accurate measure of how much data the underlying file contains. You have to use the File class for that:
File inputFile = new File(input);
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(output);
byte[] inputBytes = new byte[(int) inputFile.length()];
When you're reading file contents, you must always check how much you read and use exactly that amount:
int readBytes = inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
Always use a fully qualified Cipher string. Cipher.getInstance("RSA"); may result in different ciphers depending on the default security provider. In OpenJDK it defaults to Cipher.getInstance("RSA/ECB/PKCS1Padding");. Nowadays, you should use OAEP instead of the default PKCS#1 v1.5 padding. So you should probably use Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");.
Here is the full code of those two methods:
public void encrypt(String input, String output) {
File inputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
System.out.println("encrypt");
cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
inputFile = new File(input);
inputStream = new FileInputStream(inputFile);
outputStream = new FileOutputStream(output);
inputBytes = new byte[(int) input.length()];
int readBytes = inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
outputStream.write(outputBytes);
System.out.println("fin encrypt");
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
public void decrypt(String input, String output) {
File inputFile;
FileInputStream inputStream;
FileOutputStream outputStream;
Cipher cipher;
byte[] inputBytes;
byte[] outputBytes;
try {
System.out.println("decrypt");
cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
cipher.init(Cipher.DECRYPT_MODE, privKey);
inputFile = new File(input);
inputStream = new FileInputStream(inputFile);
outputStream = new FileOutputStream(output);
inputBytes = new byte[(int) inputFile.length()];
int readBytes = inputStream.read(inputBytes);
outputBytes = cipher.doFinal(inputBytes, 0, readBytes);
outputStream.write(outputBytes);
System.out.println("Decryption result: " + new String(outputBytes, "UTF-8"));
System.out.println("fin decrypt");
inputStream.close();
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
I am using the following code to encrypt/decrypt:
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
public class CryptoUtils {
private static final String ALGORITHM = "AES";
private static final String TRANSFORMATION = "AES";
public static void encrypt(String key, File inputFile, File outputFile)
throws CryptoException {
doCrypto(Cipher.ENCRYPT_MODE, key, inputFile, outputFile);
}
public static void decrypt(String key, File inputFile, File outputFile)
throws CryptoException {
doCrypto(Cipher.DECRYPT_MODE, key, inputFile, outputFile);
}
private static void doCrypto(int cipherMode, String key, File inputFile,
File outputFile) throws CryptoException {
try {
Key secretKey = new SecretKeySpec(key.getBytes(), ALGORITHM);
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5PAdding");
cipher.init(cipherMode, secretKey);
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes);
FileOutputStream outputStream = new FileOutputStream(outputFile);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException
| InvalidKeyException | BadPaddingException
| IllegalBlockSizeException | IOException ex) {
throw new CryptoException("Error encrypting/decrypting file", ex);
}
}
public static class CryptoException extends Exception {
public CryptoException() {
}
public CryptoException(String message, Throwable throwable) {
super(message, throwable);
}
}
}
I can both encrypt and decrypt a video file.
However, I am not able to play the decrypted file, encrypted by the same code.
The original file: http://www.megafileupload.com/hSTZ/a.mp4
The encrypted file: http://www.megafileupload.com/hSU2/encrypted-a.mp4
The decrypted file: http://www.megafileupload.com/hSU1/decrypted-final-a.mp4
The first 16 bytes of the decrypted file are different from the original file. The length is the same.
You're assuming that:
The file fits into memory.
The file size fits into an int.
read() fills the buffer.
The result of encryption or decryption fits into memory along with the source content.
There's no need for any of these assumptions.
FileInputStream inputStream = new FileInputStream(inputFile);
FileOutputStream outputStream = new FileOutputStream(outputFile);
byte[] buffer = new byte[8192];
int count;
while ((count = in.read(buffer)) > 0)
{
byte[] output = cipher.update(buffer, 0, count);
outputStream.write(output);
}
outputStream.write(cipher.doFinal());
outputStream.close();
inputStream.close();
E&OE but you get the idea. You could make your life even simpler by using CipherInput/OutputStreams, but you lose touch with the crypto exceptions a bit that way.