I have an application which displays image downloaded from server. the image is encrypted and kept in the server using AES. I need to decrypt the image at the client side. The code used for encryption is as follows
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.MessageDigest;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import javax.imageio.ImageIO;
public class Crypto {
Cipher ecipher;
Cipher dcipher;
/**
* Input a string that will be md5 hashed to create the key.
* #return void, cipher initialized
*/
public Crypto(){
try{
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(128);
this.setupCrypto(kgen.generateKey());
} catch (Exception e) {
e.printStackTrace();
}
}
public Crypto(String key){
SecretKeySpec skey = new SecretKeySpec(getMD5(key), "AES");
this.setupCrypto(skey);
}
private void setupCrypto(SecretKey key){
try
{ Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
ecipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
dcipher = Cipher.getInstance("AES/ECB/PKCS7Padding", "BC");
ecipher.init(Cipher.ENCRYPT_MODE, key);
dcipher.init(Cipher.DECRYPT_MODE, key);
}
catch (Exception e)
{
e.printStackTrace();
}
}
// Buffer used to transport the bytes from one stream to another
byte[] buf = new byte[1024];
public void encrypt(InputStream in, OutputStream out){
try {
// Bytes written to out will be encrypted
out = new CipherOutputStream(out, ecipher);
// Read in the cleartext bytes and write to out to encrypt
int numRead = 0;
while ((numRead = in.read(buf)) >= 0){
out.write(buf, 0, numRead);
}
out.close();
}
catch (java.io.IOException e){
e.printStackTrace();
}
}
public void decrypt(InputStream in, OutputStream out){
try {
// Bytes read from in will be decrypted
in = new CipherInputStream(in, dcipher);
// Read in the decrypted bytes and write the cleartext to out
int numRead = 0;
while ((numRead = in.read(buf)) >= 0) {
out.write(buf, 0, numRead);
}
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
private static byte[] getMD5(String input){
try{
byte[] bytesOfMessage = input.getBytes("UTF-8");
MessageDigest md = MessageDigest.getInstance("MD5");
return md.digest(bytesOfMessage);
} catch (Exception e){
return null;
}
}
public static void main(String args[]){
try {
Crypto encrypter = new Crypto("yursxjdlbkuikeqe"); ///key for decryption logic
encrypter.encrypt(new FileInputStream("D:\\Path\\Lighthouse.jpg"),new FileOutputStream("D:\\Encryption\\iOS code base\\Lighthouse.jpg.pkcs5"));
encrypter.decrypt(new FileInputStream("D:\\Path\\Lighthouse.jpg.pkcs5"),new FileOutputStream("D:\\Encryption\\iOS code base\\Lighthouse.jpg"));
System.out.println("DONE");
}
catch (Exception e) {
e.printStackTrace();
}
}
}
I am not able to decrypt this using Blackberry AESDecryptor Engine. I am new to this crypto graphy. Is it possible to decrypt using AESDecryptor engine. I am attaching the code which I am using. Please help me in solving this
public MyScreen(){
// Set the displayed title of the screen
setTitle("MyTitle");
byte[] keyData = new String("yursxjdlbkuikeqe").getBytes();
byte[] cipherText = openFile("file:///SDCard/Lighthouse.jpg.pkcs5");
try {
imageData = decrypt(keyData, cipherText);
} catch (CryptoException e) {
System.out.println("::::::::::::::::::::::::::::::::::Crypto Exception:::::::"+e.getMessage());
} catch (IOException e) {
System.out.println("::::::::::::::::::::::::::::::::::IO Exception:::::::"+e.getMessage());
}
if(imageData!=null){
writeByteData(imageData);
// EncodedImage image = EncodedImage.createEncodedImage(imageData, 0, imageData.length);
// add(new BitmapField(image.getBitmap()));
System.out.println("------------------Image saved successfully-----------");
}else{
System.out.println("-------------------Image Data is null");
}
}
public static byte[] decrypt(byte[] keyData, byte[] ciphertext) throws CryptoException, IOException {
// First, create the AESKey again.
/*String str=new String(keyData);
System.out.println(str);*/
AESKey key = new AESKey(keyData,0,128);
System.out.println("Key is ::"+key.getAlgorithm()+"Length:"+key.getBitLength());
//
// // Now, create the decryptor engine.
AESDecryptorEngine engine = new AESDecryptorEngine(key);
PKCS5UnformatterEngine uengine = new PKCS5UnformatterEngine(engine);
/
// // Create the BlockDecryptor to hide the decryption details away.
ByteArrayInputStream input = new ByteArrayInputStream(ciphertext);
BlockDecryptor decryptor = new BlockDecryptor(engine, input);
byte[] plaintextAndHash = new byte[1024];
ByteArrayOutputStream output = new ByteArrayOutputStream();
int bytesRead=0;
do{
bytesRead =decryptor.read(plaintextAndHash);
if(bytesRead!=-1){
output.write(plaintextAndHash,0,bytesRead);
}
}
while(bytesRead!=-1);
return output.toByteArray();
}
You don't really say what your problem is, but at least the following line looks incorrect:
BlockDecryptor decryptor = new BlockDecryptor(engine, input);
It should be
BlockDecryptor decryptor = new BlockDecryptor(uengine, input);
I just changed engine to uengine
RIM's APIs make this pretty easy but it is a little tough to find the documentation. Check out the Javadocs for the package net.rim.device.api.crypto at:
http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/crypto/package-summary.html
You should look through all of it but the answer is in number 7: Encryptor and decryptor factories.
http://www.blackberry.com/developers/docs/7.0.0api/net/rim/device/api/crypto/doc-files/factories.html
The DecryptorFactory can create an input stream that you can just read as any InputStream.
Related
I am trying to make this code work to encrypt an image using AES algorithm and its modes, then view the encrypted image.
So the bytes of the header is not encrypted and the content was. When writing the image to the new file, the header was used first and then the encrypted content so that we can open it as an image file.
But I am unable to open it. Any help would be appreciated. I am new to coding, learning as I go :)
Thanks
enter code here
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.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
public class test {
private static SecretKeySpec secretKey ;
private static byte[] key ;
static String encodekey = "770A8A65DA156D24EE2A093277530142";
static String IV = "AAAAAAAAAAAAAAAA";
public static void main(String[] args) {
encrypt(new File("/Users/uni/IdeaProjects/ExtendedExperimentalAPI”/src/image.jpeg"));
}
public static void encrypt(File file){
setKey(encodekey);
String fileName = file.getName();
byte[] fileBytes = fileToBytes(file);
//save the header from file so it is accessible as image after encryption
byte[] header = new byte[55];
for(int i = 0; i<55; i++){
header[i] = fileBytes[i];
}
byte[] toEncrypt = Arrays.copyOfRange(fileBytes, 55, fileBytes.length);
Cipher cipher;
try {
//block to encrypt using ECB and save file
cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
byte[] cipherDataECB = cipher.doFinal(toEncrypt);
FileOutputStream fos = new FileOutputStream("ECB" + fileName, true);//append to file
fos.write(header);
fos.write(cipherDataECB);
fos.close();
//block to encrypt using CBC and save file
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey,new IvParameterSpec(IV.getBytes("UTF-8")));
byte[] cipherDataCBC = cipher.doFinal(toEncrypt);
fos = new FileOutputStream("CBC" + fileName, true);
fos.write(header);
fos.write(cipherDataCBC);
fos.close();
//block to encrypt using CFB and save file
cipher = Cipher.getInstance("AES/CFB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, secretKey,new IvParameterSpec(IV.getBytes("UTF-8")));
byte[] cipherDataCFB = cipher.doFinal(toEncrypt);
fos = new FileOutputStream("CFB" + fileName, true);//append to file
fos.write(header);
fos.write(cipherDataCFB);
fos.close();
} catch (InvalidAlgorithmParameterException | NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | FileNotFoundException e) {
System.out.println("Error while encrypting file");
} catch (IOException e) {
System.out.println("Error writing to the file");
}
}
static void setKey(String myKey){
MessageDigest sha = null;
try {
key = myKey.getBytes("UTF-8");
sha = MessageDigest.getInstance("SHA-1");
key = sha.digest(key);
key = Arrays.copyOf(key, 16); // use only first 128 bit
secretKey = new SecretKeySpec(key, "AES");
} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
System.out.println("Error setting the key for encryption");
}
}
static byte[] fileToBytes(File file){
FileInputStream fileInputStream=null;
byte[] bFile = new byte[(int) file.length()];
//convert file into array of bytes
try{
fileInputStream = new FileInputStream(file);
fileInputStream.read(bFile);
fileInputStream.close();
} catch(FileNotFoundException e){
System.out.println("Specified file not found");
} catch (IOException e) {
System.out.println("Error reading from the file");
}
return bFile;
}
}
I have a web app which is deployed on tomcat in both Linux and windows environment . Blowfish algo has been implemented for login password encryption/security check. It works fine in windows but throws illegal key size exception in linux. key file is packed with war
I have gone through multiple post but nothing really helped me.
generating key file
/** Generate a secret TripleDES encryption/decryption key */
KeyGenerator keygen = KeyGenerator.getInstance(SecurityConstant.BLOW_FISH_ALGO);
// Use it to generate a key
SecretKey key = keygen.generateKey();
// Convert the secret key to an array of bytes like this
byte[] rawKey = key.getEncoded();
// Write the raw key to the file
String keyPath = getBlowFishKeyPath();
FileOutputStream out = new FileOutputStream(keyPath);
Writer writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
Files.write( Paths.get(keyPath),rawkey,StandardOpenOption.CREATE);
writer.close();
key comparision
String hexCipher = null;
try {
byte[] byteClearText = pwd.getBytes("UTF-8");
byte[] ivBytes = SecurityUtil.hexToBytes("0000000000000000");
// read secretkey from key file
byte[] secretKeyByte = secretKey.getBytes();
Cipher cipher = null;
SecretKeySpec key = new SecretKeySpec(secretKeyByte, SecurityConstant.BLOW_FISH_ALGO);
// Create and initialize the encryption engine
cipher = Cipher.getInstance(SecurityConstant.BLOW_FISH_CBC_ZEROBYTE_ALGO, SecurityConstant.BC);
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // throws exception
byte[] cipherText = new byte[cipher.getOutputSize(byteClearText.length)];
int ctLength = cipher.update(byteClearText, 0, byteClearText.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
hexCipher = SecurityUtil.bytesToHex(cipherText);// hexdecimal password stored in DB
} catch (Exception e) {
ExceptionLogger.logException(logger, e);
}
made it simpler to test
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.io.Writer;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.NoSuchAlgorithmException;
import java.security.Security;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.io.FileUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
public class SecTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
/** Generate a secret TripleDES encryption/decryption key */
Security.addProvider(new BouncyCastleProvider());
KeyGenerator keygen = KeyGenerator.getInstance("Blowfish");
// Use it to generate a key
SecretKey key = keygen.generateKey();
// Convert the secret key to an array of bytes like this
byte[] rawKey = key.getEncoded();
// Write the raw key to the file
String keyPath = "/data2/key/BlowFish.key";
FileOutputStream out = null;
try {
out = new FileOutputStream(keyPath);
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Writer writer = null;
try {
writer = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"));
Files.write( Paths.get(keyPath),rawKey,StandardOpenOption.CREATE);
writer.close();
out.close();
} catch (UnsupportedEncodingException e1) {
e1.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
generateHexCode("a");
}
private static void generateHexCode(String pwd) {
String hexCipher = null;
try {
byte[] byteClearText = pwd.getBytes("UTF-8");
byte[] ivBytes = hexToBytes("0000000000000000");
// read secretkey from key file
byte[] secretKeyByte = readSecretKey().getBytes();
Cipher cipher = null;
SecretKeySpec key = new SecretKeySpec(secretKeyByte, "Blowfish");
// Create and initialize the encryption engine
cipher = Cipher.getInstance("Blowfish/CBC/ZeroBytePadding", "BC");
IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
cipher.init(Cipher.ENCRYPT_MODE, key, ivSpec); // throws exception
byte[] cipherText = new byte[cipher.getOutputSize(byteClearText.length)];
int ctLength = cipher.update(byteClearText, 0, byteClearText.length, cipherText, 0);
ctLength += cipher.doFinal(cipherText, ctLength);
hexCipher = bytesToHex(cipherText);// hexdecimal password stored in DB
System.out.println("hex cipher is "+hexCipher);
} catch (Exception e) {
e.printStackTrace();
}
}
private static String readSecretKey() {
byte[] rawkey = null;
String file ="";
// Read the raw bytes from the keyfile
String keyFile = "/data2/key/BlowFish.key";
String is = null;
try {
is = FileUtils.readFileToString(new File(keyFile),"UTF-8");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return is;
}
public static byte[] hexToBytes(String str) {
byte[] bytes = null;
if (str != null && str.length() >= 2) {
int len = str.length() / 2;
byte[] buffer = new byte[len];
for (int i = 0; i < len; i++) {
buffer[i] = (byte) Integer.parseInt(str.substring(i * 2, i * 2 + 2), 16);
}
bytes = buffer;
}
return bytes;
}
public static String bytesToHex(byte[] data) {
if (data == null) {
return null;
} else {
int len = data.length;
StringBuilder str = new StringBuilder();
for (int i = 0; i < len; i++) {
if ((data[i] & 0xFF) < 16) {
str = str.append("0").append(java.lang.Integer.toHexString(data[i] & 0xFF));
} else {
str.append(java.lang.Integer.toHexString(data[i] & 0xFF));
}
}
return str.toString().toUpperCase();
}
}
}
Made a simple program to test it out . This also runs fine on windows but fails on linux. any clue ?
I am working on a Encryption/Decryption program in Java. I am using a key called "secret1234" to encrypt and decrypt a message from a text file. This program uses a string for the key. However, I am interested in using a number (integer) for the key so I can generate random numbers. So, how can this program be modified to allow the key to be an integer and not a string for encrypting and descrypting the message?
This is the program:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.crypto.Cipher;
import javax.crypto.CipherInputStream;
import javax.crypto.CipherOutputStream;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
public class Program {
public static void main(String[] args) {
try {
String key = "secret1234";// This is the key
FileInputStream fis = new FileInputStream("text.txt");//text.txt is a text file with a short message
FileOutputStream fos = new FileOutputStream("encryptedText.txt");
encrypt(key, fis, fos);
FileInputStream fis2 = new FileInputStream("encryptedText.txt");
FileOutputStream fos2 = new FileOutputStream("decryptedText.txt");
decrypt(key, fis2, fos2);
} catch (Throwable e) {
e.printStackTrace();
}
}
public static void encrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.ENCRYPT_MODE, is, os);
}
public static void decrypt(String key, InputStream is, OutputStream os) throws Throwable {
encryptOrDecrypt(key, Cipher.DECRYPT_MODE, is, os);
}
public static void encryptOrDecrypt(String key, int mode, InputStream is, OutputStream os) throws Throwable {
DESKeySpec dks = new DESKeySpec(key.getBytes());
SecretKeyFactory skf = SecretKeyFactory.getInstance("DES");
SecretKey desKey = skf.generateSecret(dks);
Cipher cipher = Cipher.getInstance("DES");
if (mode == Cipher.ENCRYPT_MODE) {
cipher.init(Cipher.ENCRYPT_MODE, desKey);
CipherInputStream cis = new CipherInputStream(is, cipher);
doCopy(cis, os);
} else if (mode == Cipher.DECRYPT_MODE) {
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherOutputStream cos = new CipherOutputStream(os, cipher);
doCopy(is, cos);
}
}
public static void doCopy(InputStream is, OutputStream os) throws IOException {
byte[] bytes = new byte[64];
int numBytes;
while ((numBytes = is.read(bytes)) != -1) {
os.write(bytes, 0, numBytes);
}
os.flush();
os.close();
is.close();
}
}
Use this in your code to generate the key:
String key = String.valueOf(SecureRandom.getInstance("SHA1PRNG").nextInt());
I have this strange issue with java IO, in combination with AES encryption.
I am writing some encrypted text to a binary file, appending \n at the end of text. Say,
my beautiful string...
look! Another of my beautiful strings...
When I read the data back, I get the following text in return with a lot of extra tabs:
my beautiful string...
look! Another of my beautiful strings...
Here is my self-contained code:
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
public class SecurityUtil
{
public static final String ENCRYPTION_ALGORITHM = "AES";
public static final String CHARACTER_SET = "UTF-8";
private static final int BLOCKS = 128;
private static final String KEY = "SomeSortOfEncryptionKey";
public static void main (String[] args) throws IOException
{
String str = "my beautiful string...\n";
byte[] encrypt = SecurityUtil.encrypt (str);
File f = new File ("C:\\myfile.dat");
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(f, true));
bos.write(encrypt);
bos.flush();
bos.close();
str = "look! Another of my beautiful strings...";
encrypt = SecurityUtil.encrypt (str);
bos = new BufferedOutputStream(new FileOutputStream(f, true));
bos.write(encrypt);
bos.flush();
bos.close();
byte[] buffer = new byte[(int) f.length ()];
FileInputStream fis = new FileInputStream (f);
fis.read (buffer);
fis.close ();
String decrypt = SecurityUtil.decrypt (buffer);
System.out.println(decrypt);
}
public static byte[] encrypt (String text)
{
try
{
byte[] rawKey = getRawKey (KEY.getBytes (CHARACTER_SET));
SecretKeySpec skeySpec = new SecretKeySpec (rawKey, ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance (ENCRYPTION_ALGORITHM);
cipher.init (Cipher.ENCRYPT_MODE, skeySpec);
return cipher.doFinal (text.getBytes (CHARACTER_SET));
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace ();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace ();
}
catch (BadPaddingException e)
{
e.printStackTrace ();
}
catch (InvalidKeyException e)
{
e.printStackTrace ();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace ();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace ();
}
return null;
}
public static String decrypt (byte[] data)
{
try
{
byte[] rawKey = getRawKey (KEY.getBytes (CHARACTER_SET));
SecretKeySpec skeySpec = new SecretKeySpec (rawKey, ENCRYPTION_ALGORITHM);
Cipher cipher = Cipher.getInstance (ENCRYPTION_ALGORITHM);
cipher.init (Cipher.DECRYPT_MODE, skeySpec);
byte[] decrypted = cipher.doFinal (data);
return new String (decrypted);
}
catch (UnsupportedEncodingException e)
{
e.printStackTrace ();
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace ();
}
catch (NoSuchPaddingException e)
{
e.printStackTrace ();
}
catch (InvalidKeyException e)
{
e.printStackTrace ();
}
catch (IllegalBlockSizeException e)
{
e.printStackTrace ();
}
catch (BadPaddingException e)
{
e.printStackTrace ();
}
return null;
}
private static byte[] getRawKey (byte[] seed)
{
try
{
KeyGenerator kgen = KeyGenerator.getInstance (ENCRYPTION_ALGORITHM);
SecureRandom sr = SecureRandom.getInstance ("SHA1PRNG");
sr.setSeed (seed);
kgen.init (BLOCKS, sr);
SecretKey skey = kgen.generateKey ();
byte[] raw = skey.getEncoded ();
return raw;
}
catch (NoSuchAlgorithmException e)
{
e.printStackTrace ();
}
return null;
}
}
Here is the console output (with extra spaces):
my beautiful string...
look! Another of my beautiful strings...
What am I doing wrong?
Ok! I got it. You cannot just append the encrypted text to a file. One way of solving this is extracting existing text from the file, append the new text, encrypt and write in the file again.
This doesn't seem to be a good solution, but in my case, where there is little text in a file, this can work.
I'm doing a simple encryption file transfer system and now stopped by a run time exception:
Exception in thread "main" javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.AESCipher.engineDoFinal(AESCipher.java:313)
at javax.crypto.Cipher.doFinal(Cipher.java:2087)
at ftpclient.FTPClient.main(FTPClient.java:82)
I tried to debug my code using a string to encrypt and decrypt with the same key and it works. However, when I tried to transfer stream from the file, this exception always comes.
Here are the codes of both sides. At first they will exchange symmetric key (AES key) via RSA and then transfer large files via AES encryption. We can focus on the last part of each code where the files are encrypted and decrypted by AES key.
Server Side:
package ftpserver;
import java.io.*;
import java.net.*;
import javax.crypto.*;
import java.security.*;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
*
* #author Han
*/
public class FTPServer {
public static void main(String[] args) throws Exception {
//generate symmetric key and initialize cipher for AES
SecretKey skey = null;
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
KeyGenerator kg = KeyGenerator.getInstance("AES");
kg.init(128);
skey = kg.generateKey();
//get public key of the receive side
final String PUBLIC_KEY_PATH = "key_b.public";
PublicKey publickey = null;
try {
FileInputStream fis;
fis = new FileInputStream(PUBLIC_KEY_PATH);
ObjectInputStream oin = new ObjectInputStream(fis);
publickey = (PublicKey) oin.readObject();
oin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
};
//encrypte symmetric key with own private key and send out
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.ENCRYPT_MODE, publickey);
byte cipherSKey[] = rsa.doFinal(skey.getEncoded());
//System.out.println(skey); //debug
//create tcp server socket
ServerSocket tcp = new ServerSocket(2000);
Socket client = tcp.accept();
//get input&output stream from the TCP connection
InputStream in = client.getInputStream();
OutputStream out = client.getOutputStream();
//generate a file input stream to get stream from file
File sentFile = new File("F:\\test.txt");
FileInputStream fin = new FileInputStream(sentFile);
//send encrypted symmetric key first
out.write("Symmetric Key:\r\n".getBytes());
out.write(cipherSKey);
DataInputStream din = new DataInputStream(in);
while(true)
{
if(din.readLine().equals("Received."))
{
System.out.println("Send key successfully.");
break;
}
};
//send files
int count;
byte[] bytearray = new byte[8192];
byte[] cipherbuffer;
while((count = fin.read(bytearray))>0)
{
cipherbuffer = Base64.encodeBase64(aes.doFinal(bytearray));
out.write(cipherbuffer,0,cipherbuffer.length);
System.out.println(count+" bytes have been sent.");
};
out.flush();
out.close();
client.close();
}
}
Client Side:
package ftpclient;
import java.io.*;
import java.net.*;
import java.security.PrivateKey;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.codec.binary.Base64;
/**
*
* #author Han
*/
public class FTPClient {
public static void main(String[] args) throws Exception
{
//get the private key of this side
final String PUBLIC_KEY_PATH = "key_b.privat";
PrivateKey privatkey = null;
try {
FileInputStream fis;
fis = new FileInputStream(PUBLIC_KEY_PATH);
ObjectInputStream oin = new ObjectInputStream(fis);
privatkey = (PrivateKey) oin.readObject();
oin.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
};
Cipher rsa = Cipher.getInstance("RSA");
rsa.init(Cipher.DECRYPT_MODE, privatkey);
//create tcp client socket
Socket tcp = new Socket("192.168.1.185",2000);
InputStream in = tcp.getInputStream();
OutputStream out = tcp.getOutputStream();
DataInputStream din = new DataInputStream(in);
//receive symmetric key from server
byte keybuffer[] = new byte[128];
SecretKey skey = null;
while(true)
{
if(din.readLine().equals("Symmetric Key:"))
{
System.out.println("Start to receiving key...");
in.read(keybuffer);
byte[] skeycode = rsa.doFinal(keybuffer);
skey = new SecretKeySpec(skeycode, 0, skeycode.length, "AES");
out.write("Received.\r\n".getBytes());
break;
}
};
//create cipher for symmetric decryption
Cipher aes = Cipher.getInstance("AES/ECB/PKCS5Padding");
aes.init(Cipher.DECRYPT_MODE, skey);
//System.out.println(skey); //debug
//create file stream
FileOutputStream fos = new FileOutputStream("E:\\test_cp.txt");
int count;
int i = 0;
byte[] bytearray = new byte[8192];
byte[] buffer;
while((count = in.read(bytearray)) > 0)
{
buffer = (aes.doFinal(Base64.decodeBase64(bytearray)));
fos.write(buffer,0,buffer.length);
i +=count;
System.out.println(i+" bytes have been received.");
};
fos.flush();
fos.close();
in.close();
tcp.close();
System.out.println("File Transfer completed");
}
}
you are calling doFinal multiple times. or at least trying to.
when you read data, not all data arrives or is read into the buffer at once. so you decrypt some and then read again. that is all ok.
but when you do that, you are calling doFinal each time, instead of update. this is wrong and is the cause of the error. instead, replace doFinal with update and then add an extra doFinal once you have finished reading all data (there is a doFinal() that takes no arguments for exactly this reason).
see http://docs.oracle.com/javase/7/docs/api/javax/crypto/Cipher.html
also see http://en.wikipedia.org/wiki/Block_cipher_mode_of_operation#Electronic_codebook_.28ECB.29 for why ecb mode is often not a good idea (look at the penguin pictures).