Welcome Guest [Log In] [Register]
Welcome to Crypto. We hope you enjoy your visit.


You're currently viewing our forum as a guest. This means you are limited to certain areas of the board and there are some features you can't use. If you join our community, you'll be able to access member-only sections, and use many member-only features such as customizing your profile, sending personal messages, and voting in polls. Registration is simple, fast, and completely free.


Join our community!


If you're already a member please log in to your account to access all of our features:

Username:   Password:
Add Reply
LOTUS, a block cipher with authentication based on the use of permutation polynomials mod 2**n
Topic Started: Mar 7 2014, 04:02 PM (664 Views)
mok-kong shen
NSA worthy
[ *  *  *  *  *  * ]
Code:
 
#[space]LOTUS,[space]a[space]block[space]cipher[space]with[space]authentication[space](integrity[space]check)[space]based[space]on[space]the[space]use
#[space]of[space]permutation[space]polynomials[space]mod[space]2**n



#[space]Prologue.[space][space][space]


#[space]LOTUS[space]is[space]a[space]block[space]encryption[space]scheme[space]employing[space]as[space]its[space]major[space]constituent[space]a
#[space]substitution[space]based[space]on[space]permutation[space]polynomials[space]mod[space]2**n.[space](By[space]definition[space]such
#[space]polynomials[space]preform[space]bijective[space]mappings[space]for[space][0,[space]2**n-1].)[space]The[space]present[space]author
#[space]has[space]earlier[space]posted[space]the[space]source[space]codes[space]of[space]two[space]software,[space]JADE[space]and[space]JADE-S,[space]that
#[space]also[space]exploit[space]the[space]substitution[space]properties[space]of[space]such[space]permutation[space]polynomials.
#[space]However,[space]in[space]these[space]software[space]an[space]essential[space]part[space]of[space]the[space]codes[space]is[space]destined[space]to[space]the
#[space]construction[space]of[space]a[space]compound[space]PRNG[space]consisting[space]of[space]a[space]number[space]of[space]constituent[space]PRNGs
#[space]built[space]also[space]with[space]permutation[space]polynomials,[space]which[space]renders[space]the[space]whole[space]software
#[space]design[space]rather[space]complicated.[space]LOTUS[space]however[space]is[space]designed[space]with[space]the[space]realization[space]that
#[space]it[space]is[space]in[space]fact[space]convenient[space]and[space]profitable[space]to[space]use[space]instead[space]Python's[space]built-in[space]PRNG,
#[space]which[space]has[space]very[space]good[space]statistical[space]properties[space]and[space]whose[space]use[space]for[space]the[space]current
#[space]crypto[space]processing[space]purposes[space]is[space]deemed[space]justifiable[space]even[space]though[space]the[space]PRNG[space]is[space]a
#[space]publically[space]accessible[space]one,[space]since[space]its[space]outputs[space]are[space]only[space]involved[space]in[space]the[space]internal
#[space]computational[space]operations[space]underlying[space]the[space]encryption[space]scheme[space](i.e.[space]unlike
#[space]situations[space]in[space]stream[space]encryption[space]where[space]the[space]plaintext[space]is[space]xor-ed[space]with[space]PRNs[space]to
#[space]directly[space]yield[space]the[space]ciphertext)[space]so[space]that[space]the[space]analyst[space]is[space]barely[space]feasible[space]to[space]gain
#[space]and[space]hence[space]exploit[space]any[space]knowledge[space]of[space]the[space]direct[space]outputs[space]from[space]Python's[space]PRNG
#[space](which[space]is[space]seeded[space]by[space]user's[space]secret[space]key).[space]See[space]lotusencrypt()[space]further[space]below,
#[space]where[space]most[space]PRNs[space]are[space]used[space]not[space]only[space]at[space]locations[space]far[space]from[space]the[space]location[space]of[space]the
#[space]final[space]output[space]of[space]the[space]ciphertext[space]from[space]the[space]function[space]but[space]are[space]also[space]employed[space]in
#[space]operations[space]much[space]more[space]complex[space]than[space]straightforward[space]bit[space]xor-ing,[space]e.g.[space]serving[space]as[space]the
#[space]coefficients[space]of[space]the[space]permutation[space]polynomials[space]for[space]computing[space]the[space]entities[space]being
#[space]transformed[space]by[space]them.[space](Note[space]that[space]each[space]such[space]entity[space]is[space]transformed[space]by[space]a[space]different
#[space]set[space]of[space]PR[space]coefficients[space]of[space]a[space]polynomial[space]--[space]involving[space]not[space]merely[space]1[space]PRN[space]as[space]in[space]the
#[space]case[space]of[space]stream[space]encryption[space]with[space]simple[space]bit[space]xor-ing[space]but[space]3[space]PRNs[space]for[space]the[space]3
#[space]coefficients[space]in[space]the[space]illustrative[space]example[space]further[space]below[space]--[space]forming[space]thus[space]a
#[space]separate[space]specific[space]permutation[space]polynomial[space]to[space]process[space]it.)

#[space]For[space]processing[space]each[space]block[space]of[space]plaintext,[space]PRNs[space]are[space]generated[space]to[space]build[space]a[space]specific
#[space]permutation[space]polynomial[space]to[space]serve[space]the[space]purpose[space]of[space]substitution.[space]Block[space]chaining
#[space]is[space]used[space]with[space]a[space]chaining[space]value[space](designated[space]sigma)[space]that[space]is[space]in[space]a[space]sense[space]a
#[space]summation[space]of[space]plaintext[space]and[space]ciphertext[space]of[space]all[space]preceding[space]blocks[space](noting[space]though
#[space]that[space]it[space]is[space]not[space]the[space]externally[space]accessible[space]final[space]ciphertext[space]but[space]instead[space]an
#[space]internal[space]value[space]that[space]is[space]involved[space]in[space]the[space]computation[space]of[space]sigma).[space][space]There[space]is[space]an
#[space]xor-ing[space]with[space]a[space]PRN[space]and[space]two[space]transpositions[space]of[space]the[space]bytes[space]of[space]the[space]block.
#[space]Authentication[space]is[space]done[space]through[space]appending[space]a[space]number[space]of[space]blocks[space]of[space]PRNs[space]to[space]the
#[space]user-given[space]plaintext.[space]For[space]details,[space]including[space]rotation[space]of[space]bits[space](to[space]achieve
#[space]better[space]avalanche)[space]and[space]skipping[space]of[space]outputs[space]from[space]the[space]PRNG[space]employed[space](to[space]achieve
#[space]dynamics/variability[space]in[space]the[space]processing),[space]see[space]the[space]very[space]richly[space]annotated
#[space]function[space]lotusencrypt()[space]further[space]below.

#[space]This[space]software[space]is[space]very[space]fast[space]in[space]practice[space]for[space]encryption[space]of[space]moderate-sized
#[space]materials[space]that[space]are[space]common[space]for[space]the[space]communications[space]of[space]our[space]targeted[space]users,[space]the
#[space]common[space]people.[space]For[space]a[space]message[space]of[space]1000[space]characters[space]a[space]CPU[space]time[space]of[space]0.09[space]sec[space]was
#[space]measured[space]on[space]a[space]common[space]PC[space]with[space]the[space]system[space]parameters[space]identical[space]to[space]those[space]used
#[space]in[space]the[space]illustrative[space]example[space]further[space]below.

#[space]Users[space]who[space]desire[space]to[space]employ[space]several[space]alternative[space]algorithms[space](including[space]for
#[space]multiple[space]encryptions)[space]may[space]also[space]consider[space]the[space]following[space]software[space]of[space]the[space]author:
#[space]NEOCLASSIC,[space]http://s13.zetaboards.com/Crypto/topic/7115671/1/
#[space]PREFIXCODING,[space]http://s13.zetaboards.com/Crypto/topic/7164646/1/


#[space]Version[space]1.1,[space]released[space]on[space]14.03.2014.

#[space]Update[space]notes:

#[space]Version[space]1.0:[space]Released[space]on[space]07.03.2014.

