/* py.c */ /* Inventors: Eli Biham and Jennifer Seberry */ /* This cipher is submitted as a response to the */ /* Ecrypt call for stream ciphers */ /* The designers/authors of Py (pronounced Roo) */ /* keep their rights on the design and the name */ /* However, no royalty will be necessary for use */ /* of Py, nor for using the submitted code. */ #include "ecrypt-sync.h" #include #ifdef DEBUG #include #endif /* This is a permutation of all the values between 0 and 255, */ /* used by the key setup and IV setup. */ /* It is computed by the init function. It can also be */ /* computed in advance and put into the code. */ u8 internal_permutation[256]; /* * Key setup. It is the user's responsibility to select a legal * keysize and ivsize, from the set of supported value. */ void ECRYPT_keysetup( ECRYPT_ctx* ctx, const u8* key, u32 keysize, /* Key size in bits. */ u32 ivsize) /* IV size in bits. */ { int i, j; u32 s; ctx->keysize=keysize; ctx->ivsize=ivsize; int keysizeb=(keysize+7)>>3; int ivsizeb=(ivsize+7)>>3; #define Y(x) (ctx->KPY[(x)-(YMININD)][0]) s = (u32)internal_permutation[keysizeb-1]; s = (s<<8) | (u32)internal_permutation[(s ^ (ivsizeb-1))&0xFF]; s = (s<<8) | (u32)internal_permutation[(s ^ key[0])&0xFF]; s = (s<<8) | (u32)internal_permutation[(s ^ key[keysizeb-1])&0xFF]; for(j=0; jkeysize; int ivsize=ctx->ivsize; int ivsizeb=(ivsize+7)>>3; #define P(x) (((u8*)&(ctx->KPY[x][1]))[0]) #define KY(x) (ctx->KPY[(x)-(YMININD)][0]) #define EIV(x) (((u8*)&(ctx->KPY[x+64-ivsizeb][1]))[2]) /* Create an initial permutation */ u8 v= iv[0] ^ ((KY(0)>>16)&0xFF); u8 d=(iv[1%ivsizeb] ^ ((KY(1)>>16)&0xFF))|1; for(i=0; i<64; i++) { P(i)=v&0x3F; v+=d; } v&=0x3F; #ifdef DEBUG /* Check that P is really a permutation */ u8 permcheck[64]; int j; for(j=0; j<64; j++) permcheck[j] = 0; for(j=0; j<64; j++) permcheck[P(j)]++; for(j=0; j<64; j++) if(permcheck[j] != 1) fprintf(stderr, "Error in creation of the permutation in ivsetup: %02X appears %d times\n", j, permcheck[j]); #endif /* Initial s */ s = ((u32)v<<24)^((u32)d<<16)^((u32)P(62)<<8)^((u32)P(63)); s ^= KY(YMININD)+KY(YMAXIND); for(i=0; iKPY)[(i8)+8*(j)+4]) /* access P[i+j] where i8=8*i. */ /* P is byte 4 of the 8-byte record */ #define EIV(i8,j) (((u8*)ctx->KPY)[(i8)+8*(j+64-ivsizeb)+6]) /* access P[i+j] where i8=8*i. */ /* EIV is byte 6 of the 8-byte record */ #define Y(i8,j) (((u32*)&(((u8*)ctx->KPY)[(i8)+8*((j)-(YMININD))]))[0]) /* access Y[i+j+1] where i8=8*i. */ /* Y is word 0 of the 2-word record */ for(i=0; is=s; #ifdef DEBUG /* Check that P is really a permutation */ /* Assumes that i was not changed after the last loop */ for(j=0; j<64; j++) permcheck[j] = 0; for(j=0; j<64; j++) permcheck[P(i, j)]++; for(j=0; j<64; j++) if(permcheck[j] != 1) fprintf(stderr, "Error in creation of the permutation in ivsetup: %02X appears %d times\n", j, permcheck[j]); #endif } #undef P #undef Y #define NUMBLOCKSATONCE 4000 /* A near-optimal value for the static array */ /* All computations are made in multiples of */ /* NUMBLOCKSATONCE*8 bytes, if possible */ static u32 PY[(NUMBLOCKSATONCE+PYSIZE)*2]; #define P(i8,j) (((u8*)PY)[(i8)+8*(j)+4]) /* access P[i+j] where i8=8*i. */ /* P is byte 4 of the 8-byte record */ #define Y(i8,j) (((u32*)&(((u8*)PY)[(i8)+8*((j)-(YMININD))]))[0]) /* access Y[i+j+1] where i8=8*i. */ /* Y is word 0 of the 2-word record */ void ECRYPT_process_bytes( int action, /* 0 = encrypt; 1 = decrypt; */ ECRYPT_ctx* ctx, const u8* input, u8* output, u32 msglen) /* Message length in bytes. */ /* If the msglen is not a multiple of 8, this must be */ /* the last call for this stream, or either you will */ /* loose a few bytes */ { int i; u32 s=ctx->s; while(msglen>=NUMBLOCKSATONCE*8) { memcpy(PY, ctx->PY, PYSIZE*8); for(i=0; iPY, ((u8*)PY)+i, PYSIZE*8); msglen-=NUMBLOCKSATONCE*8; input+=NUMBLOCKSATONCE*8; output+=NUMBLOCKSATONCE*8; } if(msglen>0) { memcpy(PY, ctx->PY, PYSIZE*8); for(i=0; i<(msglen&(~7)); i+=8) { u32 x0=(Y(i,43)&0x3F); P(i,64)=P(i,x0); P(i,x0)=P(i,0); s+=Y(i,P(i,1+18)); s-=Y(i,P(i,1+57)); s=ROTL32(s, (P(i,1+26)&31)); Y(i,YMAXIND+1)=(s^Y(i,YMININD))+Y(i,P(i,1+48)); s=ROTL32(s,11); u32 output1=(s^Y(i,64))+Y(i,P(i,1+8)); u8 output1b[4]; U32TO8_LITTLE(output1b, output1); ((u32*)(output+i))[0]=((u32*)output1b)[0]^((u32*)(input+i))[0]; s=ROTL32(s,7); u32 output2=(s^Y(i,-1))+Y(i,P(i,1+21)); u8 output2b[4]; U32TO8_LITTLE(output2b, output2); ((u32*)(output+i+4))[0]=((u32*)output2b)[0]^((u32*)(input+i+4))[0]; } if(msglen&7) { int ii; u32 x0=(Y(i,43)&0x3F); P(i,64)=P(i,x0); P(i,x0)=P(i,0); s+=Y(i,P(i,1+18)); s-=Y(i,P(i,1+57)); s=ROTL32(s, (P(i,1+26)&31)); Y(i,YMAXIND+1)=(s^Y(i,YMININD))+Y(i,P(i,1+48)); s=ROTL32(s,11); u32 output1=(s^Y(i,64))+Y(i,P(i,1+8)); u8 outputb[8]; U32TO8_LITTLE(outputb, output1); s=ROTL32(s,7); u32 output2=(s^Y(i,-1))+Y(i,P(i,1+21)); U32TO8_LITTLE(outputb+4, output2); for(ii=0; ii<(msglen&7); ii++) (output+i)[ii]=outputb[ii]^(input+i)[ii]; } memcpy(ctx->PY, ((u8*)PY)+i, PYSIZE*8); } ctx->s=s; } void ECRYPT_keystream_bytes( ECRYPT_ctx* ctx, u8* keystream, u32 length) /* Length of keystream in bytes. */ /* If the length is not a multiple of 8, this must be the */ /* last call for this stream, or either you will loose a few bytes */ { int i; u32 s=ctx->s; while(length>=NUMBLOCKSATONCE*8) { memcpy(PY, ctx->PY, PYSIZE*8); for(i=0; iPY, ((u8*)PY)+i, PYSIZE*8); length-=NUMBLOCKSATONCE*8; keystream+=NUMBLOCKSATONCE*8; } if(length>0) { memcpy(PY, ctx->PY, PYSIZE*8); for(i=0; i<(length&(~7)); i+=8) { u32 x0=(Y(i,43)&0x3F); P(i,64)=P(i,x0); P(i,x0)=P(i,0); s+=Y(i,P(i,1+18)); s-=Y(i,P(i,1+57)); s=ROTL32(s, (P(i,1+26)&31)); Y(i,YMAXIND+1)=(s^Y(i,YMININD))+Y(i,P(i,1+48)); s=ROTL32(s,11); u32 output1=(s^Y(i,64))+Y(i,P(i,1+8)); U32TO8_LITTLE(keystream+i, output1); s=ROTL32(s,7); u32 output2=(s^Y(i,-1))+Y(i,P(i,1+21)); U32TO8_LITTLE(keystream+i+4, output2); } if(length&7) { int ii; u32 x0=(Y(i,43)&0x3F); P(i,64)=P(i,x0); P(i,x0)=P(i,0); s+=Y(i,P(i,1+18)); s-=Y(i,P(i,1+57)); s=ROTL32(s, (P(i,1+26)&31)); Y(i,YMAXIND+1)=(s^Y(i,YMININD))+Y(i,P(i,1+48)); s=ROTL32(s,11); u32 output1=(s^Y(i,64))+Y(i,P(i,1+8)); u8 outputb[8]; U32TO8_LITTLE(outputb, output1); s=ROTL32(s,7); u32 output2=(s^Y(i,-1))+Y(i,P(i,1+21)); U32TO8_LITTLE(outputb+4, output2); for(ii=0; ii<(length&7); ii++) (keystream+i)[ii]=outputb[ii]; } memcpy(ctx->PY, ((u8*)PY)+i, PYSIZE*8); } ctx->s=s; } #undef P #undef Y void ECRYPT_init(void) { int i; u8 j=0; static u8 str[] = "This is the seed for generating the fixed internal permutation for Py. " "The permutation is used in the key setup and IV setup as a source of nonlinearity. " "The shifted special keys on a keyboard are ~!@#$%^&*()_+{}:|<>?"; u8 *p=str; for(i=0; i<256; i++) internal_permutation[i] = i; for(i=0; i<256*16; i++) { j+=p[0]; u8 tmp=internal_permutation[i&0xFF]; internal_permutation[i&0xFF] = internal_permutation[j&0xFF]; internal_permutation[j&0xFF] = tmp; p++; if(p[0] == 0) p=str; } }