package org.bouncycastle.crypto.engines; /** * A class that provides CAST6 key encryption operations, * such as encoding data and generating keys. * * All the algorithms herein are from the Internet RFC * * RFC2612 - CAST6 (128bit block, 128-256bit key) * * and implement a simplified cryptography interface. */ public final class CAST6Engine extends CAST5Engine { //==================================== // Useful constants //==================================== protected static final int ROUNDS = 12; protected static final int BLOCK_SIZE = 16; // bytes = 128 bits /* * Put the round and mask keys into an array. * Kr0[i] => _Kr[i*4 + 0] */ protected int _Kr[] = new int[ROUNDS*4]; // the rotating round key(s) protected int _Km[] = new int[ROUNDS*4]; // the masking round key(s) /* * Key setup */ protected int _Tr[] = new int[24 * 8]; protected int _Tm[] = new int[24 * 8]; private int[] _workingKey = new int[8]; public CAST6Engine() { } public String getAlgorithmName() { return "CAST6"; } public void reset() { } public int getBlockSize() { return BLOCK_SIZE; } //================================== // Private Implementation //================================== /* * Creates the subkeys using the same nomenclature * as described in RFC2612. * * See section 2.4 */ protected void setKey(byte[] key) { int Cm = 0x5a827999; int Mm = 0x6ed9eba1; int Cr = 19; int Mr = 17; /* * Determine the key size here, if required * * if keysize < 256 bytes, pad with 0 * * Typical key sizes => 128, 160, 192, 224, 256 */ for (int i=0; i< 24; i++) { for (int j=0; j< 8; j++) { _Tm[i*8 + j] = Cm; Cm = (Cm + Mm); // mod 2^32; _Tr[i*8 + j] = Cr; Cr = (Cr + Mr) & 0x1f; // mod 32 } } byte[] tmpKey = new byte[64]; int length = key.length; System.arraycopy(key, 0, tmpKey, 0, length); // now create ABCDEFGH for (int i=0; i< 8; i++) { _workingKey[i] = BytesTo32bits(tmpKey, i*4); } // Generate the key schedule for (int i=0; i< 12; i++) { // KAPPA <- W2i(KAPPA) int i2 = i*2 *8; _workingKey[6] ^= F1(_workingKey[7], _Tm[i2 ], _Tr[i2 ]); _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); // KAPPA <- W2i+1(KAPPA) i2 = (i*2 + 1)*8; _workingKey[6] ^= F1(_workingKey[7], _Tm[i2 ], _Tr[i2 ]); _workingKey[5] ^= F2(_workingKey[6], _Tm[i2+1], _Tr[i2+1]); _workingKey[4] ^= F3(_workingKey[5], _Tm[i2+2], _Tr[i2+2]); _workingKey[3] ^= F1(_workingKey[4], _Tm[i2+3], _Tr[i2+3]); _workingKey[2] ^= F2(_workingKey[3], _Tm[i2+4], _Tr[i2+4]); _workingKey[1] ^= F3(_workingKey[2], _Tm[i2+5], _Tr[i2+5]); _workingKey[0] ^= F1(_workingKey[1], _Tm[i2+6], _Tr[i2+6]); _workingKey[7] ^= F2(_workingKey[0], _Tm[i2+7], _Tr[i2+7]); // Kr_(i) <- KAPPA _Kr[i*4 ] = _workingKey[0] & 0x1f; _Kr[i*4 + 1] = _workingKey[2] & 0x1f; _Kr[i*4 + 2] = _workingKey[4] & 0x1f; _Kr[i*4 + 3] = _workingKey[6] & 0x1f; // Km_(i) <- KAPPA _Km[i*4 ] = _workingKey[7]; _Km[i*4 + 1] = _workingKey[5]; _Km[i*4 + 2] = _workingKey[3]; _Km[i*4 + 3] = _workingKey[1]; } } /** * Encrypt the given input starting at the given offset and place * the result in the provided buffer starting at the given offset. * * @param src The plaintext buffer * @param srcIndex An offset into src * @param dst The ciphertext buffer * @param dstIndex An offset into dst */ protected int encryptBlock( byte[] src, int srcIndex, byte[] dst, int dstIndex) { int result[] = new int[4]; // process the input block // batch the units up into 4x32 bit chunks and go for it int A = BytesTo32bits(src, srcIndex); int B = BytesTo32bits(src, srcIndex + 4); int C = BytesTo32bits(src, srcIndex + 8); int D = BytesTo32bits(src, srcIndex + 12); CAST_Encipher(A, B, C, D, result); // now stuff them into the destination block Bits32ToBytes(result[0], dst, dstIndex); Bits32ToBytes(result[1], dst, dstIndex + 4); Bits32ToBytes(result[2], dst, dstIndex + 8); Bits32ToBytes(result[3], dst, dstIndex + 12); return BLOCK_SIZE; } /** * Decrypt the given input starting at the given offset and place * the result in the provided buffer starting at the given offset. * * @param src The plaintext buffer * @param srcIndex An offset into src * @param dst The ciphertext buffer * @param dstIndex An offset into dst */ protected int decryptBlock( byte[] src, int srcIndex, byte[] dst, int dstIndex) { int result[] = new int[4]; // process the input block // batch the units up into 4x32 bit chunks and go for it int A = BytesTo32bits(src, srcIndex); int B = BytesTo32bits(src, srcIndex + 4); int C = BytesTo32bits(src, srcIndex + 8); int D = BytesTo32bits(src, srcIndex + 12); CAST_Decipher(A, B, C, D, result); // now stuff them into the destination block Bits32ToBytes(result[0], dst, dstIndex); Bits32ToBytes(result[1], dst, dstIndex + 4); Bits32ToBytes(result[2], dst, dstIndex + 8); Bits32ToBytes(result[3], dst, dstIndex + 12); return BLOCK_SIZE; } /** * Does the 12 quad rounds rounds to encrypt the block. * * @param A the 00-31 bits of the plaintext block * @param B the 32-63 bits of the plaintext block * @param C the 64-95 bits of the plaintext block * @param D the 96-127 bits of the plaintext block * @param result the resulting ciphertext */ protected final void CAST_Encipher(int A, int B, int C, int D,int result[]) { int x; for (int i=0; i< 6; i++) { x = i*4; // BETA <- Qi(BETA) C ^= F1(D, _Km[x], _Kr[x]); B ^= F2(C, _Km[x + 1], _Kr[x + 1]); A ^= F3(B, _Km[x + 2], _Kr[x + 2]); D ^= F1(A, _Km[x + 3], _Kr[x + 3]); } for (int i=6; i<12; i++) { x = i*4; // BETA <- QBARi(BETA) D ^= F1(A, _Km[x + 3], _Kr[x + 3]); A ^= F3(B, _Km[x + 2], _Kr[x + 2]); B ^= F2(C, _Km[x + 1], _Kr[x + 1]); C ^= F1(D, _Km[x], _Kr[x]); } result[0] = A; result[1] = B; result[2] = C; result[3] = D; } /** * Does the 12 quad rounds rounds to decrypt the block. * * @param A the 00-31 bits of the ciphertext block * @param B the 32-63 bits of the ciphertext block * @param C the 64-95 bits of the ciphertext block * @param D the 96-127 bits of the ciphertext block * @param result the resulting plaintext */ protected final void CAST_Decipher(int A, int B, int C, int D,int result[]) { int x; for (int i=0; i< 6; i++) { x = (11-i)*4; // BETA <- Qi(BETA) C ^= F1(D, _Km[x], _Kr[x]); B ^= F2(C, _Km[x + 1], _Kr[x + 1]); A ^= F3(B, _Km[x + 2], _Kr[x + 2]); D ^= F1(A, _Km[x + 3], _Kr[x + 3]); } for (int i=6; i<12; i++) { x = (11-i)*4; // BETA <- QBARi(BETA) D ^= F1(A, _Km[x + 3], _Kr[x + 3]); A ^= F3(B, _Km[x + 2], _Kr[x + 2]); B ^= F2(C, _Km[x + 1], _Kr[x + 1]); C ^= F1(D, _Km[x], _Kr[x]); } result[0] = A; result[1] = B; result[2] = C; result[3] = D; } }