#[space]Version[space]1.0.1:[space]11.03.2014:[space]In[space]lotusinit()[space]the[space]in[space]Version[space]1.0[space]implemented,
#[space]arbitrarily[space]defined,[space]choicebit[space]didn't[space]correspond[space]to[space]its[space]verbal[space]description.
#[space]This[space]formal[space]inconsistency,[space]though[space]without[space]security[space]significance,[space]is[space]corrected.

#[space]Version[space]1.1.:[space]14.03.2014:[space]The[space]algorithm[space]in[space]ncombine()[space]is[space]replaced[space]by[space]a[space]better
#[space]one[space]in[space]respect[space]of[space]avalanche.

#[space]Code[space]lines[space]of[space]documents[space]with[space]the[space]same[space]version[space]number[space]are[space]always[space]identical.
#[space]There[space]may[space]be[space]interim[space]modifications[space]of[space]comment[space]lines.[space]The[space]most[space]recent[space]document
#[space]of[space]LOTUS[space]can[space]be[space]obtained[space]from:
#[space]http://s13.zetaboards.com/Crypto/topic/7166985/1/


#[space]This[space]software[space]may[space]be[space]freely[space]used:

#[space]1.[space]for[space]all[space]personal[space]purposes[space]unconditionally[space]and

#[space]2.[space]for[space]all[space]other[space]purposes[space]under[space]the[space]condition[space]that[space]its[space]name,[space]version[space]number[space]
#[space][space][space][space]and[space]authorship[space]are[space]explicitly[space]mentioned[space]and[space]that[space]the[space]author[space]is[space]informed[space]of
#[space][space][space][space]all[space]eventual[space]code[space]modifications[space]done.


#[space]The[space]author[space]is[space]indebted[space]to[space]TPS[space]for[space]review[space]and[space]suggestions[space]throughout[space]LOTUS's
#[space]development[space]phase.[space]Any[space]remaining[space]deficiencies[space]of[space]the[space]software[space]are[space]however[space]the
#[space]sole[space]responsibilty[space]of[space]the[space]author.

#[space]Constructive[space]critiques[space]and[space]comments[space]are[space]sincerely[space]solicited.[space]

#[space]Email[space]address[space]of[space]the[space]author:[space]mok-kong.shen@t-online.de



################################################################################



import[space]random


#[space]The[space]following[space]3[space]function[space]fullperiodcriteria(),[space]evalpermpoly(),[space]invpermpoly()
#[space]are[space]general[space]functions[space]required[space]for[space]computating[space]with[space]permutation[space]polynomials
#[space]mod[space]2**n.[space]They[space]were[space]posted[space]earlier[space]by[space]the[space]author[space]in[space]e.g.[space]JADE-S
#[space]http://s13.zetaboards.com/Crypto/topic/7072208/1/.[space](Note[space]that[space]some[space]of[space]the
#[space]global[space]variables[space]declared[space]in[space]them[space]are[space]no[space]longer[space]used[space]in[space]LOTUS.)


#[space]Modify[space]user-supplied[space]coefficients[space]of[space]the[space]polynomial[space]poly[space]so[space]as[space]to[space]satisfy[space]the
#[space]full-period[space]criteria[space]of[space]a[space]permutation[space]polynomial[space]mod[space]2**n.[space]The[space]degree[space]of[space]poly
#[space]is[space]required[space]to[space]be[space]at[space]least[space]2.[space]m[space]denotes[space]the[space]number[space]of[space]coefficients[space]of[space]the
#[space]polynomial,[space]i.e.[space]degree[space]of[space]polynomial[space]plus[space]1.[space]For[space]the[space]criteria[space]see[space]ref.[1],
#[space]p.283.
#[space][1][space]V.[space]Anashin,[space]A.[space]Khrennikov,[space]Applied[space]Algebraic[space]Dynamics,[space]Berlin,[space]2009.
#[space][space][space][space][space]http://www.degruyter.com/view/supplement/9783110203011_Errata.pdf
#[space]We[space]use[space]for[space]simplification[space]of[space]coding[space]a[space]restricted[space]form[space]of[space]the[space]criteria,[space]namely:
#[space][space][space][space]c_0[space]=[space]c_1[space]=[space]1[space][space]mod[space]4
#[space][space][space][space]c_i[space]=[space]0[space][space]mod[space]4[space][space][space][space]for[space]all[space]other[space]i

def[space]fullperiodcriteria(poly,m):
[space][space]global[space]logn,n,np1,nm1,nh,chnum
[space][space]global[space]tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot
[space][space]if[space]m<3:
[space][space][space][space]print("Error[space]in[space]fullperiodcriteria")
[space][space][space][space]exit(1)
[space][space]gg=(tpwnm1<<2)&tpwnm1
[space][space]permpoly=poly[:]
[space][space]for[space]i[space]in[space]range(2):
[space][space][space][space]permpoly[i]=(permpoly[i]&gg)|1
[space][space]for[space]i[space]in[space]range(2,m):
[space][space][space][space]permpoly[i]&=gg
[space][space]return(permpoly)


#[space]Evaluate[space]permpoly[space]with[space]argument[space]x[space]with[space]Horner's[space]method.

def[space]evalpermpoly(permpoly,m,x):
[space][space]global[space]logn,n,np1,nm1,nh,chnum
[space][space]global[space]tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot
[space][space]y=permpoly[m-1]
[space][space]for[space]i[space]in[space]range(m-2,-1,-1):
[space][space][space][space]y=(y*x+permpoly[i])&tpwnm1
[space][space]return(y)


#[space]Inverse[space]of[space]evalpermpoly().[space]First[space]derivative[space]of[space]permpoly(x)[space]=[space]1[space]mod[space]2.[space]Hensel's
#[space]lifting[space]lemma[space]leads[space]to[space]the[space]iteration:[space]x_(i+1)=x_i-g(x_i)[space]mod[space]2**(i+1),[space]with
#[space]g(x)=permpoly(x)-y.[space]See[space]ref.[1],[space]p.306.[space]

def[space]invpermpoly(permpoly,m,y):
[space][space]global[space]logn,n,np1,nm1,nh,chnum
[space][space]global[space]tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot
[space][space]if[space](((permpoly[0]-y)&tpwnm1)&1)==0:
[space][space][space][space]x=0
[space][space]else:
[space][space][space][space]x=1
[space][space]for[space]i[space]in[space]range(2,np1,1):
[space][space][space][space]x=(x-(evalpermpoly(permpoly,m,x)-y))&tpwnm1
[space][space]return(x)



#[space]The[space]following[space]3[space]functions[space]initbitcount()[space]bm()[space]and[space]bitcount()[space]are[space]for[space]fast
#[space]counting[space]of[space]1-bits[space]of[space]variables[space]of[space]n[space]bits[space](n[space]=[space]2**logn).[space]They[space]were[space]earlier
#[space]posted[space]by[space]the[space]author[space]in[space]http://s13.zetaboards.com/Crypto/topic/7129099/1.

def[space]initbitcount():
[space][space]global[space]logn,byten,tpwi,mk
[space][space]assert(logn>=4)
[space][space]byten=2**logn//8
[space][space]tpwi=[2**i[space]for[space]i[space]in[space]range(logn)]
[space][space]b55=0x55
[space][space]b33=0x33
[space][space]b00=0x00
[space][space]b0f=0x0f
[space][space]bff=0xff
[space][space]mk=[]
[space][space]mk.append(bm(1,b55,b55))
[space][space]mk.append(bm(1,b33,b33))
[space][space]mk.append(bm(1,b0f,b0f))
[space][space]for[space]i[space]in[space]range(logn-3):
[space][space][space][space]mk.append(bm(tpwi[i],b00,bff))
[space][space]return

def[space]bm(nb,b1,b2):
[space][space]global[space]logn,byten,tpwi,mk
[space][space]u=0
[space][space]for[space]i[space]in[space]range(nb):
[space][space][space][space]u<<=8
[space][space][space][space]u|=b1
[space][space]for[space]i[space]in[space]range(nb):
[space][space][space][space]u<<=8
[space][space][space][space]u|=b2
[space][space]c=byten//(2*nb)
[space][space]h=2*nb*8
[space][space]v=0
[space][space]for[space]i[space]in[space]range(c):
[space][space][space][space]v<<=h
[space][space][space][space]v|=u
[space][space]return(v)


