|
|
@ -22,28 +22,28 @@ |
|
|
|
// published on github/drewcsillag/twofish
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
The MIT License (MIT) |
|
|
|
|
|
|
|
Copyright (c) 2015 Andrew T. Csillag |
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy |
|
|
|
of this software and associated documentation files (the "Software"), to deal |
|
|
|
in the Software without restriction, including without limitation the rights |
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
|
|
copies of the Software, and to permit persons to whom the Software is |
|
|
|
furnished to do so, subject to the following conditions: |
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in |
|
|
|
all copies or substantial portions of the Software. |
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
|
|
THE SOFTWARE. |
|
|
|
/**
|
|
|
|
* The MIT License (MIT) |
|
|
|
* |
|
|
|
* Copyright (c) 2015 Andrew T. Csillag |
|
|
|
* |
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
|
|
* of this software and associated documentation files (the "Software"), to deal |
|
|
|
* in the Software without restriction, including without limitation the rights |
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
|
|
* copies of the Software, and to permit persons to whom the Software is |
|
|
|
* furnished to do so, subject to the following conditions: |
|
|
|
* |
|
|
|
* The above copyright notice and this permission notice shall be included in |
|
|
|
* all copies or substantial portions of the Software. |
|
|
|
* |
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN |
|
|
|
* THE SOFTWARE. |
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
@ -123,6 +123,7 @@ const uint8_t multEF[] = { 0x00, 0xEF, 0xB7, 0x58, 0x07, 0xE8, 0xB0, 0x5F, 0x0E, |
|
|
|
0xA8, 0x47, 0x1F, 0xF0, 0xAF, 0x40, 0x18, 0xF7, 0xA6, 0x49, 0x11, 0xFE, 0xA1, 0x4E, 0x16, 0xF9, |
|
|
|
0xB4, 0x5B, 0x03, 0xEC, 0xB3, 0x5C, 0x04, 0xEB, 0xBA, 0x55, 0x0D, 0xE2, 0xBD, 0x52, 0x0A, 0xE5 }; |
|
|
|
|
|
|
|
|
|
|
|
#define RS_MOD 0x14D |
|
|
|
#define RHO 0x01010101L |
|
|
|
|
|
|
@ -140,13 +141,14 @@ const uint8_t multEF[] = { 0x00, 0xEF, 0xB7, 0x58, 0x07, 0xE8, 0xB0, 0x5F, 0x0E, |
|
|
|
#define U8S_TO_U32(r0, r1, r2, r3) ((r0 << 24) ^ (r1 << 16) ^ (r2 << 8) ^ r3) |
|
|
|
|
|
|
|
|
|
|
|
/* multiply two polynomials represented as u32's, actually called with bytes */ |
|
|
|
// multiply two polynomials represented as u32's, actually called with bytes
|
|
|
|
uint32_t polyMult(uint32_t a, uint32_t b) { |
|
|
|
|
|
|
|
uint32_t t=0; |
|
|
|
|
|
|
|
while(a) { |
|
|
|
if(a&1) t^=b; |
|
|
|
if(a & 1) |
|
|
|
t^=b; |
|
|
|
b <<= 1; |
|
|
|
a >>= 1; |
|
|
|
} |
|
|
@ -155,7 +157,7 @@ uint32_t polyMult(uint32_t a, uint32_t b) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* take the polynomial t and return the t % modulus in GF(256) */ |
|
|
|
// take the polynomial t and return the t % modulus in GF(256)
|
|
|
|
uint32_t gfMod(uint32_t t, uint32_t modulus) { |
|
|
|
|
|
|
|
int i; |
|
|
@ -164,7 +166,8 @@ uint32_t gfMod(uint32_t t, uint32_t modulus) { |
|
|
|
modulus <<= 7; |
|
|
|
for(i = 0; i < 8; i++) { |
|
|
|
tt = t ^ modulus; |
|
|
|
if(tt < t) t = tt; |
|
|
|
if(tt < t) |
|
|
|
t = tt; |
|
|
|
modulus >>= 1; |
|
|
|
} |
|
|
|
|
|
|
@ -172,11 +175,11 @@ uint32_t gfMod(uint32_t t, uint32_t modulus) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/*multiply a and b and return the modulus */ |
|
|
|
// multiply a and b and return the modulus
|
|
|
|
#define gfMult(a, b, modulus) gfMod(polyMult(a, b), modulus) |
|
|
|
|
|
|
|
|
|
|
|
/* return a u32 containing the result of multiplying the RS Code matrix by the sd matrix */ |
|
|
|
// return a u32 containing the result of multiplying the RS Code matrix by the sd matrix
|
|
|
|
uint32_t RSMatrixMultiply(uint8_t sd[8]) { |
|
|
|
|
|
|
|
int j, k; |
|
|
@ -195,7 +198,7 @@ uint32_t RSMatrixMultiply(uint8_t sd[8]) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* the Zero-keyed h function (used by the key setup routine) */ |
|
|
|
// the Zero-keyed h function (used by the key setup routine)
|
|
|
|
uint32_t h(uint32_t X, uint32_t L[4], int k) { |
|
|
|
|
|
|
|
uint8_t y0, y1, y2, y3; |
|
|
@ -224,7 +227,7 @@ uint32_t h(uint32_t X, uint32_t L[4], int k) { |
|
|
|
y3 = Q0[ Q1 [ Q1[y3] ^ b3(L[1]) ] ^ b3(L[0]) ]; |
|
|
|
} |
|
|
|
|
|
|
|
/* inline the MDS matrix multiply */ |
|
|
|
// inline the MDS matrix multiply
|
|
|
|
z0 = multEF[y0] ^ y1 ^ multEF[y2] ^ mult5B[y3]; |
|
|
|
z1 = multEF[y0] ^ mult5B[y1] ^ y2 ^ multEF[y3]; |
|
|
|
z2 = mult5B[y0] ^ multEF[y1] ^ multEF[y2] ^ y3; |
|
|
@ -234,15 +237,15 @@ uint32_t h(uint32_t X, uint32_t L[4], int k) { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* given the Sbox keys, create the fully keyed QF */ |
|
|
|
// given the Sbox keys, create the fully keyed QF
|
|
|
|
void fullKey(uint32_t L[4], int k, uint32_t QF[4][256]) { |
|
|
|
|
|
|
|
uint8_t y0, y1, y2, y3; |
|
|
|
int i; |
|
|
|
|
|
|
|
/* for all input values to the Q permutations */ |
|
|
|
// for all input values to the Q permutations
|
|
|
|
for(i = 0; i < 256; i++) { |
|
|
|
/* run the Q permutations */ |
|
|
|
// run the Q permutations
|
|
|
|
y0 = i; y1 = i; y2 = i; y3 = i; |
|
|
|
switch(k) { |
|
|
|
case 4: |
|
|
@ -262,7 +265,7 @@ void fullKey(uint32_t L[4], int k, uint32_t QF[4][256]) { |
|
|
|
y3 = Q0[ Q1 [ Q1[y3] ^ b3(L[1]) ] ^ b3(L[0]) ]; |
|
|
|
} |
|
|
|
|
|
|
|
/* now do the partial MDS matrix multiplies */ |
|
|
|
// now do the partial MDS matrix multiplies
|
|
|
|
QF[0][i] = ((multEF[y0] << 24) |
|
|
|
| (multEF[y0] << 16) |
|
|
|
| (mult5B[y0] << 8) |
|
|
@ -282,14 +285,17 @@ void fullKey(uint32_t L[4], int k, uint32_t QF[4][256]) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/* fully keyed h (aka g) function */ |
|
|
|
// fully keyed h (aka g) function
|
|
|
|
#define fkh(X) (ctx->QF[0][b0(X)]^ctx->QF[1][b1(X)]^ctx->QF[2][b2(X)]^ctx->QF[3][b3(X)]) |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/* one encryption round */ |
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
// one encryption round
|
|
|
|
#define ENC_ROUND(R0, R1, R2, R3, round) \ |
|
|
|
T0 = fkh(R0); \ |
|
|
|
T1 = fkh(ROL(R1, 8)); \ |
|
|
@ -302,7 +308,7 @@ void twofish_internal_encrypt(uint8_t PT[16], tf_context_t *ctx) { |
|
|
|
uint32_t R0, R1, R2, R3; |
|
|
|
uint32_t T0, T1; |
|
|
|
|
|
|
|
/* load/byteswap/whiten input */ |
|
|
|
// load/byteswap/whiten input
|
|
|
|
R3 = ctx->K[3] ^ le32toh(((uint32_t*)PT)[3]); |
|
|
|
R2 = ctx->K[2] ^ le32toh(((uint32_t*)PT)[2]); |
|
|
|
R1 = ctx->K[1] ^ le32toh(((uint32_t*)PT)[1]); |
|
|
@ -325,16 +331,18 @@ void twofish_internal_encrypt(uint8_t PT[16], tf_context_t *ctx) { |
|
|
|
ENC_ROUND(R0, R1, R2, R3, 14); |
|
|
|
ENC_ROUND(R2, R3, R0, R1, 15); |
|
|
|
|
|
|
|
/* load/byteswap/whiten output */ |
|
|
|
// whiten/byteswap/store output
|
|
|
|
((uint32_t*)PT)[3] = htole32(R1 ^ ctx->K[7]); |
|
|
|
((uint32_t*)PT)[2] = htole32(R0 ^ ctx->K[6]); |
|
|
|
((uint32_t*)PT)[1] = htole32(R3 ^ ctx->K[5]); |
|
|
|
((uint32_t*)PT)[0] = htole32(R2 ^ ctx->K[4]); |
|
|
|
} |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/* one decryption round */ |
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
// one decryption round
|
|
|
|
#define DEC_ROUND(R0, R1, R2, R3, round) \ |
|
|
|
T0 = fkh(R0); \ |
|
|
|
T1 = fkh(ROL(R1, 8)); \ |
|
|
@ -347,7 +355,7 @@ void twofish_internal_decrypt(uint8_t PT[16], const uint8_t CT[16], tf_context_t |
|
|
|
uint32_t T0, T1; |
|
|
|
uint32_t R0, R1, R2, R3; |
|
|
|
|
|
|
|
/* load/byteswap/whiten input */ |
|
|
|
// load/byteswap/whiten input
|
|
|
|
R3 = ctx->K[7] ^ le32toh(((uint32_t*)CT)[3]); |
|
|
|
R2 = ctx->K[6] ^ le32toh(((uint32_t*)CT)[2]); |
|
|
|
R1 = ctx->K[5] ^ le32toh(((uint32_t*)CT)[1]); |
|
|
@ -370,16 +378,18 @@ void twofish_internal_decrypt(uint8_t PT[16], const uint8_t CT[16], tf_context_t |
|
|
|
DEC_ROUND(R0, R1, R2, R3, 1); |
|
|
|
DEC_ROUND(R2, R3, R0, R1, 0); |
|
|
|
|
|
|
|
/* load/byteswap/whiten output */ |
|
|
|
// whiten/byteswap/store output
|
|
|
|
((uint32_t*)PT)[3] = htole32(R1 ^ ctx->K[3]); |
|
|
|
((uint32_t*)PT)[2] = htole32(R0 ^ ctx->K[2]); |
|
|
|
((uint32_t*)PT)[1] = htole32(R3 ^ ctx->K[1]); |
|
|
|
((uint32_t*)PT)[0] = htole32(R2 ^ ctx->K[0]); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
/* the key schedule routine */ |
|
|
|
|
|
|
|
// the key schedule routine
|
|
|
|
void keySched(const uint8_t M[], int N, uint32_t **S, uint32_t K[40], int *k) { |
|
|
|
|
|
|
|
uint32_t Mo[4], Me[4]; |
|
|
@ -402,6 +412,7 @@ void keySched(const uint8_t M[], int N, uint32_t **S, uint32_t K[40], int *k) { |
|
|
|
vector[j+4] = _b(Mo[i], j); |
|
|
|
(*S)[(*k)-i-1] = RSMatrixMultiply(vector); |
|
|
|
} |
|
|
|
|
|
|
|
for(i = 0; i < 20; i++) { |
|
|
|
A = h(2*i*RHO, Me, *k); |
|
|
|
B = ROL(h(2*i*RHO + RHO, Mo, *k), 8); |
|
|
@ -410,28 +421,33 @@ void keySched(const uint8_t M[], int N, uint32_t **S, uint32_t K[40], int *k) { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
#define fix_xor(target, source) *(uint32_t*)&(target)[0] = *(uint32_t*)&(target)[0] ^ *(uint32_t*)&(source)[0]; *(uint32_t*)&(target)[4] = *(uint32_t*)&(target)[4] ^ *(uint32_t*)&(source)[4]; \ |
|
|
|
*(uint32_t*)&(target)[8] = *(uint32_t*)&(target)[8] ^ *(uint32_t*)&(source)[8]; *(uint32_t*)&(target)[12] = *(uint32_t*)&(target)[12] ^ *(uint32_t*)&(source)[12]; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------
|
|
|
|
// ----------------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
|
|
/** public API **/ |
|
|
|
// public API
|
|
|
|
|
|
|
|
|
|
|
|
int tf_ecb_decrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx) { |
|
|
|
|
|
|
|
twofish_internal_decrypt(out, in, ctx); |
|
|
|
|
|
|
|
return TF_BLOCK_SIZE; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// not used
|
|
|
|
int tf_ecb_encrypt (unsigned char *out, const unsigned char *in, tf_context_t *ctx) { |
|
|
|
|
|
|
|
memcpy(out, in, TF_BLOCK_SIZE); |
|
|
|
twofish_internal_encrypt(out, ctx); |
|
|
|
|
|
|
|
return TF_BLOCK_SIZE; |
|
|
|
} |
|
|
|
|
|
|
@ -451,6 +467,7 @@ int tf_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
twofish_internal_encrypt(tmp, ctx); |
|
|
|
memcpy(&out[i * TF_BLOCK_SIZE], tmp, TF_BLOCK_SIZE); |
|
|
|
} |
|
|
|
|
|
|
|
return n * TF_BLOCK_SIZE; |
|
|
|
} |
|
|
|
|
|
|
@ -458,22 +475,22 @@ int tf_cbc_encrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
const unsigned char *iv, tf_context_t *ctx) { |
|
|
|
|
|
|
|
int n; // number of blocks
|
|
|
|
int ret = (int)in_len & 15; // remainder
|
|
|
|
int n; /* number of blocks */ |
|
|
|
int ret = (int)in_len & 15; /* remainder */ |
|
|
|
|
|
|
|
uint8_t ivec[TF_BLOCK_SIZE]; // the ivec/old handling might be optimized if we
|
|
|
|
uint8_t old[TF_BLOCK_SIZE]; // can be sure that in != out
|
|
|
|
uint8_t ivec[TF_BLOCK_SIZE]; /* the ivec/old handling might be optimized if we */ |
|
|
|
uint8_t old[TF_BLOCK_SIZE]; /* can be sure that in != out */ |
|
|
|
|
|
|
|
memcpy(ivec, iv, TF_BLOCK_SIZE); |
|
|
|
|
|
|
|
// 3 parallel rails of twofish decryption
|
|
|
|
for(n = in_len / TF_BLOCK_SIZE; n > 2; n -=3) { |
|
|
|
|
|
|
|
memcpy(old, in + 2 * TF_BLOCK_SIZE, TF_BLOCK_SIZE); |
|
|
|
|
|
|
|
uint32_t T0, T1; |
|
|
|
uint32_t Q0, Q1, Q2, Q3, R0, R1, R2, R3, S0, S1, S2, S3; |
|
|
|
|
|
|
|
/* load/byteswap/whiten input/iv */ |
|
|
|
// load/byteswap/whiten input/iv
|
|
|
|
Q3 = ctx->K[7] ^ le32toh(((uint32_t*)in)[3]); |
|
|
|
Q2 = ctx->K[6] ^ le32toh(((uint32_t*)in)[2]); |
|
|
|
Q1 = ctx->K[5] ^ le32toh(((uint32_t*)in)[1]); |
|
|
@ -506,8 +523,7 @@ int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
DEC_ROUND(Q0, Q1, Q2, Q3, 1); DEC_ROUND(R0, R1, R2, R3, 1); DEC_ROUND(S0, S1, S2, S3, 1); |
|
|
|
DEC_ROUND(Q2, Q3, Q0, Q1, 0); DEC_ROUND(R2, R3, R0, R1, 0); DEC_ROUND(S2, S3, S0, S1, 0); |
|
|
|
|
|
|
|
/* load/byteswap/whiten output/iv */ |
|
|
|
|
|
|
|
// whiten/byteswap/store output/iv
|
|
|
|
((uint32_t*)out)[11] = htole32(S1 ^ ctx->K[3] ^ ((uint32_t*)in)[7]); |
|
|
|
((uint32_t*)out)[10] = htole32(S0 ^ ctx->K[2] ^ ((uint32_t*)in)[6]); |
|
|
|
((uint32_t*)out)[9] = htole32(S3 ^ ctx->K[1] ^ ((uint32_t*)in)[5]); |
|
|
@ -528,13 +544,14 @@ int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
memcpy(ivec, old, TF_BLOCK_SIZE); |
|
|
|
} |
|
|
|
|
|
|
|
// handle the two or less remaining block on a single rail
|
|
|
|
for(; n != 0; n--) { |
|
|
|
uint32_t T0, T1; |
|
|
|
uint32_t Q0, Q1, Q2, Q3; |
|
|
|
|
|
|
|
memcpy(old, in, TF_BLOCK_SIZE); |
|
|
|
|
|
|
|
/* load/byteswap/whiten input */ |
|
|
|
// load/byteswap/whiten input
|
|
|
|
Q3 = ctx->K[7] ^ le32toh(((uint32_t*)in)[3]); |
|
|
|
Q2 = ctx->K[6] ^ le32toh(((uint32_t*)in)[2]); |
|
|
|
Q1 = ctx->K[5] ^ le32toh(((uint32_t*)in)[1]); |
|
|
@ -557,7 +574,7 @@ int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
DEC_ROUND(Q0, Q1, Q2, Q3, 1); |
|
|
|
DEC_ROUND(Q2, Q3, Q0, Q1, 0); |
|
|
|
|
|
|
|
/* load/byteswap/whiten output/iv */ |
|
|
|
// load/byteswap/whiten output/iv
|
|
|
|
((uint32_t*)out)[3] = htole32(Q1 ^ ctx->K[3] ^ ((uint32_t*)ivec)[3]); |
|
|
|
((uint32_t*)out)[2] = htole32(Q0 ^ ctx->K[2] ^ ((uint32_t*)ivec)[2]); |
|
|
|
((uint32_t*)out)[1] = htole32(Q3 ^ ctx->K[1] ^ ((uint32_t*)ivec)[1]); |
|
|
@ -571,11 +588,10 @@ int tf_cbc_decrypt (unsigned char *out, const unsigned char *in, size_t in_len, |
|
|
|
return n * TF_BLOCK_SIZE; |
|
|
|
} |
|
|
|
|
|
|
|
/**
|
|
|
|
* By definition twofish can only accept key up to 256 bit |
|
|
|
* we wont do any checking here and will assume user already |
|
|
|
* know about it. Twofish is undefined for key larger than 256 bit |
|
|
|
*/ |
|
|
|
|
|
|
|
// by definition twofish can only accept key up to 256 bit
|
|
|
|
// we wont do any checking here and will assume user already
|
|
|
|
// know about it. twofish is undefined for key larger than 256 bit
|
|
|
|
int tf_init (const unsigned char *key, size_t key_size, tf_context_t **ctx) { |
|
|
|
|
|
|
|
int k; |
|
|
@ -585,10 +601,11 @@ int tf_init (const unsigned char *key, size_t key_size, tf_context_t **ctx) { |
|
|
|
if(!(*ctx)) { |
|
|
|
return -1; |
|
|
|
} |
|
|
|
|
|
|
|
(*ctx)->N = key_size; |
|
|
|
keySched(key, key_size, &S, (*ctx)->K, &k); |
|
|
|
fullKey(S, k, (*ctx)->QF); |
|
|
|
free(S); // allocated in keySched(...)
|
|
|
|
free(S); /* allocated in keySched(...) */ |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|