0
votes

I am working on a hybrid encryption mechanism in java that involves encrypting message using 3DES encryption algorithm and then encrypt its key using RSA encryption mechanism at the sender side. Once delivered to the receiver side, the encrypted 3DES key is decrypted using RSA decryption mechanism and then is used to decrypt the cipher text. Once I obtain the decrypted 3DES key its string value is the same but byte [] is not the same instead returns a 2's complement of the original key.

How can I get the decrypted 3DES to be the same as the originally generated 3DES in byte [] form at the receiver side?

Below is the code I am using for my hybrid encryption mechanism: package hybrid_implementation;

import java.security.Key;
import java.security.InvalidKeyException;
import java.security.spec.InvalidKeySpecException;
import java.security.NoSuchAlgorithmException;
import java.util.Scanner;
import java.math.BigInteger;
import java.security.SecureRandom;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESedeKeySpec;
import javax.crypto.BadPaddingException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.IllegalBlockSizeException;

public class Hybrid_Implementation {

//RSA_Encryption Algorithm Required Variables
private static final BigInteger one = new BigInteger("1");
private static final SecureRandom random = new SecureRandom();
private BigInteger privatekey;
private BigInteger publickey;
private BigInteger modulus;

//3DES_Encryption Algorithm Required Variables
private byte[] DES_Key;
private SecretKeyFactory keyfactory;
private DESedeKeySpec spec;
private Key deskey;
private int DES_Key_Length;
private byte[] data;
private Cipher cipher;
private String CipherText;
private byte [] CIPHERText;

Hybrid_Implementation() throws InvalidKeyException, 
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException
{
    DES_Key_Generator();
    RSA_Key_Generator(999);
}

//3DES Encryption-Decryption Algorithm with 2 differnt keys
private String DES_Encryption(String plaintext) throws InvalidKeyException, 
IllegalBlockSizeException, BadPaddingException
{
    data = plaintext.getBytes();
    cipher.init(Cipher.ENCRYPT_MODE, deskey);
    CIPHERText = cipher.doFinal(data);
    StringBuilder hexCiphertext = new StringBuilder();
    for(int i=0; i<CIPHERText.length; i++)
    {
        int v = CIPHERText[i] & 0xff;
        v+=0x100;
        String temp = Integer.toString(v,16);
        hexCiphertext.append(temp).substring(1);
    }
    return hexCiphertext.toString();
}

private String DES_Decryption(byte [] key, byte [] encrypted_text) throws 
InvalidKeyException, IllegalBlockSizeException, BadPaddingException, 
InvalidKeySpecException
{
   spec = new DESedeKeySpec(key);
   deskey = keyfactory.generateSecret(spec);
    byte[] plaintext = cipher.doFinal(encrypted_text);
    StringBuilder decrypttext= new StringBuilder();
    for (int i = 0; i < plaintext.length; i++)
        decrypttext.append((char) plaintext[i]);
    String decrypted_plaintext = decrypttext.toString();
    return decrypted_plaintext;
}

private void DES_Key_Generator() throws InvalidKeyException, 
NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException
{
    Random rnd = new Random();
    String key = rnd.toString();

    DES_Key = key.getBytes();
    spec = new DESedeKeySpec(DES_Key);
    keyfactory = SecretKeyFactory.getInstance("desede");
    deskey = keyfactory.generateSecret(spec);
    cipher = Cipher.getInstance("desede");
}


//RSA Encryption-Decryption Algorithm
private BigInteger RSA_Encryption(BigInteger des_Key )  //RSA Encryption of 
3DES Key
{
     BigInteger encrypted_DES_Key = des_Key.modPow(publickey, modulus);
     return encrypted_DES_Key;
}

private BigInteger RSA_Decryption(BigInteger encrypted_DES_Key) //RSA 
Decryption of 3DES Key
{
    BigInteger des_Key = encrypted_DES_Key.modPow(privatekey, modulus);
    return des_Key;
}

private void RSA_Key_Generator(int number)     //RSA Public - Private Key 
Generation
{
    BigInteger p = BigInteger.probablePrime(number/2,random);
    BigInteger q = BigInteger.probablePrime(number/2, random);
    BigInteger phi = (p.subtract(one)).multiply(q.subtract(one));

    modulus = p.multiply(q);
    publickey = new BigInteger("65537");
    privatekey = publickey.modInverse(phi);
}

private String encryption(String plaintext) throws InvalidKeyException, 
IllegalBlockSizeException, BadPaddingException
{
    String cipher_text = DES_Encryption(plaintext);
    BigInteger RSA_DESKey = RSA_Encryption(new BigInteger(DES_Key));
    String temp_key = RSA_DESKey.toString();
    DES_Key_Length = temp_key.length();
    CipherText ="";
    CipherText = new 
StringBuilder().append(temp_key).append(cipher_text).toString();
    return CipherText;
}

private String decryption(String encrypted_text) throws InvalidKeyException, 
InvalidKeySpecException, IllegalBlockSizeException, BadPaddingException
{
    StringBuilder encryptedkey = new StringBuilder();
    for(int i = 0 ; i < DES_Key_Length; i++)
        encryptedkey.append (encrypted_text.charAt(i));
    StringBuilder cipheredtext = new StringBuilder();
    for(int j = DES_Key_Length ; j< encrypted_text.length() ; j++)
        cipheredtext.append (encrypted_text.charAt(j));
    BigInteger DES_Encrypted_Key = new BigInteger(encryptedkey.toString());
    BigInteger DES_KEY = RSA_Decryption(DES_Encrypted_Key);
    byte[] decrypt_key = DES_KEY.toByteArray();
    String plaintext = 
DES_Decryption(decrypt_key,cipheredtext.toString().getBytes());
       return plaintext;
}

/**
 *
 * @param args
 * @throws InvalidKeyException
 * @throws IllegalBlockSizeException
 * @throws BadPaddingException
 * @throws java.security.NoSuchAlgorithmException
 * @throws java.security.spec.InvalidKeySpecException
 * @throws javax.crypto.NoSuchPaddingException
 */
public static void main(String[] args) throws InvalidKeyException, 
IllegalBlockSizeException, BadPaddingException, NoSuchAlgorithmException, 
InvalidKeySpecException, NoSuchPaddingException {
    String plaintext;
    Hybrid_Implementation hi = new Hybrid_Implementation ();
    Scanner sc = new Scanner(System.in);
    System.out.print("Enter Text = ");
    plaintext = sc.nextLine();
    String encrypted_text = hi.encryption(plaintext);
    String decrypted_text = hi.decryption(encrypted_text);
    System.out.println("Plain Text Entered = "+plaintext);
    System.out.println("Encrypted Text = "+encrypted_text);
    System.out.println("Decrypted Text = "+decrypted_text);
    }

}