#[space]Delivers[space]number[space]of[space]1-bits[space]of[space]a[space]n-bit[space]variable[space]x[space](n=2**logn).
#[space]logn[space](>=[space]4)[space]is[space]to[space]be[space]defined[space]and[space]initbitcount()[space]invoked[space]before[space]first[space]use
#[space]of[space]bitcount().

def[space]bitcount(x):
[space][space]global[space]logn,byten,tpwi,mk
[space][space]for[space]i[space]in[space]range(logn):
[space][space][space][space]x=(x&mk[i])+((x>>tpwi[i])&mk[i])
[space][space]return(x)


#[space]Convert[space]a[space]byte[space]sequence[space]to[space]an[space]integer.

def[space]pack(byarray):
[space][space]k=0
[space][space]for[space]i[space]in[space]range(len(byarray)):
[space][space][space][space]k<<=8
[space][space][space][space]k|=byarray[i]
[space][space]return(k)


#[space]Convert[space]an[space]integer[space]to[space]a[space]nbytes[space]byte[space]sequence.

def[space]unpack(k,nbytes):
[space][space]list=[0[space]for[space]i[space]in[space]range(nbytes)]
[space][space]for[space]i[space]in[space]range(nbytes-1,-1,-1):
[space][space][space][space]list[i]=k&0xff
[space][space][space][space]k>>=8
[space][space]return(bytearray(list))[space][space]


#[space]Initialization[space]of[space]LOTUS[space]for[space]the[space]following[space]currently[space]valid[space]global[space]system
#[space]parameters[space](for[space]their[space]meaning,[space]see[space]the[space]illustrative[space]example[space]further[space]below):
#[space]secretkey
#[space]sessionkeyextension
#[space]logn
#[space]fillerchar
#[space]natuhenblock
#[space]polynomm
#[space]skipbits

def[space]initlotus():
[space][space]global[space]secretkey,[space]sessionkeyextension
[space][space]global[space]logn,blockbits,blockbytes,fillerchar,fillerbyte
[space][space]global[space]nauthenblock,polynomm
[space][space]global[space]blockmask,skipbits,skipmask,prrotmasklen,prrotmask,choicebit
[space][space]global[space]n,np1,tpwn,tpwnm1
[space][space]global[space]tpwnd4,mk0,mk1,mk2,mk3,sf0,sf1,sf2,sf3
#[space]Enforcing[space]some[space]plausibility[space]constraints:
[space][space]assert(7[space]<=[space]logn[space]<=[space]9[space]and[space]1[space]<=[space]nauthenblock[space]<=[space]3[space]and[space]3[space]<=[space]polynomm[space]<=[space]5\
[space][space][space][space][space][space][space][space][space]and[space]1[space]<=[space]skipbits[space]<=[space]2)
#[space]np1[space]and[space]tpwnm1[space]are[space]needed[space]by[space]the[space]functions[space]for[space]permutation[space]polynomials.
[space][space]n=2**logn
[space][space]np1=n+1
[space][space]tpwn=2**n
[space][space]tpwnm1=tpwn-1
[space][space]k=n//4
#[space]The[space]following[space]are[space]needed[space]by[space]ncombine()
[space][space]tpwnd4=2**k
[space][space]mk3=2**k-1
[space][space]mk2=mk3<<k
[space][space]mk1=mk2<<k
[space][space]mk0=mk1<<k
[space][space]sf3=0
[space][space]sf2=k
[space][space]sf1=2*k
[space][space]sf0=3*k
#[space]The[space]following[space]are[space]needed[space]by[space]prepareplaintextstr(),[space]lotusencrypt()[space]and
#[space]lotusdecrypt().
[space][space]blockbits=n
[space][space]blockbytes=blockbits//8
[space][space]blockmask=tpwnm1
[space][space]fillerbyte=bytearray(fillerchar,"latin-1")[space]
#[space]Mask[space]to[space]determine[space]prrot.
[space][space]prrotmask=blockbits-1
#[space]Length[space]of[space]prrotmask.
[space][space]prrotmasklen=logn
#[space]Mask[space]to[space]determine[space]skip.
[space][space]skipmask=2**skipbits-1
#[space]choicebit[space]is[space]used[space]for[space]a[space]0/1[space]choice,[space]it[space]is[space]arbitrarily[space]chosen[space]to[space]be[space]one[space]in[space]the
#[space]middle[space]of[space]the[space]block.
[space][space]choicebit=2**(n//2)
#[space]Initialization[space]for[space]the[space]bit[space]counting[space]functions.
[space][space]initbitcount()
#[space]Seed[space]Python's[space]built-in[space]PRNG.[space]Both[space]secretkey[space]and[space]sessionkeyextension[space]are
#[space]treated[space]as[space]strings.[space]
[space][space]random.seed(str(secretkey)+str(sessionkeyextension))
[space][space]return


#[space]Combining[space]two[space]n-bit[space]words[space]x[space]and[space]y[space](optimally[space]in[space]the[space]sense[space]of[space]avalanche).
#[space]See[space]http://s13.zetaboards.com/Crypto/topic/7169100/1/

def[space]ncombine(x,y):
[space][space]global[space]n,np1,tpwn,tpwnm1
[space][space]global[space]tpwnd4,mk0,mk1,mk2,mk3,sf0,sf1,sf2,sf3
[space][space]g=(2*x*y+x+y)%tpwn
[space][space]g0=(g&mk0)>>sf0
[space][space]g1=(g&mk1)>>sf1
[space][space]g2=(g&mk2)>>sf2
[space][space]g3=(g&mk3)
[space][space]s=g0+g1+g2+g3
[space][space]z0=(2*g0+s)%tpwn
[space][space]z1=(2*g1+s)%tpwn
[space][space]z2=(2*g2+s)%tpwn
[space][space]z3=(2*g3+s)%tpwn
[space][space]z=(z0<<sf0)|(z1<<sf1)|(z2<<sf2)|z3
[space][space]return(z)


#[space]Read[space]a[space]byte[space]sequence[space]from[space]a[space]binary[space]file.

def[space]readbinaryfile(binaryfilename):
[space][space]fp=open(binaryfilename+".bin","rb")
[space][space]byarray=bytearray(fp.read())
[space][space]fp.close()
[space][space]return(byarray)


#[space]Write[space]a[space]byte[space]sequence[space]to[space]a[space]binary[space]file.

def[space]writebinaryfile(byarray,binaryfilename):
[space][space]fp=open(binaryfilename+".bin","wb")
[space][space]fp.write(byarray)
[space][space]fp.close()


#[space]It[space]is[space]assumed[space]that[space]initialization[space]with[space]lotusinit()[space]has[space]been[space]done.[space]If[space]the
#[space]user-given[space]plaintext[space]is[space]in[space]the[space]form[space]of[space]a[space]string,[space]this[space]function[space]transforms[space]it
#[space]to[space]a[space]binary[space]file[space]of[space]the[space]format[space]needed[space]by[space]lotusencrypt()[space]for[space]encryption
#[space]processing.[space]It[space]is[space]assumed[space]that[space]the[space]characters[space]of[space]plaintextstr[space]are[space]in[space]latin-1.
#[space](In[space]case[space]the[space]user-given[space]material[space]is[space]binary[space](as[space]a[space]sequence[space]of[space]bytes[space]in[space]a[space]file),
#[space]this[space]function[space]is[space]of[space]course[space]not[space]used[space]and[space]one[space]proceeds[space]directly[space]with
#[space]lotusencrypt().)

def[space]prepareplaintextstr(plaintextstr,plaintextfilename):
[space][space]global[space]logn,blockbits,blockbytes,fillerchar,fillerbyte
#[space]Transform[space]the[space]plaintextstr[space]to[space]a[space]sequence[space]of[space]bytes.
[space][space]byarray=bytearray(plaintextstr,"latin-1")[space]
[space][space]numbytes=len(byarray)
[space][space]r=numbytes%blockbytes
#[space]Fill[space]to[space]whole[space]block[space]boundary[space]with[space]the[space]filler[space]character.
[space][space]if[space]r!=0:
[space][space][space][space]byarray+=(blockbytes-r)*fillerbyte
[space][space][space][space]print(blockbytes-r,"bytes[space]of","'"+fillerchar+"'",
[space][space][space][space][space][space][space][space][space][space]"are[space]appended[space]as[space]filler[space]to[space]the[space]given[space]plaintextstr")
#[space]Write[space]the[space]result[space]to[space]a[space]binary[space]file.
[space][space]writebinaryfile(byarray,plaintextfilename)
[space][space]print("Plaintext[space]written[space]to[space]file[space]with[space]name:",plaintextfilename,
[space][space][space][space][space][space][space][space]"(extension[space].bin)")
[space][space]return

[space]
#[space]This[space]function[space]serves[space]to[space]transform[space]the[space]binary[space]file[space]delivered[space]by[space]lotusdecrypt()
#[space]to[space]a[space]text[space]string.[space]It[space]is[space]assumed[space]that[space]the[space]bytes[space]in[space]the[space]binaryfile[space]are[space]in
#[space]latin-1[space]so[space]that[space]textstr[space]returned[space]can[space]be[space]printed.

def[space]gettextstrfrombinaryfile(binaryfilename):
[space][space]fp=open(binaryfilename+".bin","rb")
[space][space]byarray=fp.read()
[space][space]fp.close()
[space][space]leng=len(byarray)
[space][space]textstr=""
[space][space]for[space]i[space]in[space]range(leng):
[space][space][space][space]textstr+=chr(byarray[i])
[space][space]print(leng,"bytes[space]read[space]from[space]file[space]with[space]name:",binaryfilename,
[space][space][space][space][space][space][space][space]"(extension[space].bin)[space]and")
[space][space]print("transformed[space]to[space]textstr")
[space][space]return(textstr)


#[space]It[space]is[space]assumed[space]that[space]initialization[space]with[space]lotusinit()[space]has[space]been[space]done.[space]The
#[space]plaintext[space]file[space](binary,[space]a[space]sequence[space]of[space]bytes[space]whose[space]length[space]must[space]be[space]a[space]multiple[space]of
#[space]blockbytes)[space]is[space]processed[space]to[space]result[space]in[space]the[space]ciphertext[space]file.[space]For[space]meaning[space]of
#[space]some[space]of[space]the[space]global[space]variables,[space]see[space]also[space]lotusinit()[space]and[space]the[space]illustrative
#[space]example[space]further[space]below.

def[space]lotusencrypt(plaintextfilename,ciphertextfilename):
[space][space]global[space]logn,blockbits,blockbytes,fillerchar,fillerbyte
[space][space]global[space]nauthenblock,polynomm
[space][space]global[space]blockmask,skipbits,skipmask,prrotmasklen,prrotmask,choicebit
#[space]Initialize[space]sigma,[space]the[space]block[space]chaining[space]value,[space]with[space]a[space]PRN.
[space][space]sigma=random.getrandbits(blockbits)
#[space]Read[space]in[space]the[space]plaintext[space](or[space]in[space]multiple[space]encryption[space]the[space]intermediate[space]input)[space]file.
[space][space]byarray=readbinaryfile(plaintextfilename)
[space][space]numbytes=len(byarray)
[space][space]assert(numbytes%blockbytes==0)
[space][space]print(numbytes,"of[space]plaintext[space]read[space]from[space]file[space]with[space]name:",plaintextfilename,
[space][space][space][space][space][space][space][space]"(extension[space].bin)")
#[space]Generate[space]nauthenblock[space]blocks[space]of[space]random[space]bytes[space]for[space]the[space]purpose[space]of
#[space]authentication.
[space][space]authenblockslen=nauthenblock*blockbytes
[space][space]authenblocks=bytearray([random.getrandbits(8)[space]\
[space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space]for[space]i[space]in[space]range(authenblockslen)])
[space][space]byarray+=authenblocks
[space][space]numbytes=len(byarray)
[space][space]numblocks=numbytes//blockbytes
#[space]Generate[space]index[space]sequences[space]for[space]performing[space]transpositions.
[space][space]permseq1=[i[space]for[space]i[space]in[space]range(numbytes)]
[space][space]permseq2=permseq1[:]
[space][space]random.shuffle(permseq1)
[space][space]random.shuffle(permseq2)
#[space]Transpose[space]byarray[space]according[space]to[space]permseq1.
[space][space]list1=[byarray[permseq1[i]][space]for[space]i[space]in[space]range(numbytes)]
[space][space]byarray=bytearray(list1)
[space][space]cipherbyarray=bytearray("","latin-1")
[space][space]k=0
[space][space]for[space]blk[space]in[space]range(numblocks):
[space][space][space][space]t=sigma
#[space]Obtain[space]prrot[space]to[space]be[space]used[space]further[space]below.
[space][space][space][space]prrot=t&prrotmask
#[space]Skip[space]nskip[space]PRNs[space]output[space]by[space]the[space]PRNG[space]to[space]render[space]the[space]process[space]dynamic/variable[space]and
#[space]hence[space]hard[space]to[space]analyse.
[space][space][space][space]t>>=prrotmasklen
[space][space][space][space]nskip=t&skipmask
[space][space][space][space]for[space]i[space]in[space]range(nskip):
[space][space][space][space][space][space]random.getrandbits(blockbits)
#[space]Obtain[space]prn,[space]a[space]PRN,[space]to[space]be[space]used[space]further[space]below.
[space][space][space][space]prn=random.getrandbits(blockbits)
#[space]Generate[space]PRNs[space]for[space]the[space]coefficients[space]of[space]a[space]permutation[space]polynomial.
[space][space][space][space]permpoly=[random.getrandbits(blockbits)[space]for[space]i[space]in[space]range(polynomm)]
#[space]Modify[space]permpoly[space]to[space]satisfy[space]the[space]fullperiod[space]criteria.
[space][space][space][space]permpoly=fullperiodcriteria(permpoly,polynomm)
#[space]Obtain[space]an[space]integer[space]from[space]the[space]bytes[space]of[space]the[space]block.
[space][space][space][space]k1=k+blockbytes
[space][space][space][space]plainint=pack(byarray[k:k1])
[space][space][space][space]k=k1
#[space]xor[space]plainint[space]with[space]prn[space]and[space]the[space]chaining[space]value[space]sigma.
[space][space][space][space]blockint1=plainint^prn^sigma
#[space]Dynamic[space]choice[space]of[space]using[space]either[space]evalpermpoly()[space]or[space]invpermpoly()[space]to[space]do[space]the
#[space]substitution.[space]This[space]means[space]a[space]complexity[space]for[space]analysis[space]and[space]also[space]has[space]the
#[space]beneficial[space]effect[space]of[space]rendering[space]lotusencrypt()[space]and[space]lotusdecrypt()[space]running[space]at
#[space]roughly[space]the[space]same[space]speed,[space]since[space]invpermpoly()[space]runs[space]longer[space]than[space]evalpermpoly().
[space][space][space][space]choice=(sigma&choicebit)==0
[space][space][space][space]if[space]choice:[space][space][space][space][space][space]
[space][space][space][space][space][space]blockint2=evalpermpoly(permpoly,polynomm,blockint1)
[space][space][space][space]else:
[space][space][space][space][space][space]blockint2=invpermpoly(permpoly,polynomm,blockint1)
#[space]Do[space]a[space]rotation[space]of[space]the[space]bits.[space]The[space]amount[space]of[space]rotation[space]has[space]2[space]components,[space]the[space]one,
#[space]bitcount(),[space]serves[space]to[space]achieve[space]better[space]avalanche,[space]see
#[space]http://s13.zetaboards.com/Crypto/topic/7131993/1/,[space]the[space]other,[space]prrot,[space]is
#[space]pseudo-random[space](being[space]from[space]sigma,[space]which[space]is[space]dynamic[space](processing[space]dependent)),
#[space]which[space]hinders[space]attempts[space]to[space]reverse[space]the[space]rotation[space]without[space]knowledge[space]of[space]that
#[space]value.
[space][space][space][space]rot=(bitcount(blockint2)+prrot)%blockbits
[space][space][space][space]cipherint=((blockint2<<rot)&blockmask)|(blockint2>>(blockbits-rot))
#[space]Update[space]sigma[space]for[space]chaining[space]of[space]the[space]following[space]block.[space]Note[space]that,[space]in[space]distinction
#[space]to[space]CBC,[space]sigma[space]is[space]dependent[space]on[space]both[space]plaintext[space]and[space]ciphertext[space]of[space]all[space]preceding
#[space]blocks,[space]which[space]is[space]deemed[space]desirable[space]for[space]our[space]purposes.[space]We[space]choose[space]to[space]combine
#[space]plainint[space]and[space]cipherint[space]with[space]the[space]function[space]ncombine()[space]and[space]xor[space]the[space]result[space]to
#[space]the[space]current[space]sigma.[space](+[space]is[space]used[space]in[space]ncombine(),[space]hence[space]xor[space]here[space]to[space]result[space]in[space]a
#[space]diversity[space]of[space]operators[space]facing[space]the[space]analyst.)[space]Note[space]that[space]cipherint[space]is[space]further
#[space]processed[space]with[space]a[space]transposition[space]before[space]becoming[space]cipherarray[space]to[space]be[space]output[space]by[space]the
#[space]function,[space]hence[space]it[space]is[space]not[space]an[space]externally[space]accessible[space]value.
[space][space][space][space]sigma=(sigma^ncombine(plainint,cipherint))&blockmask
#[space]Transform[space]cipherint[space]to[space]a[space]sequence[space]of[space]bytes[space]and[space]accumulate[space]that[space]in
#[space]cipherbyarray.
[space][space][space][space]cipherbyarray+=unpack(cipherint,blockbytes)
#[space]Transpose[space]cipherarray[space]according[space]to[space]permseq2.
[space][space]list2=[cipherbyarray[permseq2[i]][space]for[space]i[space]in[space]range(numbytes)]
[space][space]cipherbyarray=bytearray(list2)
#[space]Write[space]the[space](final)[space]ciphertext[space]in[space]cipherbyarray[space]to[space]a[space]binary[space]file.
[space][space]writebinaryfile(cipherbyarray,ciphertextfilename)
[space][space]print("Ciphertext[space]written[space]to[space]file[space]with[space]name:",ciphertextfilename,
[space][space][space][space][space][space][space][space]"(extension[space].bin)")
[space][space]return()


#[space]The[space]reverse[space]of[space]lotusencrypt().[space]It[space]is[space]assumed[space]that[space]initialization[space]with
#[space]lotusinit()[space]has[space]been[space]done.

def[space]lotusdecrypt(ciphertextfilename,decryptedtextfilename):
[space][space]global[space]logn,blockbits,blockbytes,fillerchar,fillerbyte
[space][space]global[space]nauthenblock,polynomm
[space][space]global[space]blockmask,skipbits,skipmask,prrotmasklen,prrotmask,choicebit
[space][space]sigma=random.getrandbits(blockbits)
[space][space]authenblockslen=nauthenblock*blockbytes
[space][space]authenblocks=bytearray([random.getrandbits(8)[space]\
[space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space][space]for[space]i[space]in[space]range(authenblockslen)])
[space][space]cipherbyarray=readbinaryfile(ciphertextfilename)
[space][space]print("Ciphertext[space]read[space]from[space]file[space]with[space]name:",ciphertextfilename,
[space][space][space][space][space][space][space][space]"(extension[space].bin)")[space][space]
[space][space]numbytes=len(cipherbyarray)
[space][space]assert(numbytes%blockbytes==0)
[space][space]numblocks=numbytes//blockbytes
[space][space]permseq1=[i[space]for[space]i[space]in[space]range(numbytes)]
[space][space]permseq2=permseq1[:]
[space][space]random.shuffle(permseq1)
[space][space]random.shuffle(permseq2)
[space][space]list2=[0[space]for[space]i[space]in[space]range(numbytes)]
[space][space]for[space]i[space]in[space]range(numbytes):
[space][space][space][space]list2[permseq2[i]]=cipherbyarray[i]
[space][space]cipherbyarray=bytearray(list2)
[space][space]byarray=bytearray(b"")
[space][space]k=0
[space][space]for[space]blk[space]in[space]range(numblocks):
[space][space][space][space]t=sigma
[space][space][space][space]prrot=t&prrotmask
[space][space][space][space]t>>=prrotmasklen
[space][space][space][space]nskip=t&skipmask
[space][space][space][space]for[space]i[space]in[space]range(nskip):
[space][space][space][space][space][space]random.getrandbits(blockbits)
[space][space][space][space]prn=random.getrandbits(blockbits)
[space][space][space][space]permpoly=[random.getrandbits(blockbits)[space]for[space]i[space]in[space]range(polynomm)]
[space][space][space][space]permpoly=fullperiodcriteria(permpoly,polynomm)
[space][space][space][space]k1=k+blockbytes
[space][space][space][space]cipherint=pack(cipherbyarray[k:k1])
[space][space][space][space]k=k1
[space][space][space][space]rot=(bitcount(cipherint)+prrot)%blockbits
[space][space][space][space]blockint2=(cipherint>>rot)|((cipherint<<(blockbits-rot))&blockmask)
[space][space][space][space]choice=(sigma&choicebit)==0
[space][space][space][space]if[space]choice:
[space][space][space][space][space][space]blockint1=invpermpoly(permpoly,polynomm,blockint2)
[space][space][space][space]else:
[space][space][space][space][space][space]blockint1=evalpermpoly(permpoly,polynomm,blockint2)
[space][space][space][space]plainint=blockint1^prn^sigma
[space][space][space][space]sigma=(sigma^ncombine(plainint,cipherint))&blockmask
[space][space][space][space]byarray+=unpack(plainint,blockbytes)
[space][space]list1=[0[space]for[space]i[space]in[space]range(numbytes)]
[space][space]for[space]i[space]in[space]range(numbytes):
[space][space][space][space]list1[permseq1[i]]=byarray[i]
[space][space]byarray=bytearray(list1)
[space][space]authenblocksrecovered=byarray[-authenblockslen:]
#[space]Check[space]whether[space]the[space]authenblock[space]recovered[space]is[space]correct.
[space][space]if[space]authenblocksrecovered==authenblocks:
[space][space][space][space]print("Authentication[space](integrity[space]check)[space]o.k.")
[space][space]else:
[space][space][space][space]print("Authentication[space](integrity[space]check)[space]failed")
[space][space][space][space]exit(222)
#[space]Write[space]the[space]decrypted[space]text[space]in[space]byarray[space]to[space]a[space]binary[space]file.
[space][space]writebinaryfile(byarray[:-authenblockslen],decryptedtextfilename)
[space][space]print("Decrypted[space]text[space]written[space]to[space]file[space]with[space]name:",decryptedtextfilename,
[space][space][space][space][space][space][space][space]"(extension[space].bin)")
[space][space]return



###################[space]End[space]of[space]Part[space]1[space]of[space]LOTUS,[space]Version[space]1.1[space]########################
################################################################################
################################################################################
Edited by mok-kong shen, Mar 24 2014, 02:26 PM.
Offline Profile Quote Post Goto Top
 
mok-kong shen
NSA worthy
[ *  *  *  *  *  * ]
Code:
 
################################################################################
##################[space]Begin[space]of[space]Part[space]2[space]of[space]LOTUS,[space]Version[space]1.1[space]#######################



#[space]Installation[space]of[space]the[space]software.

#[space]Both[space]communication[space]partners[space]have[space]to[space]download[space]the[space]same[space]version[space]3x[space]of[space]Python
#[space]from[space]http://www.python.org.[space](Employing[space]the[space]same[space]version[space]of[space]Python[space]ensures
#[space]against[space]any[space]potentially[space]possible[space]incompatibilities[space]among[space]different[space]versions.)
#[space]The[space]present[space]code[space]can[space]be[space]stored[space]in[space]a[space]file[space]named[space]e.g.[space]lotus.py[space]and[space]the[space]example
#[space]given[space]below[space]run[space]in[space]Python's[space]GUI[space]IDLE.[space](File[space]-->[space]Open[space]to[space]find[space]and[space]open[space]the
#[space]file[space]then[space]in[space]the[space]window[space]showing[space]the[space]code[space]Run[space]-->[space]Run[space]Module[space]to[space]run[space]it.[space]One
#[space]could[space]also[space]type[space]lotus.py[space]in[space]a[space]DOS-window.)[space]Modifications[space]of[space]the[space]code[space]in[space]the
#[space]code[space]window,[space]e.g.[space]the[space]plaintext[space]string,[space]can[space]be[space]done[space]online[space]and[space]the[space]code
#[space]re-run.



################################################################################



#[space]Appendix.


#[space]This[space]appendix[space]contains[space]an[space]illustrative[space]example[space]of[space]encryption[space]and[space]decryption,
#[space]a[space]number[space]of[space]useful[space]utility[space]functions[space]and[space]a[space]test[space]of[space]Python's[space]built-in[space]PRNG.

#[space]Users[space]running[space]his[space]own[space]code[space]lines[space]may[space]desire[space]to[space]deactivate[space]a[space]certain[space]region
#[space](or[space]the[space]whole)[space]of[space]the[space]appendix.[space]This[space]may[space]be[space]done[space]through[space]placing[space]3[space]successive
#[space]quotes[space](i.e.[space]""")[space]to[space]the[space]line[space]before[space]as[space]well[space]as[space]to[space]the[space]line[space]following[space]that
#[space]region.

[space]
#[space]An[space]illustrative[space]example.


#[space]Note[space]that[space]appropriate[space]choice[space]of[space]the[space]system[space]parameters[space]and[space]proper[space]management
#[space]of[space]the[space]secret[space]key[space]materials[space]are[space]evidently[space]user's[space]own[space]responsibility[space]in[space]order
#[space]to[space]be[space]able[space]to[space]obtain[space]the[space]required[space]security[space]for[space]his[space]applications.

#[space]The[space]following[space]code[space]lines[space]specifying[space]the[space]system[space]parameters[space]are[space]to[space]be[space]the[space]same
#[space]for[space]both[space]communication[space]partners.

#[space]A[space]secret[space]key.[space]This[space]should[space]have[space]sufficient[space]entropy[space](i.e.[space]number[space]of[space]bits[space]of
#[space]randomness)[space]for[space]the[space]application[space]concerned.

secretkey="4a98717c70e997c2715e87c3fa1ef559"

#[space]A[space]dynamic[space](variable)[space]session-dependent[space]supplementary[space]key,[space]being[space]dependent
#[space]e.g.[space]on[space]subject,[space]date,[space]message[space]serial[space]number,[space]etc.[space]Its[space]use[space]enables[space]secretkey
#[space]to[space]be[space]used[space]for[space]a[space]longer[space]time,[space]while[space]rendering[space]different[space]sessions[space]have
#[space]different[space]effective[space]keys,[space]which[space]is[space]desirable.

sessionkeyextension="JJJ[space]07.03.2014[space]TM099"

#[space]Let[space]n[space]denote[space]the[space]number[space]of[space]bits[space]in[space]a[space]block,[space]logn[space]specifies[space]the[space]log[space]of[space]n.
#[space]7[space]<=[space]logn[space]<=[space]9.[space]Here[space]we[space]specify[space]that[space]each[space]block[space]has[space]2**7[space]=[space]128[space]bits.

logn=7

#[space]If[space]the[space]user-given[space]plaintext[space]doesn't[space]end[space]at[space]a[space]block[space]boundary,[space]it[space]will[space]be
#[space]appended[space]with[space]filler[space]characters.[space]Here[space]we[space]specify[space]that[space]"z"[space]is[space]to[space]be[space]the[space]filler.

fillerchar='z'

#[space]Number[space]of[space]authentication[space]blocks.[space]1[space]<=[space]nauthenblock[space]<=[space]3.

nauthenblock=1

#[space]Degree[space]of[space]permutation[space]polynormials[space]to[space]be[space]used[space]plus[space]1.[space]3[space]<=[space]polynomm[space]<=[space]5.
#[space]We[space]choose[space]to[space]use[space]second[space]degree[space]polynomials[space](2[space]+[space]1[space]=[space]3).

polynomm=3

#[space]To[space]achieve[space]some[space]dynamics/variability[space]of[space]processing[space]of[space]a[space]block,[space]a[space]number
#[space](skipbits)[space]of[space]bits[space]are[space]taken[space]from[space]sigma[space]to[space]determine[space]the[space]number[space]of[space]outputs
#[space]from[space]Python's[space]built-in[space]PRNG[space]that[space]are[space]to[space]be[space]skipped.[space]1[space]<=[space]skipbits[space]<=[space]2.

skipbits=1


#[space]Sender[space]side[space]coding:

print("Sender[space]side[space]system[space]messages:")
plaintextstr="Should[space]not[space]we,[space]then,[space]exert[space]ourselves[space]to[space]do[space]good?[space]--[space]"\
[space][space][space][space][space][space][space][space][space][space][space][space][space][space]"from[space]Kan[space]Ying[space]Pien[space](The[space]Book[space]of[space]Rewards[space]and[space]Punishments,[space]"\
[space][space][space][space][space][space][space][space][space][space][space][space][space][space]"translated[space]by[space]J.[space]Webster)"
initlotus()
prepareplaintextstr(plaintextstr,"plaintext")
lotusencrypt("plaintext","ciphertext")
print()


#[space]File[space]ciphertext.bin[space]obtained[space]is[space]to[space]be[space]transmitted[space]to[space]the[space]recipient.

[space]
#[space]Recipient[space]side[space]coding:

print("Recipient[space]side[space]system[space]messages:")
initlotus()
lotusdecrypt("ciphertext","plaintextrecovered")
recoveredplaintextstr=gettextstrfrombinaryfile("plaintextrecovered")
print()


#[space]The[space]following[space]lines[space]serve[space]to[space]check[space]whether[space]our[space]code[space]has[space]correctly[space]functioned
#[space]in[space]the[space]above[space]example.

print("Result:")
print()
print("Plaintext[space]sent:")
print(plaintextstr)
print()
print("Possibly[space]end-filled[space]recovered[space]plaintext:")
print(recoveredplaintextstr)
print()
print("Comparison:")
print(plaintextstr==recoveredplaintextstr[:len(plaintextstr)])
print()
print()



#[space]It[space]may[space]be[space]mentioned[space]that[space]for[space]key[space]management[space]a[space]master[space]secretkey[space]may[space]be[space]kept
#[space]and[space]secretkey[space]that[space]is[space]to[space]be[space]used,[space]say,[space]in[space]a[space]certain[space]month,[space]be[space]obtained[space]through
#[space]encryption[space]of[space]a[space]chosen[space]secret[space]text[space]string[space]that[space]contains[space]the[space]designation[space]of[space]the
#[space]month[space]and[space]the[space]year[space]with[space]the[space]master[space]key[space]and[space]take[space]an[space]appropriate[space]section[space]from
#[space]the[space]returned[space]ciphertext[space]bytes.[space]The[space]following[space]function[space]may[space]be[space]of[space]use[space]thereby.

#[space]Obtain[space]a[space]hexadecimal[space]sequence[space](without[space]the[space]"0x"[space]at[space]the[space]front)[space]from[space]the[space]content
#[space]of[space]a[space]binary[space]file.

def[space]gethexstrfrombinaryfile(binaryfilename):
[space][space]fp=open(binaryfilename+".bin","rb")
[space][space]byarray=fp.read()
[space][space]fp.close()
[space][space]hexstr=""
[space][space]for[space]i[space]in[space]range(len(byarray)):
[space][space][space][space]h=hex(byarray[i])[2:]
[space][space][space][space]if[space]len(h)<2:
[space][space][space][space][space][space]h="0"+h
[space][space][space][space]hexstr+=h
[space][space]return(hexstr)


#[space]The[space]master[space]secret[space]key[space](and[space]preferably[space]also[space]another[space]one[space]in[space]reserve[space]for[space]the
#[space]emergency[space]case[space]that[space]the[space]former[space]is[space]no[space]longer[space]usable)[space]must[space]evidently[space]be
#[space]carefully[space]created[space]to[space]have[space]sufficient[space]entropy[space]and[space]hence[space]difficult[space]for[space]the
#[space]analyst[space]to[space]determine[space]it[space]via[space]brute-forcing.[space]Commonly[space]it[space]is[space]deemed[space]desirable[space]to
#[space]have[space]one[space]that[space]is[space]equivalent[space]to[space]at[space]least[space]128[space]bits[space]of[space]randomness.[space]The[space]present
#[space]author[space]suggested[space]for[space]this[space]purpose[space]to[space]mix[space]a[space]number[space]of[space]secretly[space]chosen[space]natural
#[space]language[space]text[space]strings,[space]since[space]the[space]English[space]language[space]texts[space]are[space]estimated[space]to[space]have
#[space]from[space]0.6[space]to[space]1.6[space]bits[space]of[space]entropy[space]pro[space]character[space]such[space]that[space]employing[space]a[space]medium
#[space]sized[space]string[space]resulting[space]from[space]such[space]a[space]mixture[space]would[space]be[space]sufficient.[space]Note[space]that,[space]if
#[space]the[space]communication[space]partner[space]is[space]able[space]to[space]do[space]the[space]same[space]mixing[space](from[space]the[space]same[space]texts),
#[space]then[space]a[space]transfer[space]of[space]the[space]resulting[space]secret[space]key[space]string[space]is[space]not[space]necessary.[space]For[space]a
#[space]code[space]to[space]perform[space]the[space]mixing,[space]see
#[space]http://s13.zetaboards.com/Crypto/topic/6936496/1/.[space]Users[space]of[space]LOTUS[space]may
#[space]preferably[space]instead[space]encrpyt[space]a[space]pair[space]of[space]text[space]strings[space]with[space]LOTUS,[space]combine[space]the
#[space]resulting[space]binary[space]files[space]using[space]the[space]following[space]function[space]and[space]obtain[space]a[space]hex[space]string
#[space]with[space]the[space]function[space]gethexstrfrombinaryfile()[space]above.[space](In[space]case[space]of[space]more[space]than[space]two
#[space]text[space]strings[space]this[space]processing[space]may[space]be[space]repeated.)

#[space]Combine[space]two[space]binary[space]files[space]with[space]the[space]function[space]ncombine().[space]A[space]prior[space]invocation[space]of
#[space]initlotus()[space]is[space]assumed.[space]If[space]the[space]input[space]files[space]are[space]not[space]of[space]the[space]same[space]length,[space]the
#[space]smaller[space]one[space]determines[space]the[space]size[space]of[space]the[space]output[space]file.

def[space]combinefiles(binaryfilename1,binaryfilename2,combinedbinaryfilename):
[space][space]global[space]logn,blockbits,blockbytes,fillerchar,fillerbyte[space][space]
[space][space]byarray1=readbinaryfile(binaryfilename1)
[space][space]byarray2=readbinaryfile(binaryfilename2)
[space][space]leng=min(len(byarray1),len(byarray2))
[space][space]byarray=bytearray("","latin-1")
[space][space]k=0
[space][space]k1=blockbytes
[space][space]while[space]k1<=leng:
[space][space][space][space]int1=pack(byarray1[k:k1])
[space][space][space][space]int2=pack(byarray2[k:k1])
[space][space][space][space]int3=ncombine(int1,int2)
[space][space][space][space]byarray+=unpack(int3,blockbytes)
[space][space][space][space]k=k1
[space][space][space][space]k1=k+blockbytes
[space][space]writebinaryfile(byarray,combinedbinaryfilename)
[space][space]return


#[space]A[space]different[space]approach[space]to[space]obtain[space]a[space]good[space]secret[space]key[space]that[space]in[space]practice[space]is[space]also
#[space]easily[space]available[space]to[space]the[space]common[space]users,[space]is[space]to[space]throw[space]dice.[space]There[space]are[space]different
#[space]sorts[space]of[space]dice[space]purchasable[space]in[space]game[space]shops.[space]The[space]8-sided[space]ones[space]are[space]most[space]simple[space]for
#[space]the[space]computaton[space]of[space]the[space]bit[space]strings[space]to[space]be[space]derived[space]from[space]each[space]throw.[space]But[space]dice[space]with
#[space]larger[space]number[space]of[space]sides[space]needs[space]less[space]number[space]of[space]dice[space]and/or[space]number[space]of[space]throws.[space]For
#[space]a[space]12-sided[space]die,[space]for[space]example,[space]a[space]throw[space]results[space]in[space]a[space]number[space]t[space]in[space][1,[space]12].[space]We[space]can
#[space]commpute[space]the[space]corresponding[space]pseudo-random[space]bits[space]as[space]follows,[space]denoting[space]by
#[space]bits(s,n)[space]the[space]bit[space]string[space]of[space]size[space]s[space]for[space]the[space]integer[space]n,[space]e.g.[space]bits(3,2)[space]is[space]"010":
#[space]if[space]1[space]<=[space]t[space]<=[space]8[space]:[space][space]bstr[space]=[space]bits(3,t-1)[space]
#[space]if[space]9[space]<=[space]t[space]<=[space]12:[space][space]bstr[space]=[space]bits(2,t-9)
#[space]The[space]accumulated[space]bit[space]string[space]of[space]sufficient[space]length[space]can[space]finally[space]be[space]expressed[space]as
#[space]a[space]hexadecimal[space]sequence[space]for[space]convenience[space]of[space]use.[space]Note[space]that[space]a[space]tiny[space]simplification
#[space]of[space]computation[space]is[space]to[space]use[space]only[space]the[space]first[space]relation[space]above,[space]i.e.[space]ignoring[space]all
#[space]t[space]>[space]8[space]but[space]that[space]means[space]a[space]larger[space]number[space]of[space]throws.[space](It[space]seems[space]in[space]fact[space]that[space]the
#[space]possiblity[space]of[space]additionally[space]employing[space]the[space]second[space]relation[space]above[space]to[space]optimally
#[space]extract[space]the[space]entropies[space]from[space]dice[space]throws[space]is[space]not[space]popularly[space]noticed.)[space]For[space]dice
#[space]with[space]other[space]number[space]of[space]sides[space]a[space]similar[space]computation[space]can[space]be[space]done.[space]The[space]bit[space]string
#[space]thus[space]obtained[space]can[space]be[space]expressed[space]as[space]a[space]hexadecimal[space]string[space](without[space]0x[space]at[space]the
#[space]front)[space]with[space]the[space]following[space]function:[space]

def[space]gethexstrfrombitstr(bitstr):
[space][space]hexlist=[]
[space][space]bitlist=[]
[space][space]for[space]i[space]in[space]range(16):
[space][space][space][space]st=bin(i)[2:]
[space][space][space][space]df=4-len(st)
[space][space][space][space]if[space]df>0:
[space][space][space][space][space][space]bitlist+=[df*'0'+st]
[space][space][space][space]else:
[space][space][space][space][space][space]bitlist+=[st]
[space][space][space][space]hexlist+=hex(i)[2:]
[space][space]hexstr=""
[space][space]leng=len(bitstr)
[space][space]k=0
[space][space]k1=4
[space][space]while[space]k1<=leng:
[space][space][space][space]bs=bitstr[k:k1]
[space][space][space][space]hexstr+=hexlist[bitlist.index(bs)]
[space][space][space][space]k=k1
[space][space][space][space]k1=k+4
[space][space]return(hexstr)

#[space]A[space]utility[space]program[space]for[space]convenient[space]conversion[space]of[space]dice[space]throws[space]to[space]hexadecimal
#[space]strings[space]is[space]available[space]at:[space]http://s13.zetaboards.com/Crypto/topic/7126796/1/


#[space]It[space]may[space]be[space]noted[space]that,[space]since[space]both[space]lotusencrypt()[space]and[space]lotusdecrypt()[space]work[space]with
#[space]files,[space]it[space]is[space]convenient,[space]if[space]desired,[space]to[space]do[space]multiple[space]encryption[space]with[space]LOTUS
#[space](with[space]different[space]system[space]parameter[space]values)[space]or[space]to[space]accept[space]encrypted[space]stuffs[space]from
#[space]other[space]algorithms[space]for[space]further[space]processing[space](e.g.[space]from[space]author's[space]PREFIXCODING
#[space]http://s13.zetaboards.com/Crypto/topic/7164646/1/).[space]In[space]such[space]cases[space]all[space]file
#[space]lengths[space]must[space]however[space]be[space]multiples[space]of[space]one[space]and[space]the[space]same[space]value[space]of[space]blockbytes,
#[space]i.e.[space]eventually[space]necessitating[space]appending[space]a[space]required[space]number[space]of[space]arbitrary[space]chosen
#[space]filler[space]bytes[space]to[space]the[space]files[space]to[space]be[space]input[space]to[space]LOTUS[space]to[space]satisfy[space]its[space]processing
#[space]requirement.[space]In[space]case[space]file[space]lenthening[space]is[space]required[space]it[space]may[space]be[space]done[space]with[space]the
#[space]following[space]function[space]lengthenfile().[space]The[space]recipient[space](who[space]has[space]to[space]be[space]informed[space]of
#[space]the[space]number[space]of[space]added[space]bytes)[space]will[space]then[space]need[space]a[space]file[space]shortening[space]operation[space]which
#[space]may[space]be[space]performed[space]with[space]the[space]function[space]shortenfile()[space]further[space]below.

#[space]Lengthen[space]a[space]binary[space]file[space]with[space]numbytes[space]pseudo-random[space]bytes.[space]seed[space]is[space]an[space]arbitrary
#[space]seed[space]used[space]to[space]seed[space]Python's[space]built-in[space]PRNG.[space]Note[space]that[space]call[space]of[space]this[space]function[space]may
#[space]NOT[space]be[space]positioned[space]between[space]lotusinit()[space]and[space]the[space]corresponding[space]encryption[space]or
#[space]decryption[space]function[space]calls[space](due[space]to[space]conflict[space]in[space]seeding[space]the[space]PRNG).

def[space]lengthenfile(seed,binaryfilename,numbytes):
[space][space]byarray=readbinaryfile(binaryfilename)
[space][space]random.seed(seed)
[space][space]byarray+=bytearray([random.getrandbits(8)[space]for[space]i[space]in[space]range(numbytes)])
[space][space]writebinaryfile(byarray,binaryfilename)
[space][space]return


#[space]Shorten[space]a[space]binary[space]file[space]by[space]numbytes[space]bytes.

def[space]shortenfile(binaryfilename,numbytes):
[space][space]byarray=readbinaryfile(binaryfilename)
[space][space]writebinaryfile(byarray[:-numbytes],binaryfilename)
[space][space]return


#[space]Users[space]who[space]are[space]new[space]to[space]Python[space]or[space]who[space]begin[space]to[space]use[space]a[space]new[space]version[space]of[space]the[space]Python
#[space]software[space]may[space]like[space]to[space]know[space]a[space]little[space]bit[space]about[space]the[space]statistical[space]qualities[space]of[space]its
#[space]built-in[space]PRNG[space]which[space]is[space]employed[space]in[space]LOTUS.[space]The[space]following[space]code[space]is[space]intended[space]to
#[space]serve[space]for[space]that[space]purpose.[space]prnbitn[space]is[space]the[space]number[space]of[space]bits[space]of[space]the[space]PRNs[space]to[space]be
#[space]generated[space]and[space]must[space]be[space]a[space]multiple[space]of[space]8.[space]testseed[space]is[space]any[space]arbitrary[space]seed[space]chosen
#[space]for[space]running[space]the[space]test.[space]One[space]may[space]like[space]to[space]try[space]a[space]number[space]of[space]different[space]prnbitn[space]and
#[space]testseed.

import[space]math,random

#[space]Maurer's[space]Universal[space]Test,[space]see[space][2].
#[space][2][space]J-S.[space]Coron,[space]D.[space]Naccache,[space]An[space]Accurate[space]Evaluation[space]of[space]Maurer's[space]Universal[space]Test.
#[space][space][space][space][space]http://www.jscoron.fr/publications/universal.pdf

qq=2560
qqp1=qq+1
kk=256000
qqkkp1=qq+kk+1

def[space]maurertest(bb):
[space][space]global[space]qq,qqp1,kk,qqkkp1
[space][space]eftu=7.1836656
#[space]y1[space]and[space]y2[space]are[space]for[space]rho=0.01[space]and[space]rho=0.001[space]respectively.
[space][space]y1=2.5758
[space][space]y2=3.2905
[space][space]t=[0[space]for[space]i[space]in[space]range(256)]
[space][space]for[space]i[space]in[space]range(1,qqp1,1):
[space][space][space][space]t[bb[i]]=i
[space][space]sum=0.0
[space][space]for[space]i[space]in[space]range(qqp1,qqkkp1,1):
[space][space][space][space]sum+=math.log10(i-t[bb[i]])
[space][space][space][space]t[bb[i]]=i
[space][space]tu=(sum/kk)/math.log10(2.0)
[space][space]c=math.sqrt(0.3732189+(0.3730195*256)/kk)
[space][space]sigma=c*math.sqrt(3.2386622/kk)
[space][space]t11=eftu-y1*sigma
[space][space]t12=eftu+y1*sigma
[space][space]t21=eftu-y2*sigma
[space][space]t22=eftu+y2*sigma
[space][space]return(tu,t11,t12,t21,t22)

def[space]maurertestresult(h,gg):
[space][space]global[space]chnum
[space][space]global[space]qq,qqp1,kk,qqkkp1
[space][space]if[space]h*chnum<qqkkp1:
[space][space][space][space]print("Error[space]in[space]maurertestresult")
[space][space][space][space]exit(6)
[space][space]bb=[0[space]for[space]k[space]in[space]range(h*chnum)]
[space][space]u=0
[space][space]k1=-1
[space][space]k2=chnum-1
[space][space]for[space]i[space]in[space]range(h):
[space][space][space][space]g=gg[i]
[space][space][space][space]for[space]k[space]in[space]range(k2,k1,-1):
[space][space][space][space][space][space]bb[u]=g&0xff
[space][space][space][space][space][space]g>>=8
[space][space][space][space][space][space]u+=1
[space][space][space][space]k1+=chnum
[space][space][space][space]k2+=chnum
[space][space]tu,t11,t12,t21,t22[space]=[space]maurertest(bb)
[space][space]print("Maurer's[space]Universal[space]Test[space]for[space]L=8,[space]rho=0.01[space](Middle[space]value[space]is[space]the[space]"\
[space][space][space][space][space][space][space][space]"test[space]statistic\nand[space]should[space]lie[space]between[space]the[space]other[space]two[space]values):")
[space][space]print(t11,tu,t12)


def[space]randtest(prnbitn,testseed):
[space][space]global[space]chnum
[space][space]if[space]prnbitn<8[space]or[space](prnbitn%8)!=0:
[space][space][space][space]print("Error[space]randtext:[space]Wrong[space]prnbitn")
[space][space][space][space]exit(55555)
[space][space]chnum=prnbitn//8
[space][space]h=qqkkp1//chnum
[space][space]if[space]h*chnum<qqkkp1:
[space][space][space][space]h+=1
[space][space]random.seed(testseed)
[space][space]tpwbitnm1=2**prnbitn-1

[space][space]print("PRNs[space]generated[space]with[space]random.randint():")
[space][space]gg=[random.randint(0,tpwbitnm1)[space]for[space]i[space]in[space]range(h)]
[space][space]maurertestresult(h,gg)
[space][space]print("PRNs[space]generated[space]with[space]random.getrandbits():")
[space][space]gg=[random.getrandbits(prnbitn)[space]for[space]i[space]in[space]range(h)]
[space][space]maurertestresult(h,gg)
[space][space]return


#[space]User[space]chosen[space]test[space]parameters:

prnbitn=128
testseed="My[space]arbitrarily[space]chosen[space]seed"

#[space]Run[space]the[space]test.

print("Test[space]of[space]Python's[space]PRNG,[space]parameters[space]used:")
print("prnbitn:",prnbitn)
print("testseed:",testseed)
randtest(prnbitn,testseed)
Edited by mok-kong shen, Mar 29 2014, 03:01 PM.
Offline Profile Quote Post Goto Top
 
mok-kong shen
NSA worthy
[ *  *  *  *  *  * ]
A new Version 1.1 of LOTUS is now available. In it the code of the function ncombine(), which combines two n-bit words, is replaced by a better one in respect of avalanche (see http://s13.zetaboards.com/Crypto/topic/7169100/1/).
Offline Profile Quote Post Goto Top
 
1 user reading this topic (1 Guest and 0 Anonymous)
« Previous Topic · General · Next Topic »
Add Reply