The program here uses CBC mode (Cipher Block Chaining mode) to encrypt the data. First a random 8-byte (64-bit) Initialization Vector is appended to the beginning of the data. This block is encrypted first; then the encrypted block is XOR'd with the next plain text block (the first 8 bytes of the target file to be encrypted) before it is encrypted. The result of that encryption is then X0R'd with the next plain text block (the second 8 bytes of the target file) before that block is encrypted. And so on.
Note: If you do not append the Initialization Vector to the beginning of the string to be encrypted, the encrypted text will not decrypt properly; rather, the first 8 bytes will be garbled. But with the Initialization Vector appended to the beginning of the string to be encrypted, the subsequent decryption will yield an extraneous garbage vector as the first 8 bytes of the decrypted text. At that point the first 8 bytes can be disgarded, leaving the original plaintext file.
The test3des1_CBC.java program:
In this example, we see see the following five numbers:
mport java.io.*; import java.security.*; import java.math.*; import cryptix.util.core.BI; import cryptix.util.core.ArrayUtil; import cryptix.util.core.Hex; import cryptix.provider.key.*; class test3des1_CBC { public static void main (String[] args) { try { FileOutputStream outFile1 = new FileOutputStream("DES-EDE3.out"); // Note: PrintStream is deprecated, but still works fine in jdk1.1.7b PrintStream output1 = new PrintStream(outFile1); // convert a string to a 3DES key and print out the result RawSecretKey key2 = new RawSecretKey(" DES-EDE3",Hex.fromString("3812A419C63BE771AD9F61FEFA20CE633812A419C63BE771")); RawKey rkey = (RawKey) key2; byte[] yval = rkey.getEncoded(); BigInteger Bkey = new BigInteger(yval); String w = cryptix.util.core.BI.dumpString(Bkey); output1.println("The Encryption Key = " + w); // convert a string to an initialization vector and print out the result byte[] iv = new byte[8]; iv = Hex.fromString("CCF3454D1E9CCDE0"); Bkey = new BigInteger(iv); w = cryptix.util.core.BI.dumpString(Bkey); output1.println("The Initialization Vector = " + w); // use the 3DES key and initialization vector to encrypt a string in cipher block chaining (CBC) mode Cipher des=Cipher.getInstance("DES-EDE3/CBC/NONE","Cryptix"); des.initEncrypt(key2); byte[] ciphertext = des.crypt(Hex.fromString("CCF3454D1E9CCDE001010101010101010102030405060708090A0B0C0D0E0F101112131415161718")); // print out length and representation of ciphertext output1.print("\n"); output1.println("ciphertext.length = " + ciphertext.length); BigInteger Bciph = new BigInteger(ciphertext); w = cryptix.util.core.BI.dumpString(Bciph); output1.println("Ciphertext resulting from 3DES encryption = " + w); // decrypt ciphertext des.initDecrypt(key2); ciphertext = des.crypt(ciphertext); output1.print("\n"); output1.println("plaintext.length = " + (ciphertext.length-8)); // print out representation of decrypted ciphertext (start with byte 9) byte[] bt = new byte[ciphertext.length-8]; int i; for(i=8;i<ciphertext.length;i++) bt[i-8] = ciphertext[i]; Bciph = new BigInteger(bt); w = cryptix.util.core.BI.dumpString(Bciph); output1.println("Plaintext for 3DES encryption = " + w); output1.println(" "); // print out representation of decrypted ciphertext (start with byte 0) Bciph = new BigInteger(ciphertext); w = cryptix.util.core.BI.dumpString(Bciph); output1.println("Plaintext with Garbage Vector = " + w); output1.println(" "); output1.close(); } catch (Exception e) { System.err.println("Caught exception " + e.toString()); } }}
The Encryption Key = Multi-Precision Integer 190 bits long... sign: Positive magnitude: 3812A419C63BE771 AD9F61FEFA20CE63 3812A419C63BE771 The Initialization Vector = Multi-Precision Integer 62 bits long... sign: Negative magnitude: CCF3454D1E9CCDE0 ciphertext.length = 40 Ciphertext resulting from 3DES encryption = Multi-Precision Integer 319 bits long... sign: Positive magnitude: Hexadecimal dump of 40 bytes... 0: 5D505DD99BC8AC65 B25D48D2A6755630 D987EEEDD7E10F63 0EAE5063EC17B0C6 32: 8E37124A8E4C6B13 plaintext.length = 32 Plaintext for 3DES encryption = Multi-Precision Integer 249 bits long... sign: Positive magnitude: 0101010101010101 0102030405060708 090A0B0C0D0E0F10 1112131415161718 Plaintext with Garbage Vector = Multi-Precision Integer 319 bits long... sign: Positive magnitude: Hexadecimal dump of 40 bytes... 0: 42C4570790D0A6F3 0101010101010101 0102030405060708 090A0B0C0D0E0F10 32: 1112131415161718
J. Orlin Grabbe is the author of International Financial Markets, and is an internationally recognized derivatives expert who has recently branched out into cryptology, banking security, and digital cash. His home page is located at http://www.aci.net/kalliste/homepage.html. He currently resides in Costa Rica.