1 /** 2 * RC6 3 * 4 * Copyright: 5 * (C) 1999-2007 Jack Lloyd 6 * (C) 2014-2015 Etienne Cimon 7 * 8 * License: 9 * Botan is released under the Simplified BSD License (see LICENSE.md) 10 */ 11 module botan.block.rc6; 12 13 import botan.constants; 14 static if (BOTAN_HAS_RC6): 15 16 import botan.block.block_cipher; 17 import botan.utils.loadstor; 18 import botan.utils.rotate; 19 import std.algorithm; 20 import botan.utils.mem_ops; 21 22 /** 23 * RC6, Ron Rivest's AES candidate 24 */ 25 final class RC6 : BlockCipherFixedParams!(16, 1, 32), BlockCipher, SymmetricAlgorithm 26 { 27 public: 28 /* 29 * RC6 Encryption 30 */ 31 override void encryptN(const(ubyte)* input, ubyte* output, size_t blocks) 32 { 33 foreach (size_t i; 0 .. blocks) 34 { 35 uint A = loadLittleEndian!uint(input, 0); 36 uint B = loadLittleEndian!uint(input, 1); 37 uint C = loadLittleEndian!uint(input, 2); 38 uint D = loadLittleEndian!uint(input, 3); 39 40 B += m_S[0]; D += m_S[1]; 41 42 for (size_t j = 0; j != 20; j += 4) 43 { 44 uint T1, T2; 45 46 T1 = rotateLeft(B*(2*B+1), 5); 47 T2 = rotateLeft(D*(2*D+1), 5); 48 A = rotateLeft(A ^ T1, T2 % 32) + m_S[2*j+2]; 49 C = rotateLeft(C ^ T2, T1 % 32) + m_S[2*j+3]; 50 51 T1 = rotateLeft(C*(2*C+1), 5); 52 T2 = rotateLeft(A*(2*A+1), 5); 53 B = rotateLeft(B ^ T1, T2 % 32) + m_S[2*j+4]; 54 D = rotateLeft(D ^ T2, T1 % 32) + m_S[2*j+5]; 55 56 T1 = rotateLeft(D*(2*D+1), 5); 57 T2 = rotateLeft(B*(2*B+1), 5); 58 C = rotateLeft(C ^ T1, T2 % 32) + m_S[2*j+6]; 59 A = rotateLeft(A ^ T2, T1 % 32) + m_S[2*j+7]; 60 61 T1 = rotateLeft(A*(2*A+1), 5); 62 T2 = rotateLeft(C*(2*C+1), 5); 63 D = rotateLeft(D ^ T1, T2 % 32) + m_S[2*j+8]; 64 B = rotateLeft(B ^ T2, T1 % 32) + m_S[2*j+9]; 65 } 66 67 A += m_S[42]; C += m_S[43]; 68 69 storeLittleEndian(output, A, B, C, D); 70 71 input += BLOCK_SIZE; 72 output += BLOCK_SIZE; 73 } 74 } 75 /* 76 * RC6 Decryption 77 */ 78 override void decryptN(const(ubyte)* input, ubyte* output, size_t blocks) 79 { 80 foreach (size_t i; 0 .. blocks) 81 { 82 uint A = loadLittleEndian!uint(input, 0); 83 uint B = loadLittleEndian!uint(input, 1); 84 uint C = loadLittleEndian!uint(input, 2); 85 uint D = loadLittleEndian!uint(input, 3); 86 87 C -= m_S[43]; A -= m_S[42]; 88 89 for (size_t j = 0; j != 20; j += 4) 90 { 91 uint T1, T2; 92 93 T1 = rotateLeft(A*(2*A+1), 5); 94 T2 = rotateLeft(C*(2*C+1), 5); 95 B = rotateRight(B - m_S[41 - 2*j], T1 % 32) ^ T2; 96 D = rotateRight(D - m_S[40 - 2*j], T2 % 32) ^ T1; 97 98 T1 = rotateLeft(D*(2*D+1), 5); 99 T2 = rotateLeft(B*(2*B+1), 5); 100 A = rotateRight(A - m_S[39 - 2*j], T1 % 32) ^ T2; 101 C = rotateRight(C - m_S[38 - 2*j], T2 % 32) ^ T1; 102 103 T1 = rotateLeft(C*(2*C+1), 5); 104 T2 = rotateLeft(A*(2*A+1), 5); 105 D = rotateRight(D - m_S[37 - 2*j], T1 % 32) ^ T2; 106 B = rotateRight(B - m_S[36 - 2*j], T2 % 32) ^ T1; 107 108 T1 = rotateLeft(B*(2*B+1), 5); 109 T2 = rotateLeft(D*(2*D+1), 5); 110 C = rotateRight(C - m_S[35 - 2*j], T1 % 32) ^ T2; 111 A = rotateRight(A - m_S[34 - 2*j], T2 % 32) ^ T1; 112 } 113 114 D -= m_S[1]; B -= m_S[0]; 115 116 storeLittleEndian(output, A, B, C, D); 117 118 input += BLOCK_SIZE; 119 output += BLOCK_SIZE; 120 } 121 } 122 123 override void clear() 124 { 125 zap(m_S); 126 } 127 128 override @property string name() const { return "RC6"; } 129 override @property size_t parallelism() const { return 1; } 130 override BlockCipher clone() const { return new RC6; } 131 override size_t blockSize() const { return super.blockSize(); } 132 override KeyLengthSpecification keySpec() const { return super.keySpec(); } 133 protected: 134 /* 135 * RC6 Key Schedule 136 */ 137 override void keySchedule(const(ubyte)* key, size_t length) 138 { 139 m_S.resize(44); 140 141 const size_t WORD_KEYLENGTH = (((length - 1) / 4) + 1); 142 const size_t MIX_ROUNDS = 3 * std.algorithm.max(WORD_KEYLENGTH, m_S.length); 143 144 m_S[0] = 0xB7E15163; 145 foreach (size_t i; 1 .. m_S.length) 146 m_S[i] = m_S[i-1] + 0x9E3779B9; 147 148 SecureVector!uint K = SecureVector!uint(8); 149 150 for (int i = cast(int) length-1; i >= 0; --i) 151 K[i/4] = (K[i/4] << 8) + key[i]; 152 153 uint A = 0, B = 0; 154 foreach (size_t i; 0 .. MIX_ROUNDS) 155 { 156 A = rotateLeft(m_S[i % m_S.length] + A + B, 3); 157 B = rotateLeft(K[i % WORD_KEYLENGTH] + A + B, (A + B) % 32); 158 m_S[i % m_S.length] = A; 159 K[i % WORD_KEYLENGTH] = B; 160 } 161 } 162 163 SecureVector!uint m_S; 164 }