All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.fasteasytrade.jrandtest.algo.ZAC5 Maven / Gradle / Ivy

The newest version!
/*
 * Created on 12/04/2005
 *
 * JRandTest package
 *
 * Copyright (c) 2005, Zur Aougav, [email protected]
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met:
 * 
 * Redistributions of source code must retain the above copyright notice, this list 
 * of conditions and the following disclaimer. 
 * 
 * Redistributions in binary form must reproduce the above copyright notice, this 
 * list of conditions and the following disclaimer in the documentation and/or 
 * other materials provided with the distribution. 
 * 
 * Neither the name of the JRandTest nor the names of its contributors may be 
 * used to endorse or promote products derived from this software without specific 
 * prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 
 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 
 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package com.fasteasytrade.jrandtest.algo;

import java.util.Random;

/**
 * ZAC5 encryption algorithm Copyright (c) 2005 Zur Aougav
 * 

* Symetric algorithm. *

* Use 5 ARC4 keys: *

    *
  • prePermutationKey to permute input buffer before encryption begins *
  • cryptKey to encrypt input bytes, *
  • fillKey to add bytes to output, *
  • controlKey to control swapping between each two bytes - ciphered byte * and fill byte. *
  • postPermutationKey to permute ciphered output buffer after encryption *
*

* Hence, ciphered text length is double input's length. *

* Before encryption starts, each key is skipped a random number of times (with * 4096 <= skip <= 69631). SHA1 digest message (20 bytes) is calculated from the * invisible key output. The 20 bytes should be written at the header of the * ciphered message/file. Of course, decryption does the reverse, read the hash * 20 bytes, and step each key with a check if digest message arrived at is the * correct one. Hence, the random number of steps is never exposed directly, but * the hash contains implicitly the correct position. * * @author Zur Aougav */ public class ZAC5 extends Cipher { /** * encrypt and decrypt data using cryptKey */ RC4Key cryptKey; /** * add one byte for each encrypt data byte */ RC4Key fillKey; /** * controlKey gives one byte to enable swap of encrypt data and fill data * (from fillKey) */ RC4Key controlKey; /** * prePermutationKey permutes input buffer before encryption begins */ RC4Key prePermutationKey; /** * postPermutationKey permutes ciphered output buffer after encryption * completed */ RC4Key postPermutationKey; /** * cryptKey is processed cryptSkip times, and prng data is hashed using * sha1. Digest "message" is kept in cryptShaDigest. */ byte[] cryptShaDigest; /** * fillKey is processed fillSkip times, and prng data is hashed using sha1. * Digest "message" is kept in fillShaDigest. */ byte[] fillShaDigest; /** * controlKey is processed controlSkip times, and prng data is hashed using * sha1. Digest "message" is kept in controlShaDigest. */ byte[] controlShaDigest; /** * prePermutationKey is processed prePermutationSkip times, and prng data is * hashed using sha1. Digest "message" is kept in prePermutationShaDigest. */ byte[] prePermutationShaDigest; /** * postPermutationKey is processed postPermutationSkip times, and prng data * is hashed using sha1. Digest "message" is kept in * postPermutationShaDigest. */ byte[] postPermutationShaDigest; /** * Original key bytes buffer for cryptKey */ byte[] cryptBuf; /** * Original key bytes buffer for fillKey */ byte[] fillBuf; /** * Original key bytes buffer for controlKey */ byte[] controlBuf; /** * Original key bytes buffer for prePermutationKey */ byte[] prePermutationBuf; /** * Original key bytes buffer for postPermutationKey */ byte[] postPermutationBuf; /** * random number we skip cryptKey before start using it. */ int cryptSkip; /** * random number we skip fillKey before start using it. */ int fillSkip; /** * random number we skip controlKey before start using it. */ int controlSkip; /** * random number we skip prePermutationKey before start using it. */ int prePermutationSkip; /** * random number we skip postPermutationKey before start using it. */ int postPermutationSkip; /** * Boolean flag if we ever find an incorrect fill byte in data. *

* Only used while decryption. *

* If true, we fill (silently) all output data with random data from rnd * variable. */ boolean garbage = false; /** * Use java random class to *

    *
  1. fill new keys *
  2. put some garbage bytes in output buffer (if decryption fails). *
*/ java.util.Random rnd = new Random(); /** * input and output buffers are permuted numCyclesOfPermutations times */ int numCyclesOfPermutations = 4; /** * default constructor - does nothing. * */ public ZAC5() { super(); } /** * constructor with 5 keys to setup. * * @param cryptBuf * kept in obejct cryptBuf and init cryptKey * @param fillBuf * kept in obejct fillBuf and init fillKey * @param controlBuf * kept in obejct controlBuf and init controlKey * @param prePermutationBuf * kept in obejct prePerbutation and init prePermutationKey * @param postPermutationBuf * kept in obejct postPerbutation and init postPermutationKey */ public ZAC5(byte[] cryptBuf, byte[] fillBuf, byte[] controlBuf, byte[] prePermutationBuf, byte[] postPermutationBuf) { setup(cryptBuf, fillBuf, controlBuf, prePermutationBuf, postPermutationBuf); } /** * setup 5 keys to ZAC5 algorithm. If one of the input buffers is null, we * fill it with 256 random bytes. *

* keep keys and skip data in object so initEncrypt() and reset() can run * properly. * * @param cryptBuf * 256 bytes to cryptKey * @param fillBuf * 256 bytes to fillKey * @param controlBuf * 256 bytes to controlKey * @param prePermutationBuf * 256 bytes to prePermutationKey * @param postPermutationBuf * 256 bytes to postPermutationKey */ public void setup(byte[] cryptBuf, byte[] fillBuf, byte[] controlBuf, byte[] prePermutationBuf, byte[] postPermutationBuf) { if (cryptBuf == null) { cryptBuf = new byte[256]; rnd.nextBytes(cryptBuf); } if (fillBuf == null) { fillBuf = new byte[256]; rnd.nextBytes(fillBuf); } if (controlBuf == null) { controlBuf = new byte[256]; rnd.nextBytes(controlBuf); } if (prePermutationBuf == null) { prePermutationBuf = new byte[256]; rnd.nextBytes(prePermutationBuf); } if (postPermutationBuf == null) { postPermutationBuf = new byte[256]; rnd.nextBytes(postPermutationBuf); } this.cryptBuf = cryptBuf; this.fillBuf = fillBuf; this.controlBuf = controlBuf; this.prePermutationBuf = prePermutationBuf; this.postPermutationBuf = postPermutationBuf; cryptKey = new RC4Key(cryptBuf, 0, null); fillKey = new RC4Key(fillBuf, 0, null); controlKey = new RC4Key(controlBuf, 0, null); prePermutationKey = new RC4Key(prePermutationBuf, 0, null); postPermutationKey = new RC4Key(postPermutationBuf, 0, null); cryptSkip = rnd.nextInt(0xffff); fillSkip = rnd.nextInt(0xffff); controlSkip = rnd.nextInt(0xffff); prePermutationSkip = rnd.nextInt(0xffff); postPermutationSkip = rnd.nextInt(0xffff); } /** * init keys, using hash on prng of each key. Digest message generated from * key xyz is kept as xyzShaDigest variable. *

* initEncrypt method is run before encryption starts. */ public void initEncrypt() { int i; SHA1 sha = new SHA1(); for (i = 0; i < 4096; i++) { sha.update(cryptKey.next()); } for (i = 0; i < cryptSkip; i++) { sha.update(cryptKey.next()); } cryptShaDigest = sha.digest8(); for (i = 0; i < 4096; i++) { sha.update(fillKey.next()); } for (i = 0; i < fillSkip; i++) { sha.update(fillKey.next()); } fillShaDigest = sha.digest8(); for (i = 0; i < 4096; i++) { sha.update(controlKey.next()); } for (i = 0; i < controlSkip; i++) { sha.update(controlKey.next()); } controlShaDigest = sha.digest8(); for (i = 0; i < 4096; i++) { sha.update(prePermutationKey.next()); } for (i = 0; i < prePermutationSkip; i++) { sha.update(prePermutationKey.next()); } prePermutationShaDigest = sha.digest8(); for (i = 0; i < 4096; i++) { sha.update(postPermutationKey.next()); } for (i = 0; i < prePermutationSkip; i++) { sha.update(postPermutationKey.next()); } postPermutationShaDigest = sha.digest8(); } /** * encrypt buffer. each input byte becomes two bytes, by adding one byte * from fillKey. The byte from controlKey is controlling the order of the * two result bytes: *

* if control_byte is even
* then output order is concat(encrypted_data_byte, fill_byte),
* else output order is concat(fill_byte, encrypted_data_byte)
*

* input buffer length must be >= 256 bytes.
* prePermutation input buffer inplace.
* caller gets back a clear input buffer (full of 0x00). *

* output buffer length must be twice the size/length of input buffer. * * @param inputBuf * input bytes buffer, length n * @param outputBuf * output encrypted bytes buffer, must be length 2n * @return returns FALSE if inputs are null or lengths are not correct. * Else, encrypt data and returns TRUE. */ public boolean encrypt(byte[] inputBuf, byte[] outputBuf) { if (inputBuf == null || outputBuf == null || inputBuf.length < 256 || 2 * inputBuf.length != outputBuf.length) { return false; } int i, j, k; byte temp; /** * prePermutation input buffer inplace */ for (j = 0; j < numCyclesOfPermutations; j++) { for (i = 0; i < inputBuf.length; i++) { k = 0xff & prePermutationKey.next(); k = (k << 8) | (0xff & prePermutationKey.next()); k %= inputBuf.length; /** * swap inputBuf(i, k) */ if (i != k) { temp = inputBuf[i]; inputBuf[i] = inputBuf[k]; inputBuf[k] = temp; } } } /** * encrypt input buffer into output buffer using controlKey to order * each two bytes of encrypted_data and fillKey_data */ for (i = 0; i < inputBuf.length; i++) { byte data = (byte)(inputBuf[i] ^ cryptKey.next()); byte fill = fillKey.next(); int control = 0xff & controlKey.next(); if (control % 2 == 0) { outputBuf[i * 2] = data; outputBuf[i * 2 + 1] = fill; } else { outputBuf[i * 2] = fill; outputBuf[i * 2 + 1] = data; } } /** * fill inputBuf with low-values */ java.util.Arrays.fill(inputBuf, 0, inputBuf.length, (byte)0x00); /** * postPermutation output buffer inplace */ for (j = 0; j < numCyclesOfPermutations; j++) { for (i = 0; i < outputBuf.length; i++) { k = 0xff & postPermutationKey.next(); k = (k << 8) | (0xff & postPermutationKey.next()); k %= outputBuf.length; /** * swap outputBuf(i, k) */ if (i != k) { temp = outputBuf[i]; outputBuf[i] = outputBuf[k]; outputBuf[k] = temp; } } } return true; } /** * init keys, using hash on prng of each key. Digest message generated from * key xyz is compared with xyzShaDigest variable. *

* initDecrypt method is run before decryption starts. * * @return true if all skip counters are found, and state is ready to * decrypt cipher data. Else, false. */ public boolean initDecrypt(byte[] cryptShaDigest, byte[] fillShaDigest, byte[] controlShaDigest, byte[] prePermutationShaDigest, byte[] postPermutationShaDigest) { int i; SHA1 sha = new SHA1(); boolean foundSkip; for (i = 0; i < 4096; i++) { sha.update(cryptKey.next()); } /** * search for cryptSkip between 0 and 0xffff. */ foundSkip = false; for (i = 0; !foundSkip && i < 0xffff; i++) { sha.update(cryptKey.next()); this.cryptShaDigest = ((SHA1)sha.clone()).digest8(); if (compareBytes(this.cryptShaDigest, cryptShaDigest)) { cryptSkip = i; // just for debug foundSkip = true; } } if (!foundSkip) { return false; } sha.digest8(); // just to reset SHA1 for (i = 0; i < 4096; i++) { sha.update(fillKey.next()); } /** * search for fillSkip between 0 and 0xffff. */ foundSkip = false; for (i = 0; !foundSkip && i < 0xffff; i++) { sha.update(fillKey.next()); this.fillShaDigest = ((SHA1)sha.clone()).digest8(); if (compareBytes(this.fillShaDigest, fillShaDigest)) { fillSkip = i; // just for debug foundSkip = true; } } if (!foundSkip) { return false; } sha.digest8(); // just to reset SHA1 for (i = 0; i < 4096; i++) { sha.update(controlKey.next()); } /** * search for controlSkip between 0 and 0xffff. */ foundSkip = false; for (i = 0; !foundSkip && i < 0xffff; i++) { sha.update(controlKey.next()); this.controlShaDigest = ((SHA1)sha.clone()).digest8(); if (compareBytes(this.controlShaDigest, controlShaDigest)) { controlSkip = i; // just for debug foundSkip = true; } } if (!foundSkip) { return false; } sha.digest8(); // just to reset SHA1 for (i = 0; i < 4096; i++) { sha.update(prePermutationKey.next()); } /** * search for prePermutationSkip between 0 and 0xffff. */ foundSkip = false; for (i = 0; !foundSkip && i < 0xffff; i++) { sha.update(prePermutationKey.next()); this.prePermutationShaDigest = ((SHA1)sha.clone()).digest8(); if (compareBytes(this.prePermutationShaDigest, prePermutationShaDigest)) { prePermutationSkip = i; // just for debug foundSkip = true; } } if (!foundSkip) { return false; } sha.digest8(); // just to reset SHA1 for (i = 0; i < 4096; i++) { sha.update(postPermutationKey.next()); } /** * search for postPermutationSkip between 0 and 0xffff. */ foundSkip = false; for (i = 0; !foundSkip && i < 0xffff; i++) { sha.update(postPermutationKey.next()); this.postPermutationShaDigest = ((SHA1)sha.clone()).digest8(); if (compareBytes(this.postPermutationShaDigest, postPermutationShaDigest)) { postPermutationSkip = i; // just for debug foundSkip = true; } } if (!foundSkip) { return false; } return true; } /** * decrypt buffer. Two input bytes become one byte. Determin where is the * ciphred data and the fill byte using rhe control byte. *

* if control_byte is even
* then input order is concat(encrypted_data_byte, fill_byte),
* else input order is concat(fill_byte, encrypted_data_byte)
*

* If filler byte is in correctwe o not alert if filler byte * * @param inputBuf * input ciphered bytes buffer, length 2n * @param outputBuf * output data bytes buffer, must be length n * @param len * intput buffer length * @return returns FALSE if inputs are null or lengths are not correct. * Else, encrypt data and returns TRUE. */ public boolean decrypt(byte[] inputBuf, byte[] outputBuf, int len) { if (inputBuf == null || outputBuf == null || outputBuf.length < 256 || inputBuf.length != 2 * outputBuf.length) { return false; } if (garbage) { rnd.nextBytes(outputBuf); return true; } int i, j, k; byte temp; byte[] vectemp = new byte[inputBuf.length * 2 * numCyclesOfPermutations]; /** * reverse order of postPermutation */ for (i = 0; i < inputBuf.length * 2 * numCyclesOfPermutations; i++) { vectemp[i] = postPermutationKey.next(); } for (j = inputBuf.length * 2 * numCyclesOfPermutations - 1; j > -1;) { for (i = inputBuf.length - 1; i > -1; i--) { k = ((0xff & vectemp[j - 1]) << 8) | (0xff & vectemp[j]); k %= inputBuf.length; j -= 2; /** * swap inputBuf(i, k) */ if (i != k) { temp = inputBuf[i]; inputBuf[i] = inputBuf[k]; inputBuf[k] = temp; } } } /** * decrypt input buffer into output buffer, using controlKey to discard * the fillKey data */ for (i = 0; i < len / 2; i++) { byte fill = fillKey.next(); int control = 0xff & controlKey.next(); if (control % 2 == 0) { if (inputBuf[i * 2 + 1] != fill) { garbage = true; break; } outputBuf[i] = (byte)(inputBuf[i * 2] ^ cryptKey.next()); } else { if (inputBuf[i * 2] != fill) { garbage = true; break; } outputBuf[i] = (byte)(inputBuf[i * 2 + 1] ^ cryptKey.next()); } } if (garbage) { rnd.nextBytes(outputBuf); return true; } /** * reverse order of prePermutation */ for (i = 0; i < outputBuf.length * 2 * numCyclesOfPermutations; i++) { vectemp[i] = prePermutationKey.next(); } for (j = outputBuf.length * 2 * numCyclesOfPermutations - 1; j > -1;) { for (i = outputBuf.length - 1; i > -1; i--) { k = ((0xff & vectemp[j - 1]) << 8) | (0xff & vectemp[j]); k %= outputBuf.length; j -= 2; /** * swap outputBuf(i, k) */ if (i != k) { temp = outputBuf[i]; outputBuf[i] = outputBuf[k]; outputBuf[k] = temp; } } } return true; } /** * Reset "state" of prng by setting keys to bufkeys and skip each key. * */ public void reset() { cryptKey = new RC4Key(cryptBuf, 0, null); fillKey = new RC4Key(fillBuf, 0, null); controlKey = new RC4Key(controlBuf, 0, null); prePermutationKey = new RC4Key(prePermutationBuf, 0, null); postPermutationKey = new RC4Key(postPermutationBuf, 0, null); initEncrypt(); } /** * @return Returns the controlShaDigest. */ public byte[] getControlShaDigest() { return controlShaDigest; } /** * @return Returns the cryptShaDigest. */ public byte[] getCryptShaDigest() { return cryptShaDigest; } /** * @return Returns the fillShaDigest. */ public byte[] getFillShaDigest() { return fillShaDigest; } /** * @return Returns the postPermutationShaDigest. */ public byte[] getPostPermutationShaDigest() { return postPermutationShaDigest; } /** * @return Returns the prePermutationShaDigest. */ public byte[] getPrePermutationShaDigest() { return prePermutationShaDigest; } /** * @return Returns the controlBuf. */ public byte[] getControlBuf() { return controlBuf; } /** * @return Returns the cryptBuf. */ public byte[] getCryptBuf() { return cryptBuf; } /** * @return Returns the fillBuf. */ public byte[] getFillBuf() { return fillBuf; } /** * carefull clear of buffers in ZAC5 object * */ @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("ZAC5 finalize..."); /** * clear all keys */ cryptKey = null; fillKey = null; controlKey = null; prePermutationKey = null; postPermutationKey = null; /** * clear all keys' buffers */ java.util.Arrays.fill(cryptBuf, 0, cryptBuf.length, (byte)0x00); java.util.Arrays.fill(fillBuf, 0, fillBuf.length, (byte)0x00); java.util.Arrays.fill(controlBuf, 0, controlBuf.length, (byte)0x00); java.util.Arrays.fill(prePermutationBuf, 0, prePermutationBuf.length, (byte)0x00); java.util.Arrays.fill(postPermutationBuf, 0, postPermutationBuf.length, (byte)0x00); cryptBuf = null; fillBuf = null; controlBuf = null; prePermutationBuf = null; postPermutationBuf = null; /** * clear all sha digets' buffers */ java.util.Arrays.fill(cryptShaDigest, 0, cryptShaDigest.length, (byte)0x00); java.util.Arrays.fill(fillShaDigest, 0, fillShaDigest.length, (byte)0x00); java.util.Arrays.fill(controlShaDigest, 0, controlShaDigest.length, (byte)0x00); java.util.Arrays.fill(prePermutationShaDigest, 0, prePermutationShaDigest.length, (byte)0x00); java.util.Arrays.fill(postPermutationShaDigest, 0, postPermutationShaDigest.length, (byte)0x00); cryptShaDigest = null; fillShaDigest = null; controlShaDigest = null; prePermutationShaDigest = null; postPermutationShaDigest = null; rnd = null; } /** * Run ZAC5 Algorithm. Copyright (c) 2005 Zur Aougav *

* Command line syntax: *

* java ZAC5 [options] [ops] [inputfilename outputfilename] *

* options:
* -crf <cryptKeyFile.key>       * default: cryptKeyFile.key
* -fif <fillKeyFile.key>        * default: fillKeyFile.key
* -cof <controlKeyFile.key>     default: * controlKeyFile.key
* -prf <prePermutationKeyFile.key>     default: * prePermutationKeyFile.key
* -pof <postPermutationKeyFile.key>     default: * postPermutationKeyFile.key
*

* ops:
* -h       print this help message
* -e       encrypt inputfilename into * outputfilename
* -enc     encrypt inputfilename into outputfilename *
* -d       decrypt inputfilename into * outputfilename
* -dec     decrypt inputfilename into outputfilename *
* -compare     compare two files - inputfilename and * outputfilename
* -gen     generate random keys and write them to key * files
* * @param args * keys, operations, input and output filenames * @throws Exception * missing operands or IOExceptions */ public static void main(String[] args) throws Exception { String cryptKeyFile = "cryptKeyFile.key"; // -crf String fillKeyFile = "fillKeyFile.key"; // -fif String controlKeyFile = "controlKeyFile.key"; // -cof String prePermutationKeyFile = "prePermutationKeyFile.key"; // -prf String postPermutationKeyFile = "postPermutationKeyFile.key"; // -pof String op = null; // -e / -enc / -d / -dec / -gen String inFilename = ""; String outFilename = ""; int i = 0; System.out.println("ZAC5 Algorithm. Copyright (c) 2005 Zur Aougav \nJRandTest "); if (args == null || args.length == 0 || args[0] == null || args[0].equals("-?") || args[0].equals("-h") || args[0].equals("-help")) { System.out.println("java ZAC5 [options] [ops] [inputfilename outputfilename]"); System.out.println("options:"); System.out.println(" -crf default: cryptKeyFile.key"); System.out.println(" -fif default: fillKeyFile.key"); System.out.println(" -cof default: controlKeyFile.key"); System.out.println(" -prf default: prePermutationKeyFile.key"); System.out.println(" -pof default: postPermutationKeyFile.key"); System.out.println("ops:"); System.out.println(" -e encrypt inputfilename into outputfilename"); System.out.println(" -enc encrypt inputfilename into outputfilename"); System.out.println(" -d decrypt inputfilename into outputfilename"); System.out.println(" -dec decrypt inputfilename into outputfilename"); System.out.println(" -compare compare two files - inputfilename and outputfilename"); System.out.println(" -gen generate random keys and write them to key files"); return; } for (; i < args.length; i++) { if (args[i].equals("-crf")) { if (i + 1 >= args.length) { throw new Exception("missing cryptKeyFile name"); } cryptKeyFile = args[++i]; continue; } if (args[i].equals("-fif")) { if (i + 1 >= args.length) { throw new Exception("missing fillKeyFile name"); } fillKeyFile = args[++i]; continue; } if (args[i].equals("-cof")) { if (i + 1 >= args.length) { throw new Exception("missing controlKeyFile name"); } controlKeyFile = args[++i]; continue; } if (args[i].equals("-prf")) { if (i + 1 >= args.length) { throw new Exception("missing prePermutationKeyFile name"); } prePermutationKeyFile = args[++i]; continue; } if (args[i].equals("-pof")) { if (i + 1 >= args.length) { throw new Exception("missing postPermutationKeyFile name"); } postPermutationKeyFile = args[++i]; continue; } if (op == null && (args[i].equals("-e") || args[i].equals("-enc"))) { op = args[i]; continue; } if (op == null && (args[i].equals("-d") || args[i].equals("-dec"))) { op = args[i]; continue; } if (op == null && args[i].equals("-gen")) { op = args[i]; continue; } if (op == null && args[i].equals("-compare")) { op = args[i]; continue; } if (i + 1 >= args.length) { throw new Exception("missing outputfilename"); } inFilename = args[i]; outFilename = args[++i]; } if (op == null) { throw new IllegalArgumentException("No op specified."); } /** * gen key files */ if (op.equals("-gen")) { byte[] key = new byte[256]; java.util.Random rnd = new java.util.Random(); java.io.FileOutputStream fos = null; try { System.out.println("Generate key files..."); System.out.println("Generate random data in " + cryptKeyFile); rnd.nextBytes(key); fos = new java.io.FileOutputStream(cryptKeyFile); fos.write(key); fos.close(); System.out.println("Generate random data in " + fillKeyFile); rnd.nextBytes(key); fos = new java.io.FileOutputStream(fillKeyFile); fos.write(key); fos.close(); System.out.println("Generate random data in " + controlKeyFile); rnd.nextBytes(key); fos = new java.io.FileOutputStream(controlKeyFile); fos.write(key); fos.close(); System.out.println("Generate random data in " + prePermutationKeyFile); rnd.nextBytes(key); fos = new java.io.FileOutputStream(prePermutationKeyFile); fos.write(key); fos.close(); System.out.println("Generate random data in " + postPermutationKeyFile); rnd.nextBytes(key); fos = new java.io.FileOutputStream(postPermutationKeyFile); fos.write(key); fos.close(); } catch (Exception e) { System.out.println("Error: " + e); } return; } /** * encrypt file */ if (op.equals("-e") || op.equals("-enc")) { byte[] cryptKey = new byte[256]; byte[] fillKey = new byte[256]; byte[] controlKey = new byte[256]; byte[] prePermutationKey = new byte[256]; byte[] postPermutationKey = new byte[256]; java.io.FileOutputStream fos = null; java.io.FileInputStream fis = null; try { System.out.println("Crypt file " + inFilename + " into " + outFilename); System.out.println("Read " + cryptKeyFile); fis = new java.io.FileInputStream(cryptKeyFile); fis.read(cryptKey); fis.close(); System.out.println("Read " + fillKeyFile); fis = new java.io.FileInputStream(fillKeyFile); fis.read(fillKey); fis.close(); System.out.println("Read " + controlKeyFile); fis = new java.io.FileInputStream(controlKeyFile); fis.read(controlKey); fis.close(); System.out.println("Read " + prePermutationKeyFile); fis = new java.io.FileInputStream(prePermutationKeyFile); fis.read(prePermutationKey); fis.close(); System.out.println("Read " + postPermutationKeyFile); fis = new java.io.FileInputStream(postPermutationKeyFile); fis.read(postPermutationKey); fis.close(); System.out.println("Open input file " + inFilename); fis = new java.io.FileInputStream(inFilename); System.out.println("Open output file " + outFilename); fos = new java.io.FileOutputStream(outFilename); /** * write 8 bytes of the length of input file */ long avail = (new java.io.File(inFilename)).length(); System.out.println("avail=" + avail); byte[] vectemp = new byte[8]; i = 0; for (int j = 56; j >= 0; j -= 8) { vectemp[i++] = (byte)(avail >>> j); } fos.write(vectemp); ZAC5 algo = new ZAC5(cryptKey, fillKey, controlKey, prePermutationKey, postPermutationKey); algo.initEncrypt(); fos.write(algo.getCryptShaDigest()); fos.write(algo.getFillShaDigest()); fos.write(algo.getControlShaDigest()); fos.write(algo.getPrePermutationShaDigest()); fos.write(algo.getPostPermutationShaDigest()); byte[] buffer = new byte[256]; byte[] outbuffer = new byte[256 * 2]; // FIXME: does not fully buffer while ((fis.read(buffer)) > -1) { algo.encrypt(buffer, outbuffer); fos.write(outbuffer); } fis.close(); fos.close(); } catch (Exception e) { //System.out.println("Error: " + e); e.printStackTrace(); } return; } /** * decrypt file */ if (op.equals("-d") || op.equals("-dec")) { byte[] cryptKey = new byte[256]; byte[] fillKey = new byte[256]; byte[] controlKey = new byte[256]; byte[] prePermutationKey = new byte[256]; byte[] postPermutationKey = new byte[256]; byte[] cryptShaDigest = new byte[20]; byte[] fillShaDigest = new byte[20]; byte[] controlShaDigest = new byte[20]; byte[] prePermutationShaDigest = new byte[20]; byte[] postPermutationShaDigest = new byte[20]; java.io.FileOutputStream fos = null; java.io.FileInputStream fis = null; try { System.out.println("Decrypt file " + inFilename + " into " + outFilename); System.out.println("Read " + cryptKeyFile); fis = new java.io.FileInputStream(cryptKeyFile); fis.read(cryptKey); fis.close(); System.out.println("Read " + fillKeyFile); fis = new java.io.FileInputStream(fillKeyFile); fis.read(fillKey); fis.close(); System.out.println("Read " + controlKeyFile); fis = new java.io.FileInputStream(controlKeyFile); fis.read(controlKey); fis.close(); System.out.println("Read " + prePermutationKeyFile); fis = new java.io.FileInputStream(prePermutationKeyFile); fis.read(prePermutationKey); fis.close(); System.out.println("Read " + postPermutationKeyFile); fis = new java.io.FileInputStream(postPermutationKeyFile); fis.read(postPermutationKey); fis.close(); System.out.println("Open input file " + inFilename); fis = new java.io.FileInputStream(inFilename); System.out.println("Open output file " + outFilename); fos = new java.io.FileOutputStream(outFilename); /** * write 8 bytes of the length of input file */ long avail = 0; byte[] vectemp = new byte[8]; fis.read(vectemp); for (i = 0; i < 8; i++) { avail = (avail << 8) | (0xffL & vectemp[i]); } System.out.println("avail=" + avail); fis.read(cryptShaDigest); fis.read(fillShaDigest); fis.read(controlShaDigest); fis.read(prePermutationShaDigest); fis.read(postPermutationShaDigest); ZAC5 algo = new ZAC5(cryptKey, fillKey, controlKey, prePermutationKey, postPermutationKey); if (!algo.initDecrypt(cryptShaDigest, fillShaDigest, controlShaDigest, prePermutationShaDigest, postPermutationShaDigest)) { System.out.println("Invalid data files."); fos.close(); fis.close(); return; } byte[] inbuffer = new byte[256 * 2]; byte[] outbuffer = new byte[256]; int len; while (avail > 0 && (len = fis.read(inbuffer)) > -1) { algo.decrypt(inbuffer, outbuffer, len); if (avail < outbuffer.length) { fos.write(outbuffer, 0, (int)avail); avail = 0; } else { fos.write(outbuffer, 0, len / 2); avail -= len / 2; } } fis.close(); fos.close(); } catch (Exception e) { e.printStackTrace(); } return; } /** * compare infile and outfile */ if (op.equals("-compare")) { java.io.FileInputStream fis1 = null; java.io.FileInputStream fis2 = null; try { System.out.println("Compare file " + inFilename + " with " + outFilename); System.out.println("Open input file1 " + inFilename); fis1 = new java.io.FileInputStream(inFilename); System.out.println("Open input file2 " + outFilename); fis2 = new java.io.FileInputStream(outFilename); byte[] buffer1 = new byte[4096]; byte[] buffer2 = new byte[4096]; int len1; int len2; boolean eq = true; do { len1 = fis1.read(buffer1); len2 = fis2.read(buffer2); if ((len1 == -1 && len2 != -1) || (len1 != -1 && len2 == -1) || len1 != len2) { eq = false; } else { for (i = 0; eq && i < len1; i++) { if (buffer1[i] != buffer2[i]) { eq = false; } } } } while (len1 > -1 && len2 > -1 && eq); fis1.close(); fis2.close(); if (eq) { System.out.println("Files are equal."); } else { System.out.println("Files are not equal."); } } catch (Exception e) { e.printStackTrace(); } return; } System.out.println("Unkown operation " + op + " or not yet supported."); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy