/* * Twofish * (C) 1999-2007 Jack Lloyd * * Distributed under the terms of the Botan license */ #include #include #include namespace Botan { /* * Twofish Encryption */ void Twofish::encrypt_n(const byte in[], byte out[], u32bit blocks) const { for(u32bit i = 0; i != blocks; ++i) { u32bit A = load_le(in, 0) ^ round_key[0]; u32bit B = load_le(in, 1) ^ round_key[1]; u32bit C = load_le(in, 2) ^ round_key[2]; u32bit D = load_le(in, 3) ^ round_key[3]; for(u32bit j = 0; j != 16; j += 2) { u32bit X, Y; X = SBox0[get_byte(3, A)] ^ SBox1[get_byte(2, A)] ^ SBox2[get_byte(1, A)] ^ SBox3[get_byte(0, A)]; Y = SBox0[get_byte(0, B)] ^ SBox1[get_byte(3, B)] ^ SBox2[get_byte(2, B)] ^ SBox3[get_byte(1, B)]; X += Y; Y += X + round_key[2*j + 9]; X += round_key[2*j + 8]; C = rotate_right(C ^ X, 1); D = rotate_left(D, 1) ^ Y; X = SBox0[get_byte(3, C)] ^ SBox1[get_byte(2, C)] ^ SBox2[get_byte(1, C)] ^ SBox3[get_byte(0, C)]; Y = SBox0[get_byte(0, D)] ^ SBox1[get_byte(3, D)] ^ SBox2[get_byte(2, D)] ^ SBox3[get_byte(1, D)]; X += Y; Y += X + round_key[2*j + 11]; X += round_key[2*j + 10]; A = rotate_right(A ^ X, 1); B = rotate_left(B, 1) ^ Y; } C ^= round_key[4]; D ^= round_key[5]; A ^= round_key[6]; B ^= round_key[7]; store_le(out, C, D, A, B); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * Twofish Decryption */ void Twofish::decrypt_n(const byte in[], byte out[], u32bit blocks) const { for(u32bit i = 0; i != blocks; ++i) { u32bit A = load_le(in, 0) ^ round_key[4]; u32bit B = load_le(in, 1) ^ round_key[5]; u32bit C = load_le(in, 2) ^ round_key[6]; u32bit D = load_le(in, 3) ^ round_key[7]; for(u32bit j = 0; j != 16; j += 2) { u32bit X, Y; X = SBox0[get_byte(3, A)] ^ SBox1[get_byte(2, A)] ^ SBox2[get_byte(1, A)] ^ SBox3[get_byte(0, A)]; Y = SBox0[get_byte(0, B)] ^ SBox1[get_byte(3, B)] ^ SBox2[get_byte(2, B)] ^ SBox3[get_byte(1, B)]; X += Y; Y += X + round_key[39 - 2*j]; X += round_key[38 - 2*j]; C = rotate_left(C, 1) ^ X; D = rotate_right(D ^ Y, 1); X = SBox0[get_byte(3, C)] ^ SBox1[get_byte(2, C)] ^ SBox2[get_byte(1, C)] ^ SBox3[get_byte(0, C)]; Y = SBox0[get_byte(0, D)] ^ SBox1[get_byte(3, D)] ^ SBox2[get_byte(2, D)] ^ SBox3[get_byte(1, D)]; X += Y; Y += X + round_key[37 - 2*j]; X += round_key[36 - 2*j]; A = rotate_left(A, 1) ^ X; B = rotate_right(B ^ Y, 1); } C ^= round_key[0]; D ^= round_key[1]; A ^= round_key[2]; B ^= round_key[3]; store_le(out, C, D, A, B); in += BLOCK_SIZE; out += BLOCK_SIZE; } } /* * Twofish Key Schedule */ void Twofish::key_schedule(const byte key[], u32bit length) { SecureBuffer S; for(u32bit j = 0; j != length; ++j) rs_mul(S + 4*(j/8), key[j], j); if(length == 16) { for(u32bit j = 0; j != 256; ++j) { SBox0[j] = MDS0[Q0[Q0[j]^S[ 0]]^S[ 4]]; SBox1[j] = MDS1[Q0[Q1[j]^S[ 1]]^S[ 5]]; SBox2[j] = MDS2[Q1[Q0[j]^S[ 2]]^S[ 6]]; SBox3[j] = MDS3[Q1[Q1[j]^S[ 3]]^S[ 7]]; } for(u32bit j = 0; j != 40; j += 2) { u32bit X = MDS0[Q0[Q0[j ]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[j ]^key[ 9]]^key[ 1]] ^ MDS2[Q1[Q0[j ]^key[10]]^key[ 2]] ^ MDS3[Q1[Q1[j ]^key[11]]^key[ 3]]; u32bit Y = MDS0[Q0[Q0[j+1]^key[12]]^key[ 4]] ^ MDS1[Q0[Q1[j+1]^key[13]]^key[ 5]] ^ MDS2[Q1[Q0[j+1]^key[14]]^key[ 6]] ^ MDS3[Q1[Q1[j+1]^key[15]]^key[ 7]]; Y = rotate_left(Y, 8); X += Y; Y += X; round_key[j] = X; round_key[j+1] = rotate_left(Y, 9); } } else if(length == 24) { for(u32bit j = 0; j != 256; ++j) { SBox0[j] = MDS0[Q0[Q0[Q1[j]^S[ 0]]^S[ 4]]^S[ 8]]; SBox1[j] = MDS1[Q0[Q1[Q1[j]^S[ 1]]^S[ 5]]^S[ 9]]; SBox2[j] = MDS2[Q1[Q0[Q0[j]^S[ 2]]^S[ 6]]^S[10]]; SBox3[j] = MDS3[Q1[Q1[Q0[j]^S[ 3]]^S[ 7]]^S[11]]; } for(u32bit j = 0; j != 40; j += 2) { u32bit X = MDS0[Q0[Q0[Q1[j ]^key[16]]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[Q1[j ]^key[17]]^key[ 9]]^key[ 1]] ^ MDS2[Q1[Q0[Q0[j ]^key[18]]^key[10]]^key[ 2]] ^ MDS3[Q1[Q1[Q0[j ]^key[19]]^key[11]]^key[ 3]]; u32bit Y = MDS0[Q0[Q0[Q1[j+1]^key[20]]^key[12]]^key[ 4]] ^ MDS1[Q0[Q1[Q1[j+1]^key[21]]^key[13]]^key[ 5]] ^ MDS2[Q1[Q0[Q0[j+1]^key[22]]^key[14]]^key[ 6]] ^ MDS3[Q1[Q1[Q0[j+1]^key[23]]^key[15]]^key[ 7]]; Y = rotate_left(Y, 8); X += Y; Y += X; round_key[j] = X; round_key[j+1] = rotate_left(Y, 9); } } else if(length == 32) { for(u32bit j = 0; j != 256; ++j) { SBox0[j] = MDS0[Q0[Q0[Q1[Q1[j]^S[ 0]]^S[ 4]]^S[ 8]]^S[12]]; SBox1[j] = MDS1[Q0[Q1[Q1[Q0[j]^S[ 1]]^S[ 5]]^S[ 9]]^S[13]]; SBox2[j] = MDS2[Q1[Q0[Q0[Q0[j]^S[ 2]]^S[ 6]]^S[10]]^S[14]]; SBox3[j] = MDS3[Q1[Q1[Q0[Q1[j]^S[ 3]]^S[ 7]]^S[11]]^S[15]]; } for(u32bit j = 0; j != 40; j += 2) { u32bit X = MDS0[Q0[Q0[Q1[Q1[j ]^key[24]]^key[16]]^key[ 8]]^key[ 0]] ^ MDS1[Q0[Q1[Q1[Q0[j ]^key[25]]^key[17]]^key[ 9]]^key[ 1]] ^ MDS2[Q1[Q0[Q0[Q0[j ]^key[26]]^key[18]]^key[10]]^key[ 2]] ^ MDS3[Q1[Q1[Q0[Q1[j ]^key[27]]^key[19]]^key[11]]^key[ 3]]; u32bit Y = MDS0[Q0[Q0[Q1[Q1[j+1]^key[28]]^key[20]]^key[12]]^key[ 4]] ^ MDS1[Q0[Q1[Q1[Q0[j+1]^key[29]]^key[21]]^key[13]]^key[ 5]] ^ MDS2[Q1[Q0[Q0[Q0[j+1]^key[30]]^key[22]]^key[14]]^key[ 6]] ^ MDS3[Q1[Q1[Q0[Q1[j+1]^key[31]]^key[23]]^key[15]]^key[ 7]]; Y = rotate_left(Y, 8); X += Y; Y += X; round_key[j] = X; round_key[j+1] = rotate_left(Y, 9); } } } /* * Do one column of the RS matrix multiplcation */ void Twofish::rs_mul(byte S[4], byte key, u32bit offset) { if(key) { byte X = POLY_TO_EXP[key - 1]; byte RS1 = RS[(4*offset ) % 32]; byte RS2 = RS[(4*offset+1) % 32]; byte RS3 = RS[(4*offset+2) % 32]; byte RS4 = RS[(4*offset+3) % 32]; S[0] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS1 - 1]) % 255]; S[1] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS2 - 1]) % 255]; S[2] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS3 - 1]) % 255]; S[3] ^= EXP_TO_POLY[(X + POLY_TO_EXP[RS4 - 1]) % 255]; } } /* * Clear memory of sensitive data */ void Twofish::clear() { SBox0.clear(); SBox1.clear(); SBox2.clear(); SBox3.clear(); round_key.clear(); } }