0

I am working on a Java application which requires I use two keys generated from different Strings for encrypting and decrypting. One String is coming from user and other is master key. I looked on net and found a few references regarding it. I would really like some help in knowing how to implement this. I will show what I have now.

So as you can see from code, I used some code from other stackoverflow post and modified it a bit. I just don't know how to generate the 2 keys from 2 Strings and from where I can get the SecretKey desKey used for decryption.

Code :

public class Encryption {

public void doStuff() {

    String plaintext = "abc";

    SecretKey k1 = generateDESkey();
    SecretKey k2 = generateDESkey();


    String firstEncryption = desEncryption(plaintext, k1);
    String decryption = desDecryption(firstEncryption, k2);
    String secondEncryption = desEncryption(decryption, k1);

    System.out.println(firstEncryption);
    System.out.println(decryption);
    System.out.println(secondEncryption);
}

public static SecretKey generateDESkey() {
    KeyGenerator keyGen = null;
    try {
        keyGen = KeyGenerator.getInstance("DESede");
    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(Test.class
                .getName()).log(Level.SEVERE, null, ex);
    }
    try {
        assert keyGen != null;
        keyGen.init(112); // key length 56
        return keyGen.generateKey();
    } catch (NullPointerException ex){
        return null;
    }
}


public static String desEncryption(String strToEncrypt, SecretKey desKey) {
    try {
        Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, desKey);
        return Base64.encode(cipher.doFinal(strToEncrypt.getBytes()));
    } catch (NoSuchAlgorithmException | NoSuchPaddingException |
            IllegalBlockSizeException | BadPaddingException |
            InvalidKeyException ex) {
        Logger.getLogger(Test.class
                .getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}


public static String desDecryption(String strToDecrypt, SecretKey desKey) {
    try {
        Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, desKey);
        return new String(cipher.doFinal(Base64.decode(strToDecrypt)));

    } catch (NoSuchAlgorithmException |  BadPaddingException | IllegalBlockSizeException
            | InvalidKeyException | NoSuchPaddingException ex) {
        Logger.getLogger(Test.class
                .getName()).log(Level.SEVERE, null, ex);
    }
    return null;
}

}

If there is any confusion or doubts about it. Kindly let me know.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
We are Borg
  • 5,117
  • 17
  • 102
  • 225
  • So what is the problem with the current code? Any exceptions like BadPaddingException? – Artjom B. Mar 05 '15 at 10:43
  • @ArtjomB. I changed it to DESede, but how can I generate keys from String for DESede? Plus I am looking how can I decrypt using combination of the 2 keys? – We are Borg Mar 05 '15 at 10:49
  • Also, it seems you are doing a triple Triple DES. Is that wanted? – Stefano Sanfilippo Mar 05 '15 at 12:31
  • 1
    Please can you edit your title to describe your problem, not your goal. – Duncan Jones Mar 05 '15 at 12:37
  • @Duncan To Be honest, I don't really know much about cryptography implementation, I would like to use to generate two keys from plain string, and use them for encryption/decryption. – We are Borg Mar 05 '15 at 12:58
  • @WeareBorg I understand that. So clearly you started trying to achieve that ***goal***. But then you encountered a ***problem*** that stopped you going any further. Make your title reflect that ***problem***. – Duncan Jones Mar 05 '15 at 13:01
  • @Duncan : Now it reflects what else is remaining. Thank you for your patience. – We are Borg Mar 05 '15 at 13:10
  • @WeareBorg Nope, it still reflects your goal. An example of a good question title would be somehting like "*FooException received while trying to generate DES key from string*". – Duncan Jones Mar 05 '15 at 13:13
  • @WeareBorg Please don't change a question significantly after there is an answer. I rolled back your last edit. I guess your answer is here: http://stackoverflow.com/questions/20047418/pbkdf2-with-hmac-in-java – Artjom B. Mar 05 '15 at 14:44
  • @ArtjomB. Thanks .. :-) But your answer put me on track with proper methods, no need to edit them.. ;-) – We are Borg Mar 05 '15 at 14:46

1 Answers1

3

Answer for the code before it was changed.

You're trying to do DESede with only two keys instead of three.

That might generally work, but not as you've written. The problem is the padding. In the second step, you try to decrypt the ciphertext with an other key than with what it was encrypted, so the decryption will fail more than 255 out of 256 times, because the padding will be wrong (also because you use Base64 encoding where it is not necessary).

