How to implement twofish encryption to encrypt/decrypt strings in java?

1.6k Views Asked by At

i recently downloaded twofish-java.zip from https://www.schneier.com/academic/twofish/download.html . There is a jar file inside it twofish.jar. Some one explain me how to implement twofish encryption in java to encrypt/decrypt strings in java using this jar file

1

There are 1 best solutions below

0
On

You need to implement the functions blockEncrypt() and blockDecrypt() and build an mode of operation around them. Keys are created with the makeKey() function, which requires a key length of 8, 16, 24 or 32 bytes. Make sure that the plaintext is padded to a multiple of 16 bytes. I have attached my code for ECB and CBC mode with Twofish. I would recommend you to implement your own padding function and key expansion function if you want the best security. In my example, the same key is used for each block and the plaintext is only padded with 0 at the end.

static byte[] ecbEncrypt(byte[] plaintext, byte[] key) throws InvalidKeyException {
    byte[] pt = pad(plaintext, 16);
    byte[] ciphertext = new byte[pt.length];
    for (int i = 0; i < pt.length; i += 16) {
        byte[] t = Twofish_Algorithm.blockEncrypt(pt, i, Twofish_Algorithm.makeKey(key));
        for (int j = i; j < i + 16; j++) 
            ciphertext[j] = t[j % 16];
    }
    return ciphertext;
}

static byte[] ecbDecrypt(byte[] ciphertext, byte[] key) throws InvalidKeyException {
    byte[] plaintext = new byte[ciphertext.length];
    for (int i = 0; i < ciphertext.length; i += 16) {
        byte[] t = Twofish_Algorithm.blockDecrypt(ciphertext, i, Twofish_Algorithm.makeKey(key));
        for (int j = i; j < i + 16; j++) 
            plaintext[j] = t[j % 16];
    }
    return unpad(plaintext);
}
static byte[] cbcEncrypt(byte[] plaintext, byte[] key, byte[] iv) throws InvalidKeyException {
    byte[] pt = pad(plaintext, 16);
    byte[] ciphertext = new byte[pt.length];
    for (int i = 0; i < 16; i++)
        pt[i] ^= iv[i];
    byte[] t = Twofish_Algorithm.blockEncrypt(pt, 0, Twofish_Algorithm.makeKey(key));
    for (int i = 0; i < 16; i++)
        ciphertext[i] = t[i];
    for (int i = 16; i < pt.length; i += 16) {
        for (int j = 0; j < 16; j++)
            pt[i + j] ^= ciphertext[i - 16 + j];
        byte[] t2 = Twofish_Algorithm.blockEncrypt(pt, i, Twofish_Algorithm.makeKey(key));
        for (int j = 0; j < 16; j++)
            ciphertext[i + j] = t2[j];
    }
    return ciphertext;
}

static byte[] cbcDecrypt(byte[] ciphertext, byte[] key, byte[] iv) throws InvalidKeyException {
    byte[] plaintext = new byte[ciphertext.length];
    byte[] t = Twofish_Algorithm.blockDecrypt(ciphertext, 0, Twofish_Algorithm.makeKey(key));
    for (int i = 0; i < 16; i++) 
        plaintext[i] = (byte) (t[i] ^ iv[i]);
    for (int i = 16; i < ciphertext.length; i += 16) {
        byte[] t2 = Twofish_Algorithm.blockDecrypt(ciphertext, i, Twofish_Algorithm.makeKey(key));
        for (int j = 0; j < 16; j++)
            plaintext[i + j] = (byte) (t2[j] ^ ciphertext[i - 16 + j]);
    }
    return unpad(plaintext);
}
static byte[] pad(byte[] in, int blockSize) {
    byte[] ret = new byte[in.length + blockSize - in.length % blockSize];
    for (int i = 0; i < in.length; i++) 
        ret[i] = in[i];
    byte paddedBytes = 0;
    for (int i = in.length; i < ret.length - 1; i++) {
        ret[i] = 0;
        paddedBytes++;
    }
    ret[ret.length - 1] = paddedBytes;
    return ret;
}

static byte[] unpad(byte[] in) {
    byte[] ret = new byte[in.length - in[in.length - 1] - 1];
    for (int i = 0; i < ret.length; i++) 
        ret[i] = in[i];
    return ret;
}

This implementation is probably not going to be perfect, so feel free to write me improvements so I can edit my response.

You can call the functions like this:

SecureRandom sr = new SecureRandom();

byte[] plaintext = "This is secret plaintext".getBytes();
byte[] key = new byte[16];
byte[] iv = new byte[16];
sr.nextBytes(key);
sr.nextBytes(iv);

System.out.println("Plaintext: " + new String(plaintext));
byte[] ecbCiphertext = ecbEncrypt(plaintext, key);
System.out.println("ECB-Ciphertext: " + new String(ecbCiphertext));
byte[] ecbPlaintext = ecbDecrypt(ecbCiphertext, key);
System.out.println("ECB-Plaintext: " + new String(ecbPlaintext));
byte[] cbcCiphertext = cbcEncrypt(plaintext, key, iv);
System.out.println("CBC-Ciphertext: " + new String(cbcCiphertext));
byte[] cbcPlaintext = cbcDecrypt(cbcCiphertext, key, iv);
System.out.println("CBC-Plaintext: " + new String(cbcPlaintext));
Plaintext: This is secret plaintext
ECB-Ciphertext: ÑìÔõ¬ŽÁ@γ÷ÊÑ–1—N,/ )ë+$
ECB-Plaintext: This is secret plaintext
CBC-Ciphertext: JÉÌÙ•=Hæí_•¤iÔ[%˜Å?ÆÍæ“!Ø?%
CBC-Plaintext: This is secret plaintext

If you want a way to encrypt/decrypt using Counter Mode, I have appended my implementation for that too.

static byte[] ctrEncrypt(byte[] plaintext, byte[] key, byte[] iv) throws InvalidKeyException {
    byte[] initializationVector = Arrays.copyOf(iv, iv.length);
    byte[] counter = { -128, -128, -128, -128, -128, -128, -128, -128 };
    byte[] ciphertext = new byte[plaintext.length];
    for (int i = 0; i < plaintext.length / 16 + 1; i++) {
        for (int j = 0; j < 8; j++) {
            if (counter[j] == 127 && j != 7) {                  counter[j] = -128;
                counter[j + 1]++;
            }
            if (counter[j] != -128)
                initializationVector[15 - j] = counter[j];
            else
                initializationVector[15-j] = iv[15-j];
        }
        byte[] t = Twofish_Algorithm.blockEncrypt(initializationVector, 0, Twofish_Algorithm.makeKey(key));
        for (int j = 0; i < plaintext.length / 16 ? j < 16 : j < plaintext.length % 16; j++)
            ciphertext[i * 16 + j] = (byte) (plaintext[i * 16 + j] ^ t[j]);
        counter[0]++;
    }
    return ciphertext;
}

static byte[] ctrDecrypt(byte[] ciphertext, byte[] key, byte[] iv) throws InvalidKeyException {
    return ctrEncrypt(ciphertext, key, iv);
}