001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.DataLengthException;
006: import org.bouncycastle.crypto.params.KeyParameter;
007:
008: /**
009: * A Noekeon engine, using direct-key mode.
010: */
011:
012: public class NoekeonEngine implements BlockCipher {
013: private static final int genericSize = 16; // Block and key size, as well as the amount of rounds.
014:
015: private static final int[] nullVector = { 0x00, 0x00, 0x00, 0x00 // Used in decryption
016: },
017:
018: roundConstants = { 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab,
019: 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97,
020: 0x35, 0x6a, 0xd4 };
021:
022: private int[] state = new int[4], // a
023: subKeys = new int[4], // k
024: decryptKeys = new int[4];
025:
026: private boolean _initialised, _forEncryption;
027:
028: /**
029: * Create an instance of the Noekeon encryption algorithm
030: * and set some defaults
031: */
032: public NoekeonEngine() {
033: _initialised = false;
034: }
035:
036: public String getAlgorithmName() {
037: return "Noekeon";
038: }
039:
040: public int getBlockSize() {
041: return genericSize;
042: }
043:
044: /**
045: * initialise
046: *
047: * @param forEncryption whether or not we are for encryption.
048: * @param params the parameters required to set up the cipher.
049: * @exception IllegalArgumentException if the params argument is
050: * inappropriate.
051: */
052: public void init(boolean forEncryption, CipherParameters params) {
053: if (!(params instanceof KeyParameter)) {
054: throw new IllegalArgumentException(
055: "invalid parameter passed to Noekeon init - "
056: + params.getClass().getName());
057: }
058:
059: _forEncryption = forEncryption;
060: _initialised = true;
061:
062: KeyParameter p = (KeyParameter) params;
063:
064: setKey(p.getKey());
065: }
066:
067: public int processBlock(byte[] in, int inOff, byte[] out, int outOff) {
068: if (!_initialised) {
069: throw new IllegalStateException(getAlgorithmName()
070: + " not initialised");
071: }
072:
073: if ((inOff + genericSize) > in.length) {
074: throw new DataLengthException("input buffer too short");
075: }
076:
077: if ((outOff + genericSize) > out.length) {
078: throw new DataLengthException("output buffer too short");
079: }
080:
081: return (_forEncryption) ? encryptBlock(in, inOff, out, outOff)
082: : decryptBlock(in, inOff, out, outOff);
083: }
084:
085: public void reset() {
086: }
087:
088: /**
089: * Re-key the cipher.
090: * <p>
091: * @param key the key to be used
092: */
093: private void setKey(byte[] key) {
094: subKeys[0] = bytesToIntBig(key, 0);
095: subKeys[1] = bytesToIntBig(key, 4);
096: subKeys[2] = bytesToIntBig(key, 8);
097: subKeys[3] = bytesToIntBig(key, 12);
098: }
099:
100: private int encryptBlock(byte[] in, int inOff, byte[] out,
101: int outOff) {
102: state[0] = bytesToIntBig(in, inOff);
103: state[1] = bytesToIntBig(in, inOff + 4);
104: state[2] = bytesToIntBig(in, inOff + 8);
105: state[3] = bytesToIntBig(in, inOff + 12);
106:
107: int i;
108: for (i = 0; i < genericSize; i++) {
109: state[0] ^= roundConstants[i];
110: theta(state, subKeys);
111: pi1(state);
112: gamma(state);
113: pi2(state);
114: }
115:
116: state[0] ^= roundConstants[i];
117: theta(state, subKeys);
118:
119: intToBytesBig(state[0], out, outOff);
120: intToBytesBig(state[1], out, outOff + 4);
121: intToBytesBig(state[2], out, outOff + 8);
122: intToBytesBig(state[3], out, outOff + 12);
123:
124: return genericSize;
125: }
126:
127: private int decryptBlock(byte[] in, int inOff, byte[] out,
128: int outOff) {
129: state[0] = bytesToIntBig(in, inOff);
130: state[1] = bytesToIntBig(in, inOff + 4);
131: state[2] = bytesToIntBig(in, inOff + 8);
132: state[3] = bytesToIntBig(in, inOff + 12);
133:
134: System.arraycopy(subKeys, 0, decryptKeys, 0, subKeys.length);
135: theta(decryptKeys, nullVector);
136:
137: int i;
138: for (i = genericSize; i > 0; i--) {
139: theta(state, decryptKeys);
140: state[0] ^= roundConstants[i];
141: pi1(state);
142: gamma(state);
143: pi2(state);
144: }
145:
146: theta(state, decryptKeys);
147: state[0] ^= roundConstants[i];
148:
149: intToBytesBig(state[0], out, outOff);
150: intToBytesBig(state[1], out, outOff + 4);
151: intToBytesBig(state[2], out, outOff + 8);
152: intToBytesBig(state[3], out, outOff + 12);
153:
154: return genericSize;
155: }
156:
157: private void gamma(int[] a) {
158: a[1] ^= ~a[3] & ~a[2];
159: a[0] ^= a[2] & a[1];
160:
161: int tmp = a[3];
162: a[3] = a[0];
163: a[0] = tmp;
164: a[2] ^= a[0] ^ a[1] ^ a[3];
165:
166: a[1] ^= ~a[3] & ~a[2];
167: a[0] ^= a[2] & a[1];
168: }
169:
170: private void theta(int[] a, int[] k) {
171: int tmp;
172:
173: tmp = a[0] ^ a[2];
174: tmp ^= rotl(tmp, 8) ^ rotl(tmp, 24);
175: a[1] ^= tmp;
176: a[3] ^= tmp;
177:
178: for (int i = 0; i < 4; i++) {
179: a[i] ^= k[i];
180: }
181:
182: tmp = a[1] ^ a[3];
183: tmp ^= rotl(tmp, 8) ^ rotl(tmp, 24);
184: a[0] ^= tmp;
185: a[2] ^= tmp;
186: }
187:
188: private void pi1(int[] a) {
189: a[1] = rotl(a[1], 1);
190: a[2] = rotl(a[2], 5);
191: a[3] = rotl(a[3], 2);
192: }
193:
194: private void pi2(int[] a) {
195: a[1] = rotl(a[1], 31);
196: a[2] = rotl(a[2], 27);
197: a[3] = rotl(a[3], 30);
198: }
199:
200: // Helpers
201:
202: private int bytesToIntBig(byte[] in, int off) {
203: return ((in[off++]) << 24) | ((in[off++] & 0xff) << 16)
204: | ((in[off++] & 0xff) << 8) | (in[off] & 0xff);
205: }
206:
207: private void intToBytesBig(int x, byte[] out, int off) {
208: out[off++] = (byte) (x >>> 24);
209: out[off++] = (byte) (x >>> 16);
210: out[off++] = (byte) (x >>> 8);
211: out[off] = (byte) x;
212: }
213:
214: private int rotl(int x, int y) {
215: return (x << y) | (x >>> (32 - y));
216: }
217: }
|