If you really want to do it, you will have to decrypt without padding and without Base64 encoding. The good thing is that the unencoded ciphertext is already a multiple of the blocksize, so there is no stopping you to use "DES/ECB/NoPadding".

public static void main(String[] args) {
    // First I would like to create keys by giving Strings
    SecretKey k1 = generateDESkey();
    SecretKey k2 = generateDESkey();

    // encryption
    byte[] firstEncryption = desEncryption("plaintext".getBytes("UTF-8"), k1, false);
    byte[] decryption = desDecryption(firstEncryption, k2, true);
    byte[] secondEncryption = desEncryption(decryption, k1, true);

    // decryption
    byte[] firstDecryption = desDecryption(secondEncryption, k1, true);
    byte[] encryption = desEncryption(firstDecryption, k2, true);
    byte[] secondDecryption = desDecryption(encryption, k1, false);

    System.out.println(new String(secondDecryption)); // plaintext
}

public static byte[] desEncryption(byte[] strToEncrypt, SecretKey desKey, boolean noPadding) {
    try {
        Cipher cipher = Cipher.getInstance(noPadding ? "DES/ECB/NoPadding" : "DES/ECB/PKCS5Padding");
        cipher.init(Cipher.ENCRYPT_MODE, desKey);
        return cipher.doFinal(strToEncrypt);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

public static byte[] desDecryption(byte[] strToDecrypt, SecretKey desKey, boolean noPadding) {
    try {
        Cipher cipher = Cipher.getInstance(noPadding ? "DES/ECB/NoPadding" : "DES/ECB/PKCS5Padding");
        cipher.init(Cipher.DECRYPT_MODE, desKey);
        return cipher.doFinal(strToDecrypt);
    } catch (Exception ex) {
        ex.printStackTrace();
    }
    return null;
}

This is actually an equivalent implementation of DESede with two keys when the general key is constructed in this way:

SecretKey k1 = generateDESkey();
SecretKey k2 = generateDESkey();

byte[] edeKeyBytes = new byte[24];
System.arraycopy(k1.getEncoded(), 0, edeKeyBytes, 0, 8);
System.arraycopy(k2.getEncoded(), 0, edeKeyBytes, 8, 8);
System.arraycopy(k1.getEncoded(), 0, edeKeyBytes, 16, 8);

edeKey = new SecretKeySpec(edeKeyBytes, "DESede");

Cipher cipher = Cipher.getInstance("DESede/ECB/PKCS5Padding");
cipher.init(Cipher.ENCRYPT_MODE, edeKey);

System.out.println(Base64.encode(cipher.doFinal("plaintext".getBytes("UTF-8"))));

DESede uses three keys which we will call k1, k2 and k3. All of them are concatenated into a single byte array. In your case k1 is used a second time in place of k3.

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Thank you for your answer, this helps a lot. How are you generating the keys from plain String, I didn't see that in your code. – We are Borg Mar 05 '15 at 13:00
  • I don't. If the strings are not key material, but rather some kind of password, then you can use something like PBKDF2 to derive the key from the string. – Artjom B. Mar 05 '15 at 14:38
  • I will check it, but incase if you have some example how to derive key from String, please let me know. – We are Borg Mar 05 '15 at 14:40
  • @ArtjomB. thanks for mentioning this question, it works, but if I want to use custom user key with `PBEWithMD5AndDES` instance, do you know how to do it? – Firas Al Mannaa Apr 11 '15 at 22:54
  • @FirasAlMannaa No, I don't know what that entails off the top of my head. I haven't used PBEWithXAndY, yet. – Artjom B. Apr 11 '15 at 22:59
  • what if I want to decrypt the encrypted text but after converting it to string, so I'll encrypt the string, convert the byte array to string, and then decrypt the string value, not the byte array. I'm trying to do it but i'm getting this error `javax.crypto.IllegalBlockSizeException: Input length not multiple of 8 bytes`, how can I do it? – Firas Al Mannaa Apr 14 '15 at 18:11
  • 2
    @FirasAlMannaa If you convert the `byte[]` to `String` then you need to do it losslessly. For example by encoding it with Base64. Simply using the `new String(byte[])` constructor will result in loss of bytes, because ciphertexts may have any byte value, but string encodings only support some byte values as printable characters. – Artjom B. Apr 14 '15 at 18:14