java.net.SocketException: Connection reset """ - java

I am tiring to send byte encrypted data over the socket, however, It does not work, the requirement is the server reads the key from file and receives an encrypted message from client
I am facing issues with Input/Output stream:I have used one variable that read file and sockets.
Server Code
import java.io.*;
import java.net.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.security.*;
import java.security.KeyStore.ProtectionParameter;
import java.security.KeyStore.SecretKeyEntry;
import javax.crypto.*;
import javax.crypto.spec.SecretKeySpec;
public class CipherServer
{
public static void main(String[] args) throws Exception
{
int port = 7999;
ServerSocket server = new ServerSocket(port);
Socket s = server.accept();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("KeyFile.xx"));
// YOU NEED TO DO THESE STEPS:
// -Read the key from the file generated by the client.
SecretKey desKey = (SecretKey)in.readObject();
// YOU NEED TO DO THESE STEPS:
ObjectOutputStream out = new ObjectOutputStream(s.getOutputStream());
in = new ObjectInputStream(s.getInputStream());
byte[] cipherText;
cipherText= (byte[]) in.readObject();
// -Use the key to decrypt the incoming message from socket s.
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, desKey);
CipherInputStream cipherIn = new CipherInputStream(s.getInputStream(), cipher);
System.out.println("Algorithm used to generate key : "+desKey.getAlgorithm());
byte[] plaintext = cipher.doFinal(cipherText);
// -Print out the decrypt String to see if it matches the orignal message.
System.out.println(plaintext.toString());
}
}
Client Code
import java.io.*;
import java.net.*;
import javax.crypto.*;
public class CipherClient
{
public static void main(String[] args) throws Exception
{
// YOU NEED TO DO THESE STEPS:
// -Generate a DES key.
KeyGenerator keygenerator = KeyGenerator.getInstance("DES");
SecretKey desKey = keygenerator.generateKey();
// -Store it in a file.
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("KeyFile.xx"));
out.writeObject(desKey);
String message = "The quick brown fox jumps over the lazy dog.";
int port = 7999;
Socket s = new Socket("127.0.0.1", port);
out = new ObjectOutputStream(s.getOutputStream());
//convert the massage to bits
byte[] messa= message.getBytes();
// -Use the key to encrypt the message above and send it over socket s to the server.
Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, desKey);
byte[] cipherText = cipher.doFinal(messa);
System.out.println(new String(cipherText));
// YOU NEED TO DO THESE STEPS:
// ObjectOutputStream.reset(cipherText);
out.write(cipherText);
}
}
I receive an ERROR Message at the server side
Exception in thread "main" java.net.SocketException: Connection reset
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:186)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:140)
at java.base/java.net.SocketInputStream.read(SocketInputStream.java:200)
at java.base/java.io.ObjectInputStream$PeekInputStream.peek(ObjectInputStream.java:2802)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.peek(ObjectInputStream.java:3129)
at java.base/java.io.ObjectInputStream$BlockDataInputStream.peekByte(ObjectInputStream.java:3139)
at java.base/java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1619)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:482)
at java.base/java.io.ObjectInputStream.readObject(ObjectInputStream.java:440)
at DES.CipherServer.main(CipherServer.java:77)

On the write side, you are calling OutputStream.write(byte[]), on the read side, you are calling readObject (then trying to convert that to a byte[]). If you are going to use ObjectStreams (which I highly discourage) you need to be consistant with writeObject and readObject on both sides

Related

Python Decrypting with Crypto: first 16 characters are gibberish

I am trying to decrypt a file that was encrypted in Java using AES/CBC/PKCS5Padding. However, I'm having some trouble completely decrypting the file. I think I'm missing something simple. I am pretty new to encryption, so this is highly probable:
import base64
import re
from Crypto import Random
from Crypto.Cipher import AES
# generate the key
passphrase = "my_secret_passphrase"
key = passphrase[0:16].encode()
# load in the encrypted file as bytes
file_name = "tbd/enc.csv"
with open(file_name, "rb") as in_file:
encrypted_bytes = in_file.read()
# initialize the cipher
iv = Random.new().read(AES.block_size)
cipher = AES.new(key, AES.MODE_CBC, iv)
# use the cipher to decrypt the bytes
decrypted_bytes = cipher.decrypt(encrypted_bytes)
# write to an out_file
file = re.sub("\.csv", "_decoded.csv", file)
with open(file, "wb") as binary_file:
binary_file.write(decrypted_bytes)
Here's a the first line of text from what I get:
M¢p†‘GW§'tÄ%èéired Date,Employees - Id,First,Employees - Middle,Last,Employees - Preferred Name,Job Title,Employees - Marital Status,Employees - Trade Code,...
I noticed that the first 16 chars are complete gibberish, so I know I'm close. What could I be missing that is causing the first 16 chars to not be decoded properly? The weird thing is that we are able to decrypt the entire file in java, so we know its something wrong with the python implementation.
Bonus Round: the java code used to encrypt the file (I did not code it nor do I know java):
package rpa.ipaengine.bots.cmic.test;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.SecretKeySpec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class TestFile {
private static Logger LOGGER = LoggerFactory.getLogger(TestFile.class);
public static void main(String[] args) {
LOGGER.info("running");
try {
Security.setProperty("crypto.policy", "unlimited");
encryptedFile("my_secret_passphrase", "/tbd/enc.csv", "tbd/dec.csv");
decryptedFile("my_secret_passphrase", "/tbd/enc.csv", "tbd/dec.csv");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void encryptedFile(String secretKey, String fileInputPath, String fileOutPath)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, IllegalBlockSizeException,
BadPaddingException {
try {
byte[] raw1 = "my_secret_passphrase"
.getBytes();
byte[] raw = new String(raw1, 0, 16).getBytes();
Key skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivParams);
var fileInput = new File(fileInputPath);
var inputStream = new FileInputStream(fileInput);
var inputBytes = new byte[(int) fileInput.length()];
inputStream.read(inputBytes);
var outputBytes = cipher.doFinal(inputBytes);
var fileEncryptOut = new File(fileOutPath);
var outputStream = new FileOutputStream(fileEncryptOut);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
System.out.println("File successfully encrypted!");
System.out.println("New File: " + fileOutPath);
} catch (Exception e) {
e.printStackTrace();
}
}
public static void decryptedFile(String secretKey, String fileInputPath, String fileOutPath)
throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IOException, IllegalBlockSizeException,
BadPaddingException, InvalidAlgorithmParameterException {
try {
byte[] raw1 = "my_secret_passphrase"
.getBytes();
byte[] raw = new String(raw1, 0, 16).getBytes();
Key skeySpec = new SecretKeySpec(raw, "AES");
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
byte[] iv = new byte[cipher.getBlockSize()];
IvParameterSpec ivParams = new IvParameterSpec(iv);
cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivParams);
var fileInput = new File(fileInputPath);
var inputStream = new FileInputStream(fileInput);
var inputBytes = new byte[(int) fileInput.length()];
inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes);
var fileEncryptOut = new File(fileOutPath);
var outputStream = new FileOutputStream(fileEncryptOut);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
System.out.println("File successfully decrypted!");
System.out.println("New File: " + fileOutPath);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Using bytes(16) as matt suggested, I was able to decipher the text completely:
import base64
import re
from Crypto import Random
from Crypto.Cipher import AES
# generate the key
passphrase = "my_secret_passphrase"
key = passphrase[0:16].encode()
# load in the encrypted file as bytes
file_name = "tbd/enc.csv"
with open(file_name, "rb") as in_file:
encrypted_bytes = in_file.read()
# initialize the cipher
iv = bytes(16)
cipher = AES.new(key, AES.MODE_CBC, iv)
# use the cipher to decrypt the bytes
decrypted_bytes = cipher.decrypt(encrypted_bytes)
# write to an out_file
file = re.sub("\.csv", "_decoded.csv", file)
with open(file, "wb") as binary_file:
binary_file.write(decrypted_bytes)
First line of file:
Employees - Hired Date,Employees - Id,First,Employees - Middle...
However Michael provides some valid comments about the Java code used to encrypt the file. I will work with my team to make sure its more secure.

Illegal Block Size Exception Input length must be multiple of 16 when decrypting with padded cipher when decrypting

I'm getting this error when I try to decrypt a message which has already been encrypted.
I've done this by first encrypting a message in this case "Testing message"
Then running the method again but decrypting instead of encrypting.
I've looked at the other questions regarding this but could not fix the problem
import java.nio.charset.StandardCharsets;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
public class PBEusing {
public static void main(String[] args) throws Exception {
PBEusing pbe = new PBEusing();
String encrypt = pbe.pbe("encrypt", "passwordTest", "Testing message");
System.out.println(encrypt);
String decrypt = pbe.pbe("decrypt", "passwordTest", encrypt);
System.out.println(decrypt);
}
public static String pbe(String cipherMethod, String clientPassword, String clientMessage) throws Exception {
String method = cipherMethod.toUpperCase();
String output = "";
SecureRandom rnd = new SecureRandom();
byte[] iv = new byte[16];
rnd.nextBytes(iv);
byte[] plaintext = clientMessage.getBytes(StandardCharsets.UTF_8); // input message from user
byte[] salt = "01234567".getBytes(StandardCharsets.UTF_8);
IvParameterSpec ivParamSpec = new IvParameterSpec(iv);
PBEParameterSpec pbeParamSpec = new PBEParameterSpec(salt, 10000, ivParamSpec);
PBEKeySpec keySpec = new PBEKeySpec(clientPassword.toCharArray());
try {
SecretKeyFactory kf = SecretKeyFactory.getInstance("PBEWithHmacSHA256AndAES_128");
SecretKey secretKey = kf.generateSecret(keySpec);
// On J2SE the SecretKeyfactory does not actually generate a key, it just wraps the password.
// The real encryption key is generated later on-the-fly when initializing the cipher
System.out.println(new String(secretKey.getEncoded()));
// Encrypt
if (method.equals("ENCRYPT")) {
Cipher enc = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
enc.init(Cipher.ENCRYPT_MODE, secretKey, pbeParamSpec);
byte[] encrypted = enc.doFinal(plaintext);
output = new BASE64Encoder().encode(encrypted);
System.out.println("Encrypted text: " + output);
} else {
// Decrypt
Cipher dec = Cipher.getInstance("PBEWithHmacSHA256AndAES_128");
dec.init(Cipher.DECRYPT_MODE, secretKey, pbeParamSpec);
byte[] decrypted = dec.doFinal(plaintext);
String test = new BASE64Encoder().encode(decrypted);
//String message = new String(test, StandardCharsets.UTF_8);
output = test;
}
} catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
}
return output;
}
}
You're Base64 encoding the output of the encryption but aren't Base64 decoding it again before you try to decrypt it.

Decrypting URL not working

The problem I am facing is that I could not get decrypted email when I call this REST service: http://localhost:8080/RestWebService/MM/decryptEmail
For more details I also add an image below.
I hope I have explained my question well
package client;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import my.web.services.KeysGeneration;
public class TestClient {
private static String keypass = "KHU12345KHU12345";
public static void callPostService()
{
try{
URL url = new URL("http://localhost:8080/RestWebService/MM");
HttpURLConnection conn =(HttpURLConnection)url.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
conn.setRequestMethod("POST");
String text;
OutputStreamWriter writer = new OutputStreamWriter(conn.getOutputStream());
String email="sabah#gmail.com";
// //**********AES Encryption
// // Create key and cipher
SecretKey aesKey = KeysGeneration.getKeys(keypass);
Cipher cipher = Cipher.getInstance("AES");
// // encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(email.getBytes());
System.out.println("checking encryption "+new String(encrypted));
writer.write("&email="+(encrypted));
// //**********AES Encryption
//// //**********AES Decryption
//
//// // decrypt the text
cipher.init(Cipher.DECRYPT_MODE, aesKey);
String decrypted= new String(cipher.doFinal(encrypted));
System.out.println("checking dencryption "+decrypted);
////
////// //**********AES Decryption
writer.flush();
writer.close();
InputStream stream = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
while((len=stream.read(b, 0,1024))>0)
{
System.out.println(new String(b,0,len));
}
stream.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static void callGETService()
{
try{
URL url = new URL("http://localhost:8080/RestWebService/MM?email=sabah#khu.ac.kr&pwd=1985");
HttpURLConnection conn =(HttpURLConnection)url.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(false);
// Don't use a cached copy.
conn.setUseCaches(false);
conn.setRequestMethod("GET");
InputStream stream = conn.getInputStream();
byte[] b = new byte[1024];
int len = 0;
while((len=stream.read(b, 0,1024))>0)
{
System.out.println(new String(b,0,len));
}
stream.close();
}
catch(Exception ex)
{
ex.printStackTrace();
}
}
public static void main(String[] args) {
// open your connection
TestClient.callGETService();
TestClient.callPostService();
}
}
//webService
package my.web.services;
import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.ws.rs.FormParam;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.QueryParam;
#Path("/MM")
public class WebService {
private String keypass = "KHU12345KHU12345";
//********GET Method*************
#GET
//GET method provides read only access to resources
public String validateUserGETMethod(#QueryParam("email")String email, #QueryParam("pwd")String pwd)
{
return "Using GET method \n Email address: "+email+ " and password:" +pwd;
}
//********POST Method*************
//POST method is used to create or update a new resources
//To generate encryption of email parameter
#POST
#Path("/encryptEmail")
public String validateUserPOSTMethodEncryption(#FormParam("email")String email)throws Exception
{
// Create key and cipher
SecretKey aesKey = KeysGeneration.getKeys(keypass);
Cipher cipher = Cipher.getInstance("AES");
// encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(email.getBytes());
System.err.println(new String(encrypted));
return "Using POST method \n Email address (encrypted): "+new String(encrypted);
}
//POST method is used to create or update a new resources
//To generate decryption of email parameter
#POST
#Path("/decryptEmail")
public String validateUserPOSTMethodDecryption(#FormParam("email")String email)throws Exception
{
//SecretKey aesKey = KeysGeneration.getKeys(keypass);
SecretKey secKey = KeysGeneration.getKeys(keypass);//generator.generateKey();
// Create key and cipher
Cipher cipher = Cipher.getInstance("AES");
// decrypt the text
cipher.init(Cipher.DECRYPT_MODE, secKey);
String decrypted= new String(cipher.doFinal(email.getBytes()));
return "Using POST method \n Email address (decrypted): "+decrypted;
}
}
hi thank you i solved problem by your kind suggestion. I want to show you if I am calculating time correctly required for encryption: Here is my code
// //**********AES Encryption
//checking time in msec
long startTime=System.currentTimeMillis();
//System.out.println(startTime);
// // Create key and cipher
SecretKey aesKey = KeysGeneration.getKeys(keypass);
Cipher cipher = Cipher.getInstance("AES");
// // encrypt the text
cipher.init(Cipher.ENCRYPT_MODE, aesKey);
byte[] encrypted = cipher.doFinal(email.getBytes());
System.out.println("checking encryption "+new String(encrypted));
BASE64Encoder encoder = new BASE64Encoder();
email = encoder.encode(encrypted);
System.out.println("Encoded Encrypted Value="+email);
// text="&email="+URLEncoder.encode(new String(encrypted), "UTF-8");
writer.write("&email="+email);
//Calculating Encryption Time
long stopTime = System.currentTimeMillis();
Duration ms=Duration.ofMillis(stopTime);
//System.out.println(stopTime);
long elapsedTime = stopTime - startTime;
System.out.println("Time required for encryption (milliseconds)= "+elapsedTime);

org.bouncycastle.asn1.DLSequence cannot be cast to org.bouncycastle.asn1.ASN1Integer

I am trying to use BouncyCastle classes to encrypt and decrypt a password. I have written a test program and generated a test key/cert in PEM format as well as DER format. I can read the key/cert into my program and get the public key and encrypt a value. When I try to setup to decrypt the value I am getting the error "org.bouncycastle.asn1.DLSequence cannot be cast to org.bouncycastle.asn1.ASN1Integer" when creating the AsymmetricKeyParameter. It seems that when I am trying to pull in the data from the cert by doing the cert.getEncoded() it pulls in the header values as well. I tried just reading the file and removing the BEGIN and END CERTIFCATE lines, along with the dashes and that netted me the same error. I have tried used the java.security.cert.Certificate as well as the X509Certificate the code below is using. Any help would be greatly appreciated.
I can upload the key file is that would be helpful to you as it is a test key that I generated on my local machine and will be thrown away once I have this working.
package com.cds.test;
import java.io.FileInputStream;
import java.io.InputStream;
import java.security.Security;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import org.bouncycastle.crypto.AsymmetricBlockCipher;
import org.bouncycastle.crypto.engines.RSAEngine;
import org.bouncycastle.crypto.params.AsymmetricKeyParameter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.crypto.util.PublicKeyFactory;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.util.encoders.Base64;
public class RSAEncryptDecrypt {
public X509Certificate cert = null;
//
public void readCertificate() throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
CertificateFactory factory = CertificateFactory.getInstance("X.509", new BouncyCastleProvider());
InputStream fis = new FileInputStream("/opt/temp/keys/openssl_crt.pem");
X509Certificate x509Cert = (X509Certificate) factory.generateCertificate(fis);
this.cert = x509Cert;
System.out.println("issuer: " + x509Cert.getIssuerX500Principal());
}
//
public String encrypt(String inputData) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//
System.out.println("public key: " + new String(Base64.encode(cert.getPublicKey().getEncoded())));
AsymmetricKeyParameter publicKey = PublicKeyFactory.createKey(cert.getPublicKey().getEncoded());
AsymmetricBlockCipher cipher = new RSAEngine();
cipher = new org.bouncycastle.crypto.encodings.PKCS1Encoding(cipher);
cipher.init(true, publicKey);
//
byte[] messageBytes = inputData.getBytes();
byte[] hexEncodedCipher = cipher.processBlock(messageBytes, 0, messageBytes.length);
//
return new String(Base64.encode(hexEncodedCipher));
}
//
private String decrypt (String encryptedData) throws Exception {
Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());
//
byte[] certData = cert.getEncoded();
//certData = Base64.decode(certData);
AsymmetricKeyParameter privateKey = PrivateKeyFactory.createKey(cert.getEncoded());
AsymmetricBlockCipher cipher = new RSAEngine();
cipher = new org.bouncycastle.crypto.encodings.PKCS1Encoding(cipher);
cipher.init(false, privateKey);
//
byte[] decoded = Base64.decode(encryptedData.getBytes());
byte[] result = cipher.processBlock(decoded, 0, decoded.length);
//
return new String(result);
}
//
public static void main(String[] args) throws Exception {
String inputData = "This is the message I am trying to encrypt.";
String encrypted = null;
String decrypted = null;
//
RSAEncryptDecrypt rsa = new RSAEncryptDecrypt();
//
rsa.readCertificate();
System.out.println(" input: " + inputData);
encrypted = rsa.encrypt(inputData);
System.out.println("encrypted: " + encrypted);
decrypted = rsa.decrypt(encrypted);
System.out.println("decrypted: " + decrypted);
}
}
A certificate only contains the public key, not a private key. Of course the public key has a private key associated to it, but that is not kept in the certificate. The certificate is what you distribute to other parties.
It could be that you have been working with Microsoft code too much. I'm mentioning Microsoft as in .NET code the certificate class can internally contain the associated private key, making for a rather oversimplified API.
So to decrypt you will have to read the private key separately of your certificate (using PKCS8EncodedKeySpec and an "RSA" KeyFactory).
Another option is to put both in a PKCS#12 key store and read it into Java using KeyStore.load.

In AES decryption, "Given final block not properly padded" occurred

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).

Categories

Resources