001: package org.bouncycastle.crypto.engines;
002:
003: import org.bouncycastle.crypto.BlockCipher;
004: import org.bouncycastle.crypto.CipherParameters;
005: import org.bouncycastle.crypto.params.KeyParameter;
006: import org.bouncycastle.crypto.params.RC5Parameters;
007:
008: /**
009: * The specification for RC5 came from the <code>RC5 Encryption Algorithm</code>
010: * publication in RSA CryptoBytes, Spring of 1995.
011: * <em>http://www.rsasecurity.com/rsalabs/cryptobytes</em>.
012: * <p>
013: * This implementation has a word size of 32 bits.
014: * <p>
015: * Implementation courtesy of Tito Pena.
016: */
017: public class RC532Engine implements BlockCipher {
018: /*
019: * the number of rounds to perform
020: */
021: private int _noRounds;
022:
023: /*
024: * the expanded key array of size 2*(rounds + 1)
025: */
026: private int _S[];
027:
028: /*
029: * our "magic constants" for 32 32
030: *
031: * Pw = Odd((e-2) * 2^wordsize)
032: * Qw = Odd((o-2) * 2^wordsize)
033: *
034: * where e is the base of natural logarithms (2.718281828...)
035: * and o is the golden ratio (1.61803398...)
036: */
037: private static final int P32 = 0xb7e15163;
038: private static final int Q32 = 0x9e3779b9;
039:
040: private boolean forEncryption;
041:
042: /**
043: * Create an instance of the RC5 encryption algorithm
044: * and set some defaults
045: */
046: public RC532Engine() {
047: _noRounds = 12; // the default
048: _S = null;
049: }
050:
051: public String getAlgorithmName() {
052: return "RC5-32";
053: }
054:
055: public int getBlockSize() {
056: return 2 * 4;
057: }
058:
059: /**
060: * initialise a RC5-32 cipher.
061: *
062: * @param forEncryption whether or not we are for encryption.
063: * @param params the parameters required to set up the cipher.
064: * @exception IllegalArgumentException if the params argument is
065: * inappropriate.
066: */
067: public void init(boolean forEncryption, CipherParameters params) {
068: if (params instanceof RC5Parameters) {
069: RC5Parameters p = (RC5Parameters) params;
070:
071: _noRounds = p.getRounds();
072:
073: setKey(p.getKey());
074: } else if (params instanceof KeyParameter) {
075: KeyParameter p = (KeyParameter) params;
076:
077: setKey(p.getKey());
078: } else {
079: throw new IllegalArgumentException(
080: "invalid parameter passed to RC532 init - "
081: + params.getClass().getName());
082: }
083:
084: this .forEncryption = forEncryption;
085: }
086:
087: public int processBlock(byte[] in, int inOff, byte[] out, int outOff) {
088: return (forEncryption) ? encryptBlock(in, inOff, out, outOff)
089: : decryptBlock(in, inOff, out, outOff);
090: }
091:
092: public void reset() {
093: }
094:
095: /**
096: * Re-key the cipher.
097: * <p>
098: * @param key the key to be used
099: */
100: private void setKey(byte[] key) {
101: //
102: // KEY EXPANSION:
103: //
104: // There are 3 phases to the key expansion.
105: //
106: // Phase 1:
107: // Copy the secret key K[0...b-1] into an array L[0..c-1] of
108: // c = ceil(b/u), where u = 32/8 in little-endian order.
109: // In other words, we fill up L using u consecutive key bytes
110: // of K. Any unfilled byte positions in L are zeroed. In the
111: // case that b = c = 0, set c = 1 and L[0] = 0.
112: //
113: int[] L = new int[(key.length + (4 - 1)) / 4];
114:
115: for (int i = 0; i != key.length; i++) {
116: L[i / 4] += (key[i] & 0xff) << (8 * (i % 4));
117: }
118:
119: //
120: // Phase 2:
121: // Initialize S to a particular fixed pseudo-random bit pattern
122: // using an arithmetic progression modulo 2^wordsize determined
123: // by the magic numbers, Pw & Qw.
124: //
125: _S = new int[2 * (_noRounds + 1)];
126:
127: _S[0] = P32;
128: for (int i = 1; i < _S.length; i++) {
129: _S[i] = (_S[i - 1] + Q32);
130: }
131:
132: //
133: // Phase 3:
134: // Mix in the user's secret key in 3 passes over the arrays S & L.
135: // The max of the arrays sizes is used as the loop control
136: //
137: int iter;
138:
139: if (L.length > _S.length) {
140: iter = 3 * L.length;
141: } else {
142: iter = 3 * _S.length;
143: }
144:
145: int A = 0, B = 0;
146: int i = 0, j = 0;
147:
148: for (int k = 0; k < iter; k++) {
149: A = _S[i] = rotateLeft(_S[i] + A + B, 3);
150: B = L[j] = rotateLeft(L[j] + A + B, A + B);
151: i = (i + 1) % _S.length;
152: j = (j + 1) % L.length;
153: }
154: }
155:
156: /**
157: * Encrypt the given block starting at the given offset and place
158: * the result in the provided buffer starting at the given offset.
159: * <p>
160: * @param in in byte buffer containing data to encrypt
161: * @param inOff offset into src buffer
162: * @param out out buffer where encrypted data is written
163: * @param outOff offset into out buffer
164: */
165: private int encryptBlock(byte[] in, int inOff, byte[] out,
166: int outOff) {
167: int A = bytesToWord(in, inOff) + _S[0];
168: int B = bytesToWord(in, inOff + 4) + _S[1];
169:
170: for (int i = 1; i <= _noRounds; i++) {
171: A = rotateLeft(A ^ B, B) + _S[2 * i];
172: B = rotateLeft(B ^ A, A) + _S[2 * i + 1];
173: }
174:
175: wordToBytes(A, out, outOff);
176: wordToBytes(B, out, outOff + 4);
177:
178: return 2 * 4;
179: }
180:
181: private int decryptBlock(byte[] in, int inOff, byte[] out,
182: int outOff) {
183: int A = bytesToWord(in, inOff);
184: int B = bytesToWord(in, inOff + 4);
185:
186: for (int i = _noRounds; i >= 1; i--) {
187: B = rotateRight(B - _S[2 * i + 1], A) ^ A;
188: A = rotateRight(A - _S[2 * i], B) ^ B;
189: }
190:
191: wordToBytes(A - _S[0], out, outOff);
192: wordToBytes(B - _S[1], out, outOff + 4);
193:
194: return 2 * 4;
195: }
196:
197: //////////////////////////////////////////////////////////////
198: //
199: // PRIVATE Helper Methods
200: //
201: //////////////////////////////////////////////////////////////
202:
203: /**
204: * Perform a left "spin" of the word. The rotation of the given
205: * word <em>x</em> is rotated left by <em>y</em> bits.
206: * Only the <em>lg(32)</em> low-order bits of <em>y</em>
207: * are used to determine the rotation amount. Here it is
208: * assumed that the wordsize used is a power of 2.
209: * <p>
210: * @param x word to rotate
211: * @param y number of bits to rotate % 32
212: */
213: private int rotateLeft(int x, int y) {
214: return ((x << (y & (32 - 1))) | (x >>> (32 - (y & (32 - 1)))));
215: }
216:
217: /**
218: * Perform a right "spin" of the word. The rotation of the given
219: * word <em>x</em> is rotated left by <em>y</em> bits.
220: * Only the <em>lg(32)</em> low-order bits of <em>y</em>
221: * are used to determine the rotation amount. Here it is
222: * assumed that the wordsize used is a power of 2.
223: * <p>
224: * @param x word to rotate
225: * @param y number of bits to rotate % 32
226: */
227: private int rotateRight(int x, int y) {
228: return ((x >>> (y & (32 - 1))) | (x << (32 - (y & (32 - 1)))));
229: }
230:
231: private int bytesToWord(byte[] src, int srcOff) {
232: return (src[srcOff] & 0xff) | ((src[srcOff + 1] & 0xff) << 8)
233: | ((src[srcOff + 2] & 0xff) << 16)
234: | ((src[srcOff + 3] & 0xff) << 24);
235: }
236:
237: private void wordToBytes(int word, byte[] dst, int dstOff) {
238: dst[dstOff] = (byte) word;
239: dst[dstOff + 1] = (byte) (word >> 8);
240: dst[dstOff + 2] = (byte) (word >> 16);
241: dst[dstOff + 3] = (byte) (word >> 24);
242: }
243: }
|