/* FUBUKI encryption system, by Hagita-Matsumoto-Nishimura-Saito */ /* Coded by Makoto Matsumoto, 2001/12/25 */ /* Re-Coded by Makoto Matsumoto, 2005/03/29 */ /* Multiplication-based by Makoto Matsumoto, 2005/04/10 */ /* Variable Tuple by Takuji Nishimura, 2005/04/12 */ /* Tough against differential crypt attack, 2005/04/13 */ /* The algorithm is fixed, 2005/04/15 */ #include #include "ecrypt-config.h" #include "ecrypt-machine.h" #include "ecrypt-portable.h" #include "ecrypt-sync.h" void genrand_tuple_int32(ECRYPT_ctx* ctx, u32 rand_tuple[], s32 len); void init_by_array(ECRYPT_ctx* ctx, u32 init_key[], int key_length); #ifdef ECRYPT_API #include "mt-fubuki.c" #endif /* This is a stream cipher. One word means a 32 bit word. */ /* Tuple words will be gather to make one Block. */ /* Typically Tuple is 4. Log_Tuple is log2(Tuple) */ #define Log_Tuple 2 #define Tuple (U32C(1) << Log_Tuple) #define Low_Mask (Tuple-1) #define Iteration 4 /* <=32: number of primitive encrypt function iterations */ #define Multi_Size 32 /* number of constant multipliers */ #define Log_Add_Size 5 /* Log of Add_Size */ #define Add_Size 32 /* number of constant adders */ /* for debug */ void print_block(u32 block[]) { s32 i; for (i=0; imulti_table[i], 4); } for (i=0; i< Multi_Size; i+=2) { ctx->multi_table[i] = (ctx->multi_table[i] & U32C(0xfffffff8)) | U32C(0x3); ctx->multi_table[i] |= (U32C(0x80000000) >> (i % 8)); ctx->multi_table[i] &= ~(U32C(0x40000000) >> (i % 8)); ctx->multi_table[i+1] = (ctx->multi_table[i+1] & U32C(0xfffffff0)) | U32C(0x7); ctx->multi_table[i+1] |= (U32C(0x80000000) >> (i+1 % 8)); ctx->multi_table[i+1] &= ~(U32C(0x40000000) >> (i+1 % 8)); } } /* compute multiplicative inverse mod 2^32 */ unsigned int inv_mod_32(u32 m) { u32 inv; s32 i; if ((m & U32C(0x1)) == 0) { printf("error\n"); return -1;} inv = 1; for (i=30; i>=0; i--) { if (((inv * m - 1) << i) != 0) inv |= (0x1 << (32-i-1)); } return inv; } /* prepare the table of inverses */ void prepare_multi_inv(ECRYPT_ctx* ctx) { s32 i; for (i=0; i< Multi_Size; i++) { ctx->inv_table[i] = inv_mod_32(ctx->multi_table[i]); } } /* Compute addition constants */ void prepare_add_table(ECRYPT_ctx* ctx) { s32 i; genrand_tuple_int32(ctx, ctx->add_table, Add_Size); for (i=0; i< Add_Size; i++) { u32 s; s = (i * 1103515245 + 12345) & (Add_Size - 1); s ^= (s >> (Log_Add_Size / 2)); ctx->add_table[i] <<= Log_Add_Size; ctx->add_table[i] |= s; } } /**********************************************/ /*******Primitive Ecnryption Families**********/ /**********************************************/ /**********************************************/ /*******PEF (almost word wise operation)*******/ /**********************************************/ /* word wise encrypt by Exor Mult table-Plus Rotate */ /* rotate number is between 16 - 23 */ void crypt_empr(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, s; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; i> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= param[i]; block[i] *= ctx->multi_table[param[(i+1) % Tuple]>> (32 - 5)]; block[(i+ctx->jump) & Low_Mask] += ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] = ((~block[i]) << (32 - s)) | (block[i] >> s); } } void crypt_empr_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, s; for (i=Tuple-1; i>=0; i--) { s = ((param[i] >> (32 - 4)) | 0x10 ) & 0x17; block[i] = ((~block[i]) >> (32 - s)) | (block[i] << s); block[(i+ctx->jump) & Low_Mask] -= ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] *= ctx->inv_table[param[(i+1) % Tuple]>> (32 - 5)]; block[i] ^= param[i]; } } /* word wise encrypt by Exor Mult table-Exor Rotate */ /* rotate number is between 16 - 23 */ void crypt_emer(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, s; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; i> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= param[i]; block[i] *= ctx->multi_table[param[(i+2) % Tuple]>> (32 - 5)]; block[(i+ctx->jump) & Low_Mask] ^= ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] = ((~block[i]) << (32 - s)) | (block[i] >> s); } } void crypt_emer_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, s; for (i=Tuple-1; i>=0; i--) { s = ((param[i] >> (32 - 4)) | 0x10 ) & 0x17; block[i] = ((~block[i]) >> (32 - s)) | (block[i] << s); block[(i+ctx->jump) & Low_Mask] ^= ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] *= ctx->inv_table[param[(i+2) % Tuple]>> (32 - 5)]; block[i] ^= param[i]; } } /* word wise encrypt by Exor Mult table-Plus Shift */ /* Shift number is betwee 16 - 23 */ void crypt_emps(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, s; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; i> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= param[i]; block[i] *= ctx->multi_table[param[(i+2) % Tuple]>> (32 - 5)]; block[(i+ctx->jump) & Low_Mask] += ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] ^= ((~block[i]) >> s); } } void crypt_emps_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, s; for (i=Tuple-1; i>=0; i--) { s = ((param[i] >> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= ((~block[i]) >> s); block[(i+ctx->jump) & Low_Mask] -= ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] *= ctx->inv_table[param[(i+2) % Tuple]>> (32 - 5)]; block[i] ^= param[i]; } } /* word wise encrypt by Exor Mult table-Exor Shift */ /* Shift number is betwee 16 - 23 */ void crypt_emes(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, s; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; i> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= param[i]; block[i] *= ctx->multi_table[param[(i+3) % Tuple]>> (32 - 5)]; block[(i+ctx->jump) & Low_Mask] ^= ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] ^= ((~block[i]) >> s); } } void crypt_emes_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, s; for (i=Tuple-1; i>=0; i--) { s = ((param[i] >> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= ((~block[i]) >> s); block[(i+ctx->jump) & Low_Mask] ^= ctx->add_table[block[i] >> (32 - Log_Add_Size)]; block[i] *= ctx->inv_table[param[(i+3) % Tuple]>> (32 - 5)]; block[i] ^= param[i]; } } /* Inter-word operations */ /* multiply to one and add to the other */ void crypt_ma(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, j, s; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; ijump) & Low_Mask; s = ((param[j] >> (32 - 4)) | 0x10 ) & 0x17; block[i] += (block[j]*param[i]); block[i] ^= ((~block[i]) >> s); } } void crypt_ma_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, j, s; for (i=Tuple-1; i>=0; i--) { j = (i - ctx->jump) & Low_Mask; s = ((param[j] >> (32 - 4)) | 0x10 ) & 0x17; block[i] ^= ((~block[i]) >> s); block[i] -= (block[j]*param[i]); } } /* multiply two words, exor to another words, and minus */ void crypt_mem(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, j, k; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; ijump) & Low_Mask; k = param[j] >> (32 - Log_Tuple); if (k==i) k=(k-1) & Low_Mask; block[i] ^= (block[j]*block[k]); block[i] -= param[i]; block[i] ^= (block[i] >> 16); } } void crypt_mem_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, j, k; for (i=Tuple-1; i>=0; i--) { j = (i - ctx->jump) & Low_Mask; k = param[j] >> (32 - Log_Tuple); if (k==i) k=(k-1) & Low_Mask; block[i] ^= (block[i] >> 16); block[i] += param[i]; block[i] ^= (block[j]*block[k]); } } /* (one word OR param) times another word) is EXORed to another */ void crypt_ome(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, j, k; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; ijump) & Low_Mask; k = param[j] >> (32 - Log_Tuple); if (k==i) k=(k-1) & Low_Mask; block[i] ^= (block[k]|param[i])*block[j]; block[i] ^= (block[i] >> 16); } } void crypt_ome_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, j, k; for (i=Tuple-1; i>=0; i--) { j = (i - ctx->jump) & Low_Mask; k = param[j] >> (32 - Log_Tuple); if (k==i) k=(k-1) & Low_Mask; block[i] ^= (block[i] >> 16); block[i] ^= (block[k]|param[i])*block[j]; } } /* (one word EXOR param) times another word) is EXORed to another */ void crypt_eme(ECRYPT_ctx* ctx, u32 block[Tuple]) { s32 i, j, k; u32 param[Tuple]; genrand_tuple_int32(ctx, param, Tuple); for (i=0; ijump) & Low_Mask; k = param[j] >> (32 - Log_Tuple); if (k==i) k=(k-1) & Low_Mask; block[i] ^= (block[k]^param[i])*block[j]; block[i] ^= (block[i] >> 17); } } void crypt_eme_inv(ECRYPT_ctx* ctx, u32 block[Tuple], u32 param[Tuple]) { s32 i, j, k; for (i=Tuple-1; i>=0; i--) { j = (i - ctx->jump) & Low_Mask; k = param[j] >> (32 - Log_Tuple); if (k==i) k=(k-1) & Low_Mask; block[i] ^= (block[i] >> 17); block[i] ^= (block[k]^param[i])*block[j]; } } /* vertical partial rotation with bit inversion*/ void crypt_vert_rotate(ECRYPT_ctx* ctx, u32 block[Tuple]) { u32 key, rkey, s; s32 i, j, jump_odd; u32 param[Tuple]; jump_odd = (ctx->jump - 1) | 0x1; genrand_tuple_int32(ctx, param, Tuple); key = ((param[0]+param[Tuple-1])<< 2) + 1; rkey = ~key; s = block[0]; j = 0; for (i=0; ijump - 1)| 0x1; for (i=0; i= 4*Tuple ) { for (i=0; i>8) & U32C(0xFF)); text[cpos++] = (u8)((buf[i]>>16) & U32C(0xFF)); text[cpos++] = (u8)((buf[i]>>24) & U32C(0xFF)); } } void hmnencode(ECRYPT_ctx* ctx, const u8* plaintext, u8* ciphertext, u32 msglen) /* Message length in bytes. */ { s32 i, j, repeat; u32 msgbuf[Tuple]; u32 cinpos, coutpos; repeat = msglen/(4*Tuple); if (msglen % (4*Tuple)) repeat++; cinpos = coutpos = 0;; for (i=0; i> 5); func_choice[1] ^= (func_choice[2] >> 5); ctx->jump = 1; for (j=0; j< 2*Iteration;) { s32 c, t; t = j >> 4; c = (func_choice[t] >> ((j++ & 0xfUL) * 2)) & 0x3UL; switch (c) { case 0: crypt_empr(ctx, msgbuf); break; case 1: crypt_emer(ctx, msgbuf); break; case 2: crypt_emps(ctx, msgbuf); break; case 3: crypt_emes(ctx, msgbuf); break; } if ((ctx->jump <<= 1) >= Tuple) ctx->jump = 1; t = j >> 4; c = (func_choice[t] >> ((j++ & 0xfUL) * 2)) & 0x3UL; switch (c) { case 0: crypt_ma(ctx, msgbuf); break; case 1: crypt_mem(ctx, msgbuf); break; case 2: crypt_ome(ctx, msgbuf); break; case 3: crypt_eme(ctx, msgbuf); break; } if ((ctx->jump <<= 1) >= Tuple) ctx->jump = 1; crypt_vert_rotate(ctx, msgbuf); if ((ctx->jump <<= 1) >= Tuple) ctx->jump = 1; } set_array(msgbuf, ciphertext, coutpos); coutpos += 4*Tuple; } } void hmndecode(ECRYPT_ctx* ctx, const u8* ciphertext, u8* plaintext, u32 msglen) /* Message length in bytes. */ { s32 i, j, k, repeat; u32 temp_rand[3*Iteration][Tuple]; u32 msgbuf[Tuple]; s32 cinpos, coutpos; repeat = msglen/(4*Tuple); cinpos = coutpos = 0; for (i=0; i> 5); func_choice[1] ^= (func_choice[2] >> 5); for (k=0; k< 3*Iteration; k++) genrand_tuple_int32(ctx, temp_rand[k], Tuple); ctx->jump = 1 << ((3*Iteration-1) % Log_Tuple); for (j=2*Iteration -1; j>=0;) { s32 c, t; t = j >> 4; c = (func_choice[t] >> ((j-- & 0xfUL) * 2)) & 0x3UL; crypt_vert_rotate_inv(ctx, msgbuf,temp_rand[--k]); if ((ctx->jump >>= 1) == 0) ctx->jump = Tuple >> 1; switch (c) { case 0: crypt_ma_inv(ctx, msgbuf,temp_rand[--k]); break; case 1: crypt_mem_inv(ctx, msgbuf,temp_rand[--k]); break; case 2: crypt_ome_inv(ctx, msgbuf,temp_rand[--k]); break; case 3: crypt_eme_inv(ctx, msgbuf,temp_rand[--k]); break; } if ((ctx->jump >>= 1) == 0) ctx->jump = Tuple >> 1; t = j >> 4; c = (func_choice[t] >> ((j-- & 0xfUL) * 2)) & 0x3UL; switch (c) { case 0: crypt_empr_inv(ctx, msgbuf,temp_rand[--k]); break; case 1: crypt_emer_inv(ctx, msgbuf,temp_rand[--k]); break; case 2: crypt_emps_inv(ctx, msgbuf,temp_rand[--k]); break; case 3: crypt_emes_inv(ctx, msgbuf,temp_rand[--k]); break; } if ((ctx->jump >>= 1) == 0) ctx->jump = Tuple >> 1; } set_array(msgbuf, plaintext, coutpos); coutpos += 4*Tuple; } } void ECRYPT_init() { /* do nothing */ } void ECRYPT_keysetup( ECRYPT_ctx* ctx, const u8* key, u32 keysize, /* Key size in bits. */ u32 ivsize) /* IV size in bits. */ { s32 i; ctx->keysize = keysize; ctx->ivsize = ivsize; for (i=0; ikey[i] = key[i]; } void ECRYPT_ivsetup( ECRYPT_ctx* ctx, const u8* iv) { s32 i,j,k,t,s; u32 x, init_array[(ECRYPT_MAXKEYSIZE+ECRYPT_MAXIVSIZE)/32]; for (i=0; iivsize/8; i++) ctx->iv[i] = iv[i]; j = 0; t = ctx->keysize/32; for (i=0; ikey[j++]; x |= ((u32)ctx->key[j++]) << 8; x |= ((u32)ctx->key[j++]) << 16; x |= ((u32)ctx->key[j++]) << 24; init_array[i] = x; } if ( ctx->keysize % 32 != 0 ) { x = 0; k = (ctx->keysize % 32)/8; for (i=0; ikey[j++]) << (8*k); } init_array[t++] = x; } j = 0; s = ctx->ivsize/32; for (i=0; iiv[j++]; x |= ((u32)ctx->iv[j++]) << 8; x |= ((u32)ctx->iv[j++]) << 16; x |= ((u32)ctx->iv[j++]) << 24; init_array[t+i] = x; } if ( ctx->ivsize % 32 != 0 ) { x = 0; k = (ctx->ivsize % 32)/8; for (i=0; iiv[j++]) << (8*k); } init_array[t+(s++)] = x; } init_by_array(ctx, init_array, t+s); prepare_multi(ctx); prepare_multi_inv(ctx); prepare_add_table(ctx); } void ECRYPT_keystream_bytes( ECRYPT_ctx* ctx, u8* keystream, u32 length) /* length % (4*Tuple) == 0 */ /* Length of keystream in bytes. */ { s32 i, j, repeat; u32 msgbuf[Tuple]; u32 coutpos; repeat = length/(4*Tuple); if (length % (4*Tuple)) repeat++; coutpos = 0;; for (i=0; i> 5); func_choice[1] ^= (func_choice[2] >> 5); for (j=0; j< 2*Iteration;) { s32 c, t; t = j >> 4; c = (func_choice[t] >> ((j++ & 0xfUL) * 2)) & 0x3UL; switch (c) { case 0: crypt_empr(ctx, msgbuf); break; case 1: crypt_emer(ctx, msgbuf); break; case 2: crypt_emps(ctx, msgbuf); break; case 3: crypt_emes(ctx, msgbuf); break; } t = j >> 4; c = (func_choice[t] >> ((j++ & 0xfUL) * 2)) & 0x3UL; switch (c) { case 0: crypt_ma(ctx, msgbuf); break; case 1: crypt_mem(ctx, msgbuf); break; case 2: crypt_ome(ctx, msgbuf); break; case 3: crypt_eme(ctx, msgbuf); break; } crypt_vert_rotate(ctx, msgbuf); } set_array(msgbuf, keystream, coutpos); coutpos += 4*Tuple; } } void ECRYPT_encrypt_bytes( ECRYPT_ctx* ctx, const u8* plaintext, u8* ciphertext, u32 msglen) /* Message length in bytes. */ { hmnencode(ctx, plaintext, ciphertext, msglen); } void ECRYPT_decrypt_bytes( ECRYPT_ctx* ctx, const u8* ciphertext, u8* plaintext, u32 msglen) /* Message length in bytes. */ { if ( (msglen % (4*Tuple)) != 0 ) { printf("ECRYPT_decrypt_bytes: msglen should be multiple of %d.\n", 4*Tuple); return; } hmndecode(ctx, ciphertext, plaintext, msglen); } #ifndef ECRYPT_API int main(void) { int i; ECRYPT_ctx x; u8 plaintext[128], plaintext2[128], ciphertext[128]; for (i=0; i<128; i++){ plaintext[i]=0; } ECRYPT_keysetup(&x, "1234567812345678", 128, 128); ECRYPT_ivsetup(&x, "8765432187654321"); ECRYPT_encrypt_bytes(&x, plaintext, ciphertext, 128); for (i=0; i<16; i++) printf("%2x ", ciphertext[i]); printf("\n"); ECRYPT_ivsetup(&x, "8765432187654321"); ECRYPT_decrypt_bytes(&x, ciphertext, plaintext2, 128); for (i=0; i<16; i++) printf("%2x ", plaintext2[i]); printf("\n"); return 0; } #endif