diff options
Diffstat (limited to 'bcprov/src/main/java/org/bouncycastle/crypto/engines/RC564Engine.java')
-rw-r--r-- | bcprov/src/main/java/org/bouncycastle/crypto/engines/RC564Engine.java | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC564Engine.java b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC564Engine.java new file mode 100644 index 0000000..2121a4b --- /dev/null +++ b/bcprov/src/main/java/org/bouncycastle/crypto/engines/RC564Engine.java @@ -0,0 +1,288 @@ +package org.bouncycastle.crypto.engines; + +import org.bouncycastle.crypto.BlockCipher; +import org.bouncycastle.crypto.CipherParameters; +import org.bouncycastle.crypto.params.RC5Parameters; + +/** + * The specification for RC5 came from the <code>RC5 Encryption Algorithm</code> + * publication in RSA CryptoBytes, Spring of 1995. + * <em>http://www.rsasecurity.com/rsalabs/cryptobytes</em>. + * <p> + * This implementation is set to work with a 64 bit word size. + * <p> + * Implementation courtesy of Tito Pena. + */ +public class RC564Engine + implements BlockCipher +{ + private static final int wordSize = 64; + private static final int bytesPerWord = wordSize / 8; + + /* + * the number of rounds to perform + */ + private int _noRounds; + + /* + * the expanded key array of size 2*(rounds + 1) + */ + private long _S[]; + + /* + * our "magic constants" for wordSize 62 + * + * Pw = Odd((e-2) * 2^wordsize) + * Qw = Odd((o-2) * 2^wordsize) + * + * where e is the base of natural logarithms (2.718281828...) + * and o is the golden ratio (1.61803398...) + */ + private static final long P64 = 0xb7e151628aed2a6bL; + private static final long Q64 = 0x9e3779b97f4a7c15L; + + private boolean forEncryption; + + /** + * Create an instance of the RC5 encryption algorithm + * and set some defaults + */ + public RC564Engine() + { + _noRounds = 12; + _S = null; + } + + public String getAlgorithmName() + { + return "RC5-64"; + } + + public int getBlockSize() + { + return 2 * bytesPerWord; + } + + /** + * initialise a RC5-64 cipher. + * + * @param forEncryption whether or not we are for encryption. + * @param params the parameters required to set up the cipher. + * @exception IllegalArgumentException if the params argument is + * inappropriate. + */ + public void init( + boolean forEncryption, + CipherParameters params) + { + if (!(params instanceof RC5Parameters)) + { + throw new IllegalArgumentException("invalid parameter passed to RC564 init - " + params.getClass().getName()); + } + + RC5Parameters p = (RC5Parameters)params; + + this.forEncryption = forEncryption; + + _noRounds = p.getRounds(); + + setKey(p.getKey()); + } + + public int processBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + return (forEncryption) ? encryptBlock(in, inOff, out, outOff) + : decryptBlock(in, inOff, out, outOff); + } + + public void reset() + { + } + + /** + * Re-key the cipher. + * <p> + * @param key the key to be used + */ + private void setKey( + byte[] key) + { + // + // KEY EXPANSION: + // + // There are 3 phases to the key expansion. + // + // Phase 1: + // Copy the secret key K[0...b-1] into an array L[0..c-1] of + // c = ceil(b/u), where u = wordSize/8 in little-endian order. + // In other words, we fill up L using u consecutive key bytes + // of K. Any unfilled byte positions in L are zeroed. In the + // case that b = c = 0, set c = 1 and L[0] = 0. + // + long[] L = new long[(key.length + (bytesPerWord - 1)) / bytesPerWord]; + + for (int i = 0; i != key.length; i++) + { + L[i / bytesPerWord] += (long)(key[i] & 0xff) << (8 * (i % bytesPerWord)); + } + + // + // Phase 2: + // Initialize S to a particular fixed pseudo-random bit pattern + // using an arithmetic progression modulo 2^wordsize determined + // by the magic numbers, Pw & Qw. + // + _S = new long[2*(_noRounds + 1)]; + + _S[0] = P64; + for (int i=1; i < _S.length; i++) + { + _S[i] = (_S[i-1] + Q64); + } + + // + // Phase 3: + // Mix in the user's secret key in 3 passes over the arrays S & L. + // The max of the arrays sizes is used as the loop control + // + int iter; + + if (L.length > _S.length) + { + iter = 3 * L.length; + } + else + { + iter = 3 * _S.length; + } + + long A = 0, B = 0; + int i = 0, j = 0; + + for (int k = 0; k < iter; k++) + { + A = _S[i] = rotateLeft(_S[i] + A + B, 3); + B = L[j] = rotateLeft(L[j] + A + B, A+B); + i = (i+1) % _S.length; + j = (j+1) % L.length; + } + } + + /** + * Encrypt the given block starting at the given offset and place + * the result in the provided buffer starting at the given offset. + * <p> + * @param in in byte buffer containing data to encrypt + * @param inOff offset into src buffer + * @param out out buffer where encrypted data is written + * @param outOff offset into out buffer + */ + private int encryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + long A = bytesToWord(in, inOff) + _S[0]; + long B = bytesToWord(in, inOff + bytesPerWord) + _S[1]; + + for (int i = 1; i <= _noRounds; i++) + { + A = rotateLeft(A ^ B, B) + _S[2*i]; + B = rotateLeft(B ^ A, A) + _S[2*i+1]; + } + + wordToBytes(A, out, outOff); + wordToBytes(B, out, outOff + bytesPerWord); + + return 2 * bytesPerWord; + } + + private int decryptBlock( + byte[] in, + int inOff, + byte[] out, + int outOff) + { + long A = bytesToWord(in, inOff); + long B = bytesToWord(in, inOff + bytesPerWord); + + for (int i = _noRounds; i >= 1; i--) + { + B = rotateRight(B - _S[2*i+1], A) ^ A; + A = rotateRight(A - _S[2*i], B) ^ B; + } + + wordToBytes(A - _S[0], out, outOff); + wordToBytes(B - _S[1], out, outOff + bytesPerWord); + + return 2 * bytesPerWord; + } + + + ////////////////////////////////////////////////////////////// + // + // PRIVATE Helper Methods + // + ////////////////////////////////////////////////////////////// + + /** + * Perform a left "spin" of the word. The rotation of the given + * word <em>x</em> is rotated left by <em>y</em> bits. + * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em> + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * <p> + * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private long rotateLeft(long x, long y) + { + return ((x << (y & (wordSize-1))) | (x >>> (wordSize - (y & (wordSize-1))))); + } + + /** + * Perform a right "spin" of the word. The rotation of the given + * word <em>x</em> is rotated left by <em>y</em> bits. + * Only the <em>lg(wordSize)</em> low-order bits of <em>y</em> + * are used to determine the rotation amount. Here it is + * assumed that the wordsize used is a power of 2. + * <p> + * @param x word to rotate + * @param y number of bits to rotate % wordSize + */ + private long rotateRight(long x, long y) + { + return ((x >>> (y & (wordSize-1))) | (x << (wordSize - (y & (wordSize-1))))); + } + + private long bytesToWord( + byte[] src, + int srcOff) + { + long word = 0; + + for (int i = bytesPerWord - 1; i >= 0; i--) + { + word = (word << 8) + (src[i + srcOff] & 0xff); + } + + return word; + } + + private void wordToBytes( + long word, + byte[] dst, + int dstOff) + { + for (int i = 0; i < bytesPerWord; i++) + { + dst[i + dstOff] = (byte)word; + word >>>= 8; + } + } +} |