001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.CipherParameters;
004: import org.bouncycastle.crypto.DataLengthException;
005: import org.bouncycastle.crypto.StreamCipher;
006: import org.bouncycastle.crypto.params.KeyParameter;
007: import org.bouncycastle.crypto.params.ParametersWithIV;
008:
009: public class VMPCEngine implements StreamCipher {
010: /*
011: * variables to hold the state of the VMPC engine during encryption and
012: * decryption
013: */
014: protected byte n = 0;
015: protected byte[] P = null;
016: protected byte s = 0;
017:
018: protected byte[] workingIV;
019: protected byte[] workingKey;
020:
021: public String getAlgorithmName() {
022: return "VMPC";
023: }
024:
025: /**
026: * initialise a VMPC cipher.
027: *
028: * @param forEncryption
029: * whether or not we are for encryption.
030: * @param params
031: * the parameters required to set up the cipher.
032: * @exception IllegalArgumentException
033: * if the params argument is inappropriate.
034: */
035: public void init(boolean forEncryption, CipherParameters params) {
036: if (!(params instanceof ParametersWithIV)) {
037: throw new IllegalArgumentException(
038: "VMPC init parameters must include an IV");
039: }
040:
041: ParametersWithIV ivParams = (ParametersWithIV) params;
042: KeyParameter key = (KeyParameter) ivParams.getParameters();
043:
044: if (!(ivParams.getParameters() instanceof KeyParameter)) {
045: throw new IllegalArgumentException(
046: "VMPC init parameters must include a key");
047: }
048:
049: this .workingIV = ivParams.getIV();
050:
051: if (workingIV == null || workingIV.length < 1
052: || workingIV.length > 768) {
053: throw new IllegalArgumentException(
054: "VMPC requires 1 to 768 bytes of IV");
055: }
056:
057: this .workingKey = key.getKey();
058:
059: initKey(this .workingKey, this .workingIV);
060: }
061:
062: protected void initKey(byte[] keyBytes, byte[] ivBytes) {
063: s = 0;
064: P = new byte[256];
065: for (int i = 0; i < 256; i++) {
066: P[i] = (byte) i;
067: }
068:
069: for (int m = 0; m < 768; m++) {
070: s = P[(s + P[m & 0xff] + keyBytes[m % keyBytes.length]) & 0xff];
071: byte temp = P[m & 0xff];
072: P[m & 0xff] = P[s & 0xff];
073: P[s & 0xff] = temp;
074: }
075: for (int m = 0; m < 768; m++) {
076: s = P[(s + P[m & 0xff] + ivBytes[m % ivBytes.length]) & 0xff];
077: byte temp = P[m & 0xff];
078: P[m & 0xff] = P[s & 0xff];
079: P[s & 0xff] = temp;
080: }
081: n = 0;
082: }
083:
084: public void processBytes(byte[] in, int inOff, int len, byte[] out,
085: int outOff) {
086: if ((inOff + len) > in.length) {
087: throw new DataLengthException("input buffer too short");
088: }
089:
090: if ((outOff + len) > out.length) {
091: throw new DataLengthException("output buffer too short");
092: }
093:
094: for (int i = 0; i < len; i++) {
095: s = P[(s + P[n & 0xff]) & 0xff];
096: byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
097: // encryption
098: byte temp = P[n & 0xff];
099: P[n & 0xff] = P[s & 0xff];
100: P[s & 0xff] = temp;
101: n = (byte) ((n + 1) & 0xff);
102:
103: // xor
104: out[i + outOff] = (byte) (in[i + inOff] ^ z);
105: }
106: }
107:
108: public void reset() {
109: initKey(this .workingKey, this .workingIV);
110: }
111:
112: public byte returnByte(byte in) {
113: s = P[(s + P[n & 0xff]) & 0xff];
114: byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
115: // encryption
116: byte temp = P[n & 0xff];
117: P[n & 0xff] = P[s & 0xff];
118: P[s & 0xff] = temp;
119: n = (byte) ((n + 1) & 0xff);
120:
121: // xor
122: return (byte) (in ^ z);
123: }
124: }
|