package security;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.util.Scanner;
import java.util.zip.DataFormatException;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
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 PGP {
public static KeyPair Akeys;
public static KeyPair Bkeys;
static int keyLength;
static SecretKey Sessionkey;
static String encodedKey;
static Cipher ecipher;
static Cipher decipher;
private final static char[] hexArray = "0123456789ABCDEF".toCharArray();
static KeyPairGenerator keyGen;
static SecretKey RSAKey;
static Cipher CipherRSA_A;
static Cipher DecipherRSA_A;
static Cipher CipherRSA_B;
static Cipher DecipherRSA_B;
static PublicKey publicKey;
public static void main(String args[]) throws NoSuchAlgorithmException, NoSuchPaddingException, UnsupportedEncodingException, Exception {
Scanner in = new Scanner(System.in);
System.out.println("Enter the message!");
String plaintext = in.nextLine();
//To create keys.
initalizeKey();
byte[] encryptedMessage = SourceA(plaintext);
System.out.println(DestinationB(encryptedMessage));
}
public static byte[] SourceA(String plaintext) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException {
byte[] bytesOfMessage = plaintext.getBytes("UTF-8");//to byte array
byte[] theHash = MD5(bytesOfMessage);//hashing
byte[] EncryptedWithRsa = EncryptRSA_A(theHash);//encrypting the hash with RSA
byte[] Concentaned = Concentane(EncryptedWithRsa, bytesOfMessage);//Concatenation
byte[] CompressedData = compress(Concentaned);//Compressing
byte[] EncryptedWithDes = DES(CompressedData);//Encrypting with DES
byte[] EncryptedKeyWithRSA = EncryptRSA_B(encodedKey.getBytes("UTF-8"));//Encrypting key for DES with RSA
byte[] result = Concentane(EncryptedKeyWithRSA, EncryptedWithDes);//Concatenation
return result;
}
public static String DestinationB(byte[] MessageFromA) throws UnsupportedEncodingException, NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, IOException, DataFormatException {
//Copying first 256 bytes from MessageFromA (first 256 bytes are encrypted key with rsa)
byte[] EncriptedKeyWithRSA = new byte[256];
System.arraycopy(MessageFromA, 0, EncriptedKeyWithRSA, 0, 256);
//copying to EncryptedWithDes bytes after key, main message is there
byte[] EncryptedWithDes = new byte[MessageFromA.length - 256];
System.arraycopy(MessageFromA, 256, EncryptedWithDes, 0, MessageFromA.length - 256);
//Decrypting the key, and decrypting main message using the DES
byte[] decyptedKeyWithRSA = DecryptRSA_B(EncriptedKeyWithRSA);
String decryptedKey = new String(decyptedKeyWithRSA, "UTF-8");
byte[] fromDecryptionDES = DecryptDES(EncryptedWithDes, decryptedKey);//getting first 256 that is with RSA than decrypting;
//bytes after 256's are clear mainmessage
// check if encrypted hash is equal to hash of mainmessage
byte[] decomp = decompress(fromDecryptionDES);
byte[] EncryptedHash = new byte[256];
System.arraycopy(decomp, 0, EncryptedHash, 0, 256);
byte[] MainMessage = new byte[decomp.length - 256];
System.arraycopy(decomp, 256, MainMessage, 0, decomp.length - 256);
System.out.println("Main message: " + new String(MainMessage, "UTF-8"));
//changed to hex because it's easier to check
return "Decrypted hash: \t" + bytesToHex(DecryptRSA_A(EncryptedHash)) + "\n" + "Hashed main message: \t" + bytesToHex(MD5(MainMessage)) + "\nif they equal ? " + bytesToHex(MD5(MainMessage)).equals(bytesToHex(DecryptRSA_A(EncryptedHash)));
}
public static String bytesToHex(byte[] bytes) {
char[] hexChars = new char[bytes.length * 2];
for (int j = 0; j < bytes.length; j++) {
int v = bytes[j] & 0xFF;
hexChars[j * 2] = hexArray[v >>> 4];
hexChars[j * 2 + 1] = hexArray[v & 0x0F];
}
return new String(hexChars);
}
public static byte[] MD5(byte[] bytesOfMessage) throws UnsupportedEncodingException, NoSuchAlgorithmException {
MessageDigest md = MessageDigest.getInstance("MD5");
byte[] thedigest = md.digest(bytesOfMessage);
return thedigest;
}
public static byte[] Concentane(byte[] bytesOfMessage, byte[] fromRsa) {
byte[] c = new byte[bytesOfMessage.length + fromRsa.length];
System.arraycopy(bytesOfMessage, 0, c, 0, bytesOfMessage.length);
System.arraycopy(fromRsa, 0, c, bytesOfMessage.length, fromRsa.length);
return c;
}
public static byte[] compress(byte[] b) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream zos = new GZIPOutputStream(baos);
zos.write(b);
zos.close();
return baos.toByteArray();
}
public static byte[] decompress(byte[] b) throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ByteArrayInputStream bais = new ByteArrayInputStream(b);
GZIPInputStream zis = new GZIPInputStream(bais);
byte[] tmpBuffer = new byte[256];
int n;
while ((n = zis.read(tmpBuffer)) >= 0) {
baos.write(tmpBuffer, 0, n);
}
zis.close();
return baos.toByteArray();
}
private static void initalizeKey() throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException {
//des
Sessionkey = KeyGenerator.getInstance("DES").generateKey();
ecipher = Cipher.getInstance("DES");
decipher = Cipher.getInstance("DES");
ecipher.init(Cipher.ENCRYPT_MODE, Sessionkey);
decipher.init(Cipher.DECRYPT_MODE, Sessionkey);
//rsa
CipherRSA_A = Cipher.getInstance("RSA");
DecipherRSA_A = Cipher.getInstance("RSA");
CipherRSA_B = Cipher.getInstance("RSA");
DecipherRSA_B = Cipher.getInstance("RSA");
keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
Akeys = keyGen.genKeyPair();
Bkeys = keyGen.genKeyPair();
//encdoing the key to make it possible to sent and use again
encodedKey = java.util.Base64.getEncoder().encodeToString(Sessionkey.getEncoded());
}
private static byte[] DES(byte[] CompressedData) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] encryptedDes = ecipher.doFinal(CompressedData);
return encryptedDes;
}
private static byte[] EncryptRSA_B(byte[] bytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
CipherRSA_B.init(Cipher.ENCRYPT_MODE, Bkeys.getPublic());
byte[] x = CipherRSA_B.doFinal(bytes);
return x;
}
private static byte[] DecryptRSA_B(byte[] bytes) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
DecipherRSA_B.init(Cipher.DECRYPT_MODE, Bkeys.getPrivate());
byte[] x = DecipherRSA_B.doFinal(bytes);
return x;
}
public static byte[] EncryptRSA_A(byte[] messageDigest) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
CipherRSA_A.init(Cipher.ENCRYPT_MODE, Akeys.getPrivate());
byte[] x = CipherRSA_A.doFinal(messageDigest);
return x;
}
public static byte[] DecryptRSA_A(byte[] messageDigest) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
DecipherRSA_A.init(Cipher.DECRYPT_MODE, Akeys.getPublic());
byte[] x = DecipherRSA_A.doFinal(messageDigest);
return x;
}
private static byte[] DecryptDES(byte[] fromAntiRsa, String string) throws NoSuchAlgorithmException, NoSuchPaddingException, InvalidKeyException, IllegalBlockSizeException, BadPaddingException {
byte[] decodedKey = java.util.Base64.getDecoder().decode(string);
SecretKey originalKey = new SecretKeySpec(decodedKey, 0, decodedKey.length, "DES");
Cipher de = Cipher.getInstance("DES");
de.init(Cipher.DECRYPT_MODE, originalKey);
byte[] res = de.doFinal(fromAntiRsa);
return res;
}
}