The output I receive is: enter image description here Whereas the decrypted text is not the same as the entered plain text

1
Do you really mean it's the negative of the value, or do you mean it displays as signed using something like System.out.print(bytearray[i]) or Arrays.toString(bytearray)? The latter is expected because type byte in Java is signed. However Java crypto (and I/O also) treats byte[] elements (both keys/IVs/etc and data) as unsigned and works correctly. It's usually clearer to display (and sometimes enter) crypto values as hex. OTOH keys should not be restricted to valid characters and so treating them as String will usually produce wrong results.dave_thompson_085
Below is the code I am using for my hybrid encryption mechanism:Maryam Zahid
Are you sure you want to use your own RSA implementation without secure padding? You have no message authentication so your message could be easily tampered. Consider using Java's inbuilt RSA/ECB/PKCS1Padding or RSA/ECB/OAEPWithSHA-1AndMGF1Padding RSA modes.Alastair McCormack

1 Answers

1
votes

There are multiple (many) issues with your code

The main issue (why you get incorrect decrypted text) is in the ciphertext encoding. The ciphertext you are decrypting with 3DES is different than the one you got from the encryption (your "hex encoding" is simply buggy). Just debug you program (and print the values after encryption and before decryption) and you should find it. I'd advice using something standard, such as working hexadecimal or base64 encoding.

Other issues:

  • you are using "textbook RSA" which is not really secure, so I hope you are doing that for learning / assignment purposes, not real life encryption application. As already commented, using RSA should be always with padding (e.g. RSA/ECB/PKCS1Padding or OAEP)
  • Generating random keys - you should use SecureRandom instead of Random (which is not really random) or - much better - a KeyGenerator
  • DESede without providing any IV is using ECB mode, which has its weaknesses. So using symmetric encryption you should provide random IV and specify the encryption mode explicitly (e.g. DESede/CBC/PKCS5Padding)
  • for each operation after doFinal() you should use a new Cipher instance with initialized decrpytion mode

I have a blog about encryption with a few examples, you may take inspiration from.