RSA encrypt share data between 2 client - java

Is it possible to encrypt a file with 2 RSA key (private key from pair A and public key from pair B), so that user B can open the file with his private key and A's public key?
I have code build in java and I still try encrypt it manually so I know my program work or not but when I try encrypt my data in second time's my data broken and didn't encrypt at all.
it's my code :
public static void main(String[] args) throws Exception {
generateKeys();
RSA.rsaEncrypt("AES.key","RSA(AES).key");
RSA.rsaDecrypt("RSA(AES).key","AES(RSA).key");
}
public static void generateKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
PublicKey publicKey = kp.getPublic();
PrivateKey privateKey = kp.getPrivate();
System.out.println("keys created");
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(publicKey,
RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(privateKey,
RSAPrivateKeySpec.class);
saveToFile("publicA.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("privateA.key", priv.getModulus(), priv.getPrivateExponent());
System.out.println("keys saved");
}
public static void saveToFile(String fileName, BigInteger mod,
BigInteger exp) throws IOException {
ObjectOutputStream fileOut = new ObjectOutputStream(
new BufferedOutputStream(new FileOutputStream(fileName)));
try {
fileOut.writeObject(mod);
fileOut.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error");
} finally {
fileOut.close();
System.out.println("Closed writing file.");
}
}
// Return the saved key
static Key readKeyFromFile(String keyFileName) throws IOException {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(
in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
KeyFactory fact = KeyFactory.getInstance("RSA");
if (keyFileName.startsWith("publicB")) {
return fact.generatePublic(new RSAPublicKeySpec(m, e));
} else {
return fact.generatePrivate(new RSAPrivateKeySpec(m, e));
}
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
System.out.println("Closed reading file.");
}
}
// Use this PublicKey object to initialize a Cipher and encrypt some data
public static void rsaEncrypt(String file_loc, String file_des)
throws Exception {
byte[] data = new byte[32];
int i;
System.out.println("start encyption");
Key pubKey = readKeyFromFile("publicB.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
FileInputStream fileIn = new FileInputStream(file_loc);
FileOutputStream fileOut = new FileOutputStream(file_des);
CipherOutputStream cipherOut = new CipherOutputStream(fileOut, cipher);
// Read in the data from the file and encrypt it
while ((i = fileIn.read(data)) != -1) {
cipherOut.write(data, 0, i);
}
// Close the encrypted file
cipherOut.close();
fileIn.close();
System.out.println("encrypted file created");
}
// Use this PublicKey object to initialize a Cipher and decrypt some data
public static void rsaDecrypt(String file_loc, String file_des)
throws Exception {
byte[] data = new byte[32];
int i;
System.out.println("start decyption");
Key priKey = readKeyFromFile("privateB.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, priKey);
FileInputStream fileIn = new FileInputStream(file_loc);
CipherInputStream cipherIn = new CipherInputStream(fileIn, cipher);
FileOutputStream fileOut = new FileOutputStream(file_des);
// Write data to new file
while ((i = cipherIn.read()) != -1) {
fileOut.write(i);
}
// Close the file
fileIn.close();
cipherIn.close();
fileOut.close();
System.out.println("decrypted file created");
}

If you want to ensure that the information really came from A, you should sign with A key pair, not encrypt it twice. In a nutshell:
Data -> Encrypt with B public Key -> Encrypted data -> Sign with A private key
Then send it to B who will verify A sign with A public key then open the encrypted data with his own private key.
With this method, you ll have:
- Privacy: encrypted with B public key, only B can open it.
- Non repudiation: Using A private key to sign, only A could have done it.
- Data integrity: When sign it and using a good hash function, you can check the received data for alteration.
Cheers.

Related

Input length must be multiple of 8 when decrypting with padded cipher

I have a client/server application that encrypts or decrypts a message both on the client-side and server-side. However on decryption I keep getting the following error from the StackTrace
Input length must be multiple of 8 when decrypting with padded cipher
Following is the code from both the Server and Client classes.
The thing is I have tried using ("DES/CBC/PKCS5Padding") and ("UTF-8") but still haven't been able to fix said issue.
Any help would be appreciated thanks?
public class ServerApp {
public static byte[] encrypt(String input, Key k) {
try {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] data = input.getBytes();
byte[] result = cipher.doFinal(data);
return result;
} catch (Exception ex) {
return null;
}
}
public static String decrypt(byte[] cipher, Key k) {
try {
Cipher cipher1 = Cipher.getInstance("DES");
cipher1.init(Cipher.DECRYPT_MODE, k);
byte[] original = cipher1.doFinal(cipher);
return new String(original);
} catch (Exception ex) {
return null;
//Logger.getLogger(DES.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) throws NoSuchAlgorithmException {
try {
Key key=KeyGen.getSecretKey();
ServerSocket ser = new ServerSocket(3333);
System.out.println("Server Started");
Socket client = ser.accept();
DataInputStream in = new DataInputStream(client.getInputStream());
DataOutputStream out = new DataOutputStream(client.getOutputStream());
Scanner scan = new Scanner(System.in);
// SecretSocket sc = new SecretSocket(client, KeyGen.getSecretKey());
String serMsg, cliMsg, plain;
// OutputStream sout = sc.getOutputStream();
// InputStream sin = sc.getInputStream();
do {
System.out.print("You say: ");
serMsg = scan.nextLine();
// sout.write(serMsg.getBytes());
// System.out.println("cli server "+sin.read());
byte[] ci = encrypt(serMsg, KeyGen.getSecretKey());
System.out.println("encrypt " +ci.toString());
out.writeUTF(ci.toString());
plain = decrypt(ci, KeyGen.getSecretKey() );
System.out.println("decrypt " + plain);
} while (!serMsg.equals("end"));
client.close();
ser.close();
} catch (IOException ex) {
Logger.getLogger(ServerApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
public class ClientApp {
public static byte[] encrypt(String input, Key k) {
try {
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] data = input.getBytes();
byte[] result = cipher.doFinal(data);
return result;
} catch (Exception ex) {
return null;
}
}
public static String decrypt(byte[] cipher, Key k) {
try {
Cipher cipher1 = Cipher.getInstance("DES/CBC/PKCS5Padding");
cipher1.init(Cipher.DECRYPT_MODE, k);
byte[] original = cipher1.doFinal(cipher);
return new String(original);
} catch (Exception ex) {
return null;
//Logger.getLogger(DES.class.getName()).log(Level.SEVERE, null, ex);
}
}
public static void main(String[] args) throws NoSuchAlgorithmException, InvalidKeyException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException {
try {
Socket s = new Socket("localhost", 3333);
DataInputStream in = new DataInputStream(s.getInputStream());
DataOutputStream out = new DataOutputStream(s.getOutputStream());
Scanner scan = new Scanner(System.in);
String serMsg, cliMsg, plain;
do {
System.out.println("server server "+in.readUTF());
serMsg = in.readUTF();
System.out.println("enc: " + serMsg);
plain = decrypt(serMsg.getBytes("UTF-8"), KeyGen.getSecretKey());
System.out.println("Server says: " + plain);
} while (!serMsg.equals("end"));
s.close();
} catch (IOException ex) {
Logger.getLogger(ClientApp.class.getName()).log(Level.SEVERE, null, ex);
}
}
Cipher cipher = Cipher.getInstance("DES");
cipher.init(Cipher.ENCRYPT_MODE, k);
byte[] data = input.getBytes();
byte[] result = cipher.doFinal(data);
Using DES without IV you are implicitly using DES/ECB/PKCS5Padding.
do not print a byte array directly. Java will output only printable characters. Always encode and decode a byte array when printing (Hex or Base64 are the most common encodings)
Here is an example project
Base64.getEncoder().encodeToString(byteArray)
I hope you are aware DES is considered a weak cipher today and should be used only for backward compatibility.

javax.crypto.BadPaddingException: Given final block not properly padded while decryption

I am trying to decrypt a file in java. The first 16 bytes of decrypted file are IV (initialization vector). Please help in resolving the above exception.
I am trying to prepend the IV in the output file in AESFileEncryption() and then reading it while decryption.
Thank You.
public class AESFileEncryption {
public static void encrypt(String path,String pwd) throws Exception {
FileOutputStream outFile;
try (
FileInputStream inFile = new FileInputStream(path)) {
String fileName=path;
System.out.println(path);
outFile = new FileOutputStream(fileName+".aes");
// password to encrypt the file
String password = pwd;
byte[] salt = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt,65536,128);// user-chosen password that can be used with password-based encryption (PBE).
SecretKey secretKey = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(secretKey.getEncoded(), "AES");//Secret KeySpec is a class and implements inteface SecretKey
Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
SecureRandom random = new SecureRandom();
byte bytes[] = new byte[16];
random.nextBytes(bytes);
IvParameterSpec ivspec = new IvParameterSpec(bytes);
cipher.init(Cipher.ENCRYPT_MODE, secret,ivspec);//opmode,key
outFile.write(bytes);
byte[] input = new byte[64];
int bytesRead;
while ((bytesRead = inFile.read(input)) != -1) {
byte[] output = cipher.update(input, 0, bytesRead);
if (output != null)
Files.write(Paths.get(fileName+".aes"), output, StandardOpenOption.APPEND);
} byte[] output = cipher.doFinal();
if (output != null)
Files.write(Paths.get(fileName+".aes"), output, StandardOpenOption.APPEND);
}
outFile.flush();
outFile.close();
File f=new File(path);
boolean x=f.delete();
if(x){
System.out.println("File deleted");
}
JOptionPane.showMessageDialog(null,"File Encrypted.");
}
}
Decryption code
public class AESFileDecryption {
public static void decrypt(String path,String pwd) throws Exception {
String password = pwd;
String fileName=path;
File file=new File(path);
//System.out.println(inFile.toString());
String fileNameWithOutExt = path.replaceFirst("[.][^.]+$", "");
System.out.println(fileName);
System.out.println(fileNameWithOutExt);
byte[] salt = {
(byte)0xc7, (byte)0x73, (byte)0x21, (byte)0x8c,
(byte)0x7e, (byte)0xc8, (byte)0xee, (byte)0x99
};
System.out.println("1");
FileInputStream fis = new FileInputStream(path);
SecretKeyFactory factory = SecretKeyFactory
.getInstance("PBKDF2WithHmacSHA1");
KeySpec keySpec = new PBEKeySpec(password.toCharArray(),salt,65536,128);
SecretKey tmp = factory.generateSecret(keySpec);
SecretKey secret = new SecretKeySpec(tmp.getEncoded(), "AES");
System.out.println("2");
// file decryption
Cipher cipher=null;
byte bytes[]=new byte[16];
fis.read(bytes, 0, 16);
IvParameterSpec ivspec = new IvParameterSpec(bytes);
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
cipher.init(Cipher.DECRYPT_MODE, secret, ivspec);
System.out.println("3");
FileOutputStream fos = new FileOutputStream(fileNameWithOutExt);
System.out.println("4");
byte[] in = new byte[64];
int read;
while ((read = fis.read(in,16,(int)file.length()-16)) != -1) {
byte[] output = cipher.update(in, 0, read);
if (output != null)
fos.write(output);
}
try{
byte[] output = cipher.doFinal();
if (output != null)
fos.write(output);
fis.close();
fos.flush();
fos.close();
System.out.println("File Decrypted.");
}
catch(IOException | BadPaddingException | IllegalBlockSizeException e)
{
System.out.println(e+"");
}
}
}
There are a few problems with the small example, but the one that is most immediately your problem is the line
while ((read = fis.read(in,16,(int)file.length()-16)) != -1) {
You seem to be confused about the meaning of the offset parameter to the read(). It is not the offset into the file, but rather the offset into the array (in) that is specified in the first parameter.
A non-exhaustive list of other problems that I see include:
writing to the file using the two independent mechanisms (FileOutputStream.write() and Files.write()). This actually worked ok when I ran your program but it seems like it's asking for trouble. There's no reason to use Files.write() here.
fis.read(bytes, 0, 16); does not check the return value.
It seems you are struggling with finding some IO idioms that you're comfortable with. Or perhaps just experimenting. At the risk of giving you even more options to juggle, you might consider investigating google's open source Guava library. Many people find it has just what they needed.

RSA - Encrypt in Android / Decrypt in PHP

I encrypt a word in java and I have trouble decrypting it in php.
here is how I create the keys in android:
public void GenerateAndSaveToFile(){
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(1024);
KeyPair kp = kpg.genKeyPair();
Key publicKey = kp.getPublic();
Key privateKey = kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
//////////////////////////
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/keys");
myDir.mkdirs();
File file = new File (myDir, "private.key");
FileOutputStream fileout1 = new FileOutputStream(file);
ObjectOutputStream oout1 = new ObjectOutputStream(fileout1);
oout1.writeObject(priv.getModulus());
oout1.writeObject( priv.getPrivateExponent());
oout1.close();
///////////////////////
File file2 = new File (myDir, "public.key");
FileOutputStream fileout2 = new FileOutputStream(file2);
ObjectOutputStream oout2 = new ObjectOutputStream(new BufferedOutputStream(fileout2));
oout2.writeObject(pub.getModulus());
oout2.writeObject( pub.getPublicExponent());
oout2.close();
}
catch (Exception ex){
Exception e = ex;
}
}
here is how I encrypt the word with generated public key in android:
byte[] u1Encrypted = RSAEncrypt(String.valueOf(inputEmail.getText()).getBytes());
public byte[] RSAEncrypt(byte[] data) {
try {
PublicKey pubKey = ReadPublicKey();
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
catch (Exception ex)
{
Exception e = ex;
return null;
}
}
private PublicKey ReadPublicKey() throws IOException {
try {
AssetManager assetManager = getAssets();
InputStream in = assetManager.open("public.key");
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
catch (Exception ex)
{
Exception e = ex;
return null;
}
}
then I convert the encrypted string to base64 in android:
String u1EncryptedBase64 = Base64.encodeToString(u1Encrypted, Base64.DEFAULT);
and in php I decode the base64 string:
$encryptedString = base64_decode(u1EncryptedBase64);
get the private key:
$keytmp = fopen("../../../private.key", "r") or die("Unable to open file!");
$key = fread($keytmp,filesize("../../../private.key"));
$res = openssl_get_privatekey($key);
and finally I try to decrypt the string in php:
if (openssl_private_decrypt($encryptedString, $decrypted, $res)) {
echo $decrypted;
}
else
{
echo "problem";
}
and error I get is:
Warning: openssl_private_decrypt(): key parameter is not a valid private key ...
please guide me how to accompolish this task.
thanks
I can show you how i have done encryption in my android and decryption in php. It worked wonderfully fine.May be you can get some help from this. In android the code is like:
final private static String RSA_public_key="MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0AMIIBCAKCAQEApeRuOhn71+wcRtlN6JoW\n" +
"JLrVE5HKLPukFgpMdguNskBwDOPrrdYKP1e3rZMHN9oVB/QTTpkQM4CrGYlstUmT\n" +
"u5nEfdsH4lHRxe3qhi9+zOknWKJCnW4Cq70oITCAK08BIJ/4ZcGM1SUyv1+0u1aB\n" +
"cx6g1aKhthttRjNpck2LBaHVolt7Z4FTb5SdZMwJKRyEv8fuP6yyR0CJGEbQKZKA\n" +
"ODNKyqJ42sVzUQ2AMQIWdhkFdAFahKCL4MChGvKU6F20cHdvokyxXJjU3sZobjNf\n" +
"i+8FzH9hd7y8kmi4o3AKP69p5asgflXoXHpo135i3NzZqlNJ+Bs9pY+90u9iLScp\n" +
"JwIBAw==";
static String enccriptData(String txt)
{
String encoded = "";
byte[] encrypted = null;
try {
byte[] publicBytes = Base64.decode(RSA_public_key, Base64.DEFAULT);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicBytes);
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1PADDING"); //or try with "RSA"
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
encrypted = cipher.doFinal(txt.getBytes());
encoded = Base64.encodeToString(encrypted, Base64.DEFAULT);
}
catch (Exception e) {
e.printStackTrace();
}
return encoded;
}
I have paste that encoded string that is returned in the above function in below $string. This is the code for php:
<?php
$string="W39VlV1Q96QzDIR/jINzaEL7rh2Z+Z90uxJ1DtaSfkVKzIgt2TIkxsuRY+A2icwPtTdq6+9j1Xb009KT+ck2KD+dot3wPL5UaHqApbZSi6UZan/nDbFCNJdffTlTWsPS2ThEefeMMSs8HE2ORSt42D8cxYlogOvkvlLr60cHYKwfC1itLSqPuYR+C/gPAf6yCteLbj//EkJp8TemlmPi0eSsH492FgrmBqiTOS4LzpzsPFpSI4KJbuM2dvqp5jkt7MnpR1laILmyC37fA5XPUQmEQChoG5eSbMxqO7SPboYC1BH9ATy6uTS1MGXGDzJ2FSJ41MMRV1Ul/4UNFVA8Ng==";
$encryptedString = base64_decode($string);
$key="-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCl5G46GfvX7BxG
2U3omhYkutUTkcos+6QWCkx2C42yQHAM4+ut1go/V7etkwc32hUH9BNOmRAzgKsZ
iWy1SZO7mcR92wfiUdHF7eqGL37M6SdYokKdbgKrvSghMIArTwEgn/hlwYzVJTK/
X7S7VoFzHqDVoqG2G21GM2lyTYsFodWiW3tngVNvlJ1kzAkpHIS/x+4/rLJHQIkY
RtApkoA4M0rKonjaxXNRDYAxAhZ2GQV0AVqEoIvgwKEa8pToXbRwd2+iTLFcmNTe
xmhuM1+L7wXMf2F3vLySaLijcAo/r2nlqyB+VehcemjXfmLc3NmqU0n4Gz2lj73S
72ItJyknAgEDAoIBAG6YSXwRUo/yvYSQ3psRZBh8jg0L3B39GA6xiE6yXnbVoAiX
8nPkBtTlJR5iBM/muK/4DN8QtXerHLuw8yOGYn0RLak8r+w2i9lJRwQfqd3wxOXB
gb5JVx0oxWt1qseKAMBqpZkrszjDdyo/zdI5q6IUazkXFnlnni7M8PbeXK5q0PE6
0XclC1W79jX71D8d24SITAfXDqaXOwObSn9dadw1gsxx8fPd6Fr7ZTS0AddxJZN2
jNK14xkv2rkxdP1W529gnCVQUhju5SPJS5QwphI7KyfH7wTHnBOhbhp3FpaVKPz0
biLwZ6D0xgR6reZofz+t1cvDOha54wC4ZZYJyTsCgYEA0blJn8zxAHDSj8z/01zz
dc1qdYfdlf9gEWgr+APS9XSowGg+CdQN2W0XwySlpPoMZyCKM/aH0DNcl11yynpL
Mkm5MU2V2T+VKWXwUNHrGXSVRJkgLu+iD1Pt0oGPfS9qRYydG5TBjQEVrBrh4Jtk
KdsMBA82mgxEdFqtERbTpi0CgYEAyn85oWfYwf4oHEbSd218RauRBqwMhk39nyqx
6Gaza/k6Ri+5hBjqvVt8pT1Obrji5fZFU1IH5wecQae1mvIQJv+tVBy+XPedU8Mo
Jj3/TPwBAHezTADvQyEIwPot6y5lZt2fX7Urv+n1k7XkfWfb8O/ChTc/zHc0dPct
uLVE1SMCgYEAi9Dbv932AEs3CoiqjOiiTojxo6/pDqpAC5rH+q03Tk3F1ZrUBo1e
kPNlLMMZGKay72sGzU8FNXeTD5Oh3FGHdtvQy4kOkNUOG5lK4IvyEPhjgxDAH0ps
Cjfz4au0/h+cLl2+EmMrs1YOcryWlbztcTyyrV95vAgtouceC2SNGXMCgYEAhv97
wO/l1qlwEtnhpPOoLnJgrx1drt6pFMchRZnM8qYm2XUmWBCcfjz9w340SdCXQ/mD
jOFamgUS1m/OZ0wKxKpzjWh+6KUTjSzFbtP/iKgAqvp3iACfghYF1fwenMmY7z5q
P84dKpv5DSPtqO/n9fUsWM9/3aTNo09z0HjYjhcCgYEAoN+1/ZzonPWDIY/u+7bW
e8BkcuBVpMZe7qBYHeVix89yvyuVE+erKqurnG7fN7YIDX8V1OcVP+qHw8fJNQKL
wd03nNIIJyTPXodgty3HYjBUe8fVn/8P+JOv2U7bJCkUGlFeyZIMZWEsYd8t5794
3fotiYXOUug9bFtnGHRyY7I=
-----END PRIVATE KEY-----";
openssl_private_decrypt($encryptedString, $decrypted, $key);
$string1=$decrypted;
echo $string1;
?>
The private and public keys are made for each other.

Send file encrypted (Server) and receive file decrypted (Client) with AES 256

Im sending a file from Server to a Client but i need to send a encrypted file with AES 256 and receive a original for client use in diferente machine.
I want use 2 string to generate a SHA256 for example: "fruit" and "car29".
After generate this key I want to use this key as secretkey to encrypt with AES256.The client and server know the two strings.
My server code:
public final static int SOCKET_PORT = 4444;
public final static String FILE_TO_SEND = "C:\\file.txt";
public static void main(String[] args) throws IOException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
FileInputStream fis = null;
BufferedInputStream bis = null;
OutputStream os = null;
ServerSocket servsock = null;
Socket sock = null;
try {
servsock = new ServerSocket(SOCKET_PORT);
while (true) {
System.out.println("Waiting...");
try {
sock = servsock.accept();
System.out.println("Accepted connection : " + sock);
// send file
File myFile = new File(FILE_TO_SEND);
byte[] mybytearray = new byte[(int) myFile.length()];
fis = new FileInputStream(myFile);
bis = new BufferedInputStream(fis);
bis.read(mybytearray, 0, mybytearray.length);
os = sock.getOutputStream();
System.out.println("Sending " + FILE_TO_SEND + "(" + mybytearray.length + " bytes)");
os.write(mybytearray, 0, mybytearray.length);
os.flush();
System.out.println("Done.");
} finally {
if (bis != null) {
bis.close();
}
if (os != null) {
os.close();
}
if (sock != null) {
sock.close();
}
}
}
} finally {
if (servsock != null) {
servsock.close();
}
}
}
My client code:
public final static int SOCKET_PORT = 4444;
public final static String SERVER = "127.0.0.1";
public final static String FILE_TO_RECEIVED = "C:\\file.txt";
public final static int FILE_SIZE = 6022386;
public static void main (String [] args ) throws IOException {
int bytesRead;
int current = 0;
FileOutputStream fos = null;
BufferedOutputStream bos = null;
Socket sock = null;
try {
sock = new Socket(SERVER, SOCKET_PORT);
System.out.println("Connecting...");
// receive file
byte [] mybytearray = new byte [FILE_SIZE];
InputStream is = sock.getInputStream();
fos = new FileOutputStream(FILE_TO_RECEIVED);
bos = new BufferedOutputStream(fos);
bytesRead = is.read(mybytearray,0,mybytearray.length);
current = bytesRead;
do {
bytesRead =
is.read(mybytearray, current, (mybytearray.length-current));
if(bytesRead >= 0) current += bytesRead;
} while(bytesRead > -1);
bos.write(mybytearray, 0 , current);
bos.flush();
System.out.println("File " + FILE_TO_RECEIVED
+ " downloaded (" + current + " bytes read)");
}
finally {
if (fos != null) fos.close();
if (bos != null) bos.close();
if (sock != null) sock.close();
}
}
Thanks in advance!
There's some function I write for you, check it out.
For generating HASH/Digest:
public byte[] generateHASH(byte[] message) throws Exception {
MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
byte[] hash = messageDigest.digest(message);
return hash;
}
For Encryption:
public byte[] encrypt(byte[] msg, byte[] key, byte[] iv) throws Exception {
//prepare key
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
//prepare cipher
String cipherALG = "AES/CBC/PKCS5padding"; // use your preferred algorithm
Cipher cipher = Cipher.getInstance(cipherALG);
String string = cipher.getAlgorithm();
//as iv (Initial Vector) is only required for CBC mode
if (string.contains("CBC")) {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
} else {
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
}
byte[] encMessage = cipher.doFinal(msg);
return encMessage;
}
For Decryption:
public byte[] decrypt(byte[] encMsgtoDec, byte[] key, byte[] iv) throws Exception {
//prepare key
SecretKeySpec secretKeySpec = new SecretKeySpec(key, "AES");
//prepare cipher
String cipherALG = "AES/CBC/PKCS5padding"; // use your preferred algorithm
Cipher cipher = Cipher.getInstance(cipherALG);
String string = cipher.getAlgorithm();
//as iv (Initial Vector) is only required for CBC mode
if (string.contains("CBC")) {
IvParameterSpec ivParameterSpec = new IvParameterSpec(iv);
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec);
} else {
cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec);
}
byte[] decMsg = cipher.doFinal(encMsgtoDec);
return decMsg;
}
Note:
If you use CBC mode, then both encrypt() and decrypt() use same iv, otherwise you don't need iv, and of course key is same for both.
Your key generation process is naive. You better use RSA public key encryption for key exchange or Diffie–Hellman key exchange method for secret key transfer.
I would suggest you to use SSL. The data encryption comes by default. The SSL handshake takes care of generating and exchanging the encryption keys and subsequently encrypting the data from the source and decrypting it at the receiving end. All this happens at the transport layer and the application does not have to bother or do anything explicit except for configuring it to use SSL.

Issues in RSA encryption in Java class

public class MyEncrypt {
public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}
public static void main(String[] args) throws Exception {
MyEncrypt myEncrypt = new MyEncrypt();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(128);
KeyPair kp = kpg.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
myEncrypt.saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
myEncrypt.saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
String encString = myEncrypt.bytes2String(myEncrypt.rsaEncrypt("pritesh".getBytes()));
System.out.println("encrypted : " + encString);
String decString = myEncrypt.bytes2String(myEncrypt.rsaDecrypt(encString.getBytes()));
System.out.println("decrypted : " + decString);
}
PublicKey readKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
public byte[] rsaEncrypt(byte[] data) throws Exception {
byte[] src = new byte[] { (byte) 0xbe, (byte) 0xef };
PublicKey pubKey = this.readKeyFromFile("public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
public byte[] rsaDecrypt(byte[] data) throws Exception {
byte[] src = new byte[] { (byte) 0xbe, (byte) 0xef };
PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
byte[] cipherData = cipher.doFinal(data);
return cipherData;
}
private String bytes2String(byte[] bytes) {
StringBuilder string = new StringBuilder();
for (byte b: bytes) {
String hexString = Integer.toHexString(0x00FF & b);
string.append(hexString.length() == 1 ? "0" + hexString : hexString);
}
return string.toString();
}
}
I am getting this error:
Exception in thread "main" java.security.InvalidParameterException: RSA keys must be at least 512 bits long
at sun.security.rsa.RSAKeyPairGenerator.initialize(RSAKeyPairGenerator.java:70)
at java.security.KeyPairGenerator$Delegate.initialize(KeyPairGenerator.java:631)
at java.security.KeyPairGenerator.initialize(KeyPairGenerator.java:340)
at MyEncrypt.main(MyEncrypt.java:42)
I have make this class from http://www.javamex.com/tutorials/cryptography/rsa_encryption_2.shtml example
public class MyEncrypt {
static final String HEXES = "0123456789ABCDEF";
byte[] buf = new byte[1024];
public void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}
public static void main(String[] args) throws Exception {
MyEncrypt myEncrypt = new MyEncrypt();
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(2048);
KeyPair kp = kpg.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
myEncrypt.saveToFile("public.key", pub.getModulus(), pub.getPublicExponent());
myEncrypt.saveToFile("private.key", priv.getModulus(), priv.getPrivateExponent());
String encString = myEncrypt.rsaEncrypt("pritesh");
System.out.println("encrypted : " + encString);
String decString = myEncrypt.rsaDecrypt(encString);
System.out.println("decrypted : " + decString);
String main_file_path = "resume.doc";
String main_encrypt_file_path = "encrypt.doc";
String main_decrypt_file_path = "decrypt.doc";
myEncrypt.rsaEncrypt(new FileInputStream(main_file_path),new FileOutputStream(main_encrypt_file_path));
// Decrypt
myEncrypt.rsaDecrypt(new FileInputStream(main_encrypt_file_path),new FileOutputStream(main_decrypt_file_path));
}
PublicKey readKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
public String rsaEncrypt(String plaintext) throws Exception {
PublicKey pubKey = this.readKeyFromFile("public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
byte[] ciphertext = cipher.doFinal(plaintext.getBytes("UTF-8"));
return this.byteToHex(ciphertext);
}
public void rsaEncrypt(InputStream in, OutputStream out) throws Exception {
try {
PublicKey pubKey = this.readKeyFromFile("public.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, pubKey);
// Bytes written to out will be encrypted
out = new CipherOutputStream(out, cipher);
// 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 rsaDecrypt(InputStream in, OutputStream out) throws Exception {
try {
PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
Cipher dcipher = Cipher.getInstance("RSA");
dcipher.init(Cipher.DECRYPT_MODE, pubKey);
// 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();
}
}
public String rsaDecrypt(String hexCipherText) throws Exception {
PrivateKey pubKey = this.readPrivateKeyFromFile("private.key");
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, pubKey);
String plaintext = new String(cipher.doFinal(this.hexToByte(hexCipherText)), "UTF-8");
return plaintext;
}
public static String byteToHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
public static byte[] hexToByte( String hexString){
int len = hexString.length();
byte[] ba = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
ba[i/2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4) + Character.digit(hexString.charAt(i+1), 16));
}
return ba;
}
}
It works well with text file but giving issue on files like docx and video any idea?
The error says it all: you're initializing with a keyset of 128 and RSA expects at least 512.
You have more than one problem:
Java does not support RSA keys of size less than 512. 2048 bit is a better choice. So change the key length:
kpg.initialize(2048);
String.getBytes() is not the inverse operation to your bytes2String(). After encrypting you convert the bytes to a hexadecimal string. But then you convert this hexadecimal string to its ASCII representation before decrypting, which yields a byte-array that is too long. Instead, use something like this to convert the hexadecimal string back:
private byte[] string2bytes(String s) {
int len = s.length();
byte[] res = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
res[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return res;
}
and then call that instead of String.getBytes():
// Note, this line is not completely fixed yet
String decString =
myEncrypt.bytes2String(
myEncrypt.rsaDecrypt(
myEncrypt.string2bytes(encString)
)
);
Finally you have the opposite problem. Your bytes2String() method does not reverse the String.getBytes() operation. You encrypted the output of "pritesh".getBytes(), so that is what you got out of the decrypt operation. Now you have to convert that back to a String. The String(byte[])-constructor will do that for you:
String decString =
new String(
myEncrypt.rsaDecrypt(
myEncrypt.string2bytes(encString)
)
);
Final ans
public class MyEncrypt {
public static final int AES_Key_Size = 128;
Cipher pkCipher, aesCipher;
byte[] aesKey;
SecretKeySpec aeskeySpec;
public static void main(String[] args) throws Exception {
//MyEncrypt.createRSAKeys(); //call to generated RSA keys
MyEncrypt secure = new MyEncrypt();
// to encrypt a file
secure.makeKey();
secure.saveKey(new File("keys/ase.key"), "keys/public.key");
secure.encrypt(new File("test/sample.pdf"), new File("test/encrypt_sample.pdf"));
// to decrypt it again
secure.loadKey(new File("keys/ase.key"), "keys/private.key");
secure.decrypt(new File("test/encrypt_sample.pdf"), new File("test/decrypted_sample.pdf"));
}
/**
* Constructor: creates ciphers
*/
public MyEncrypt() throws GeneralSecurityException {
// create RSA public key cipher
pkCipher = Cipher.getInstance("RSA");
// create AES shared key cipher
aesCipher = Cipher.getInstance("AES");
}
public static void createRSAKeys() throws Exception {
KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
kpg.initialize(512);
KeyPair kp = kpg.genKeyPair();
RSAPublicKey publicKey = (RSAPublicKey) kp.getPublic();
RSAPrivateKey privateKey = (RSAPrivateKey) kp.getPrivate();
KeyFactory fact = KeyFactory.getInstance("RSA");
RSAPublicKeySpec pub = fact.getKeySpec(kp.getPublic(), RSAPublicKeySpec.class);
RSAPrivateKeySpec priv = fact.getKeySpec(kp.getPrivate(), RSAPrivateKeySpec.class);
saveToFile("keys/public.key", pub.getModulus(), pub.getPublicExponent());
saveToFile("keys/private.key", priv.getModulus(), priv.getPrivateExponent());
System.out.println("RSA public & private keys are generated");
}
private static void saveToFile(String fileName, BigInteger mod, BigInteger exp) throws IOException {
ObjectOutputStream oout = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(fileName)));
try {
oout.writeObject(mod);
oout.writeObject(exp);
} catch (Exception e) {
throw new IOException("Unexpected error", e);
} finally {
oout.close();
}
}
/**
* Creates a new AES key
*/
public void makeKey() throws NoSuchAlgorithmException {
KeyGenerator kgen = KeyGenerator.getInstance("AES");
kgen.init(AES_Key_Size);
SecretKey key = kgen.generateKey();
aesKey = key.getEncoded();
aeskeySpec = new SecretKeySpec(aesKey, "AES");
}
/**
* Encrypts the AES key to a file using an RSA public key
*/
public void saveKey(File out, String publicKeyFile) throws IOException, GeneralSecurityException {
try {
// read public key to be used to encrypt the AES key
byte[] encodedKey = new byte[(int)publicKeyFile.length()];
new FileInputStream(publicKeyFile).read(encodedKey);
// create public key
//X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(encodedKey);
//KeyFactory kf = KeyFactory.getInstance("RSA");
//PublicKey pk = kf.generatePublic(publicKeySpec);
PublicKey pk = this.readPublicKeyFromFile(publicKeyFile);
// write AES key
pkCipher.init(Cipher.ENCRYPT_MODE, pk);
CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), pkCipher);
os.write(aesKey);
os.close();
} catch (Exception e) {
//throw new Exception("Saving key exception", e);
}
}
private PublicKey readPublicKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPublicKeySpec keySpec = new RSAPublicKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PublicKey pubKey = fact.generatePublic(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
private PrivateKey readPrivateKeyFromFile(String keyFileName) throws Exception {
InputStream in = new FileInputStream(keyFileName);
ObjectInputStream oin = new ObjectInputStream(new BufferedInputStream(in));
try {
BigInteger m = (BigInteger) oin.readObject();
BigInteger e = (BigInteger) oin.readObject();
RSAPrivateKeySpec keySpec = new RSAPrivateKeySpec(m, e);
KeyFactory fact = KeyFactory.getInstance("RSA");
PrivateKey pubKey = fact.generatePrivate(keySpec);
return pubKey;
} catch (Exception e) {
throw new RuntimeException("Spurious serialisation error", e);
} finally {
oin.close();
}
}
/**
* Decrypts an AES key from a file using an RSA private key
*/
public void loadKey(File in, String privateKeyFile) throws GeneralSecurityException, IOException {
try {
// read private key to be used to decrypt the AES key
byte[] encodedKey = new byte[(int)privateKeyFile.length()];
new FileInputStream(privateKeyFile).read(encodedKey);
// create private key
//PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(encodedKey);
//KeyFactory kf = KeyFactory.getInstance("RSA");
//PrivateKey pk = kf.generatePrivate(privateKeySpec);
PrivateKey pk = this.readPrivateKeyFromFile(privateKeyFile);
// read AES key
pkCipher.init(Cipher.DECRYPT_MODE, pk);
aesKey = new byte[AES_Key_Size/8];
CipherInputStream is = new CipherInputStream(new FileInputStream(in), pkCipher);
is.read(aesKey);
aeskeySpec = new SecretKeySpec(aesKey, "AES");
} catch (Exception e) {
}
}
/**
* Encrypts and then copies the contents of a given file.
*/
public void encrypt(File in, File out) throws IOException, InvalidKeyException {
aesCipher.init(Cipher.ENCRYPT_MODE, aeskeySpec);
FileInputStream is = new FileInputStream(in);
CipherOutputStream os = new CipherOutputStream(new FileOutputStream(out), aesCipher);
copy(is, os);
os.close();
}
/**
* Decrypts and then copies the contents of a given file.
*/
public void decrypt(File in, File out) throws IOException, InvalidKeyException {
aesCipher.init(Cipher.DECRYPT_MODE, aeskeySpec);
CipherInputStream is = new CipherInputStream(new FileInputStream(in), aesCipher);
FileOutputStream os = new FileOutputStream(out);
copy(is, os);
is.close();
os.close();
}
/**
* Copies a stream.
*/
private void copy(InputStream is, OutputStream os) throws IOException {
int i;
byte[] b = new byte[1024];
while((i=is.read(b))!=-1) {
os.write(b, 0, i);
}
}
}

Categories