#### Do you have a question? Post it now! No Registration Necessary. Now with pictures!

**posted on**

- Mok-Kong Shen

June 24, 2013, 6:35 pm

JADE-S is a successor of JADE. It employs the same PRN generation

scheme as JADE but implements a novel idea of block encryption

processing which is inspired by the iterative solution of systems of

linear equations and is presented by me recently in a thread in this

group. For comments and critiques I should be very grateful.

M. K. Shen

-----------------------------------------------------------------------

# JADE-S, a block cipher with authentication (integrity check) based on

the use

# of permutation polynomials mod 2

******n

# JADE-S is a block encryption scheme for securing the privacy of

communications

# of the common people via encrypting text messages (with automatically

# performed authentication (integrity check)) sent over the Internet.

Its novel

# design includes as a major component a sophistically designed

pseudo-random

# number (PRN) generation scheme, involving a pool of constituent PRN

generators

# (PRNGs) based on permutation polynomials mod 2

******n that are pseudo-randomly

# activated (by themselves) with runtime dynamic renewal. Block lengths

ranging

# from 128 to 1024 bits can be chosen by the user. Blocks of n bits are

treated

# as n-bit integers with certain arithmetic operations being directly

performed

# upon them. The PRNGs in the pool serve further the purpose of

pseudo-random

# substitution (in the crypto sense) operations, since permutation

polynomials

# can be employed for bijective mappings. Particular attention is paid

to very

# thoroughly mixing together the entire set of blocks that constitute the

# user-given messages during encryption processing, thus resulting in

superior

# avalanche effects. The very good readability of its open-source code

enables

# the user to easily ensure the correctness of the code and that there

can be no

# backdoors as could otherwise potentially be the case where commercial

# proprietary (blackbox) encryption software are employed. Speed competition

# with commercial software in processing huge volumes of materials, e.g.

# graphics files, is intentionally excluded from the design goals of

JADE-S. On

# the other hand, extreme prudence is taken to ensure that the code is

# practically absolutely immune to all known attacks against block ciphers

# owing to the fact that their underlying assumptions simply don't hold for

# JADE-S from the very beginning. (JADE-S presumably will be secure as

well in

# the forthcoming so-called post-quantum era.) Despite the trade-offs hereby

# forcefully being taken, JADE-S's processing efficiency, as benchmarking

# clearly shows, is nonetheless entirely acceptable for its targeted

users (see

# result of running Ex. 2 in Sec.2, and Sec.3).

# JADE-S is a successor of JADE (latest Version 2.0.3 available from

# http://s13.zetaboards.com/Crypto/topic/6948465/1/#new ). It employs the

same

# PRN generation scheme as JADE but implements a novel idea of block

encryption

# processing which is taken from the iterative method of solutions of

systems of

# equations in linear algegra and which is recently posted to a number

of Usenet

# groups by the present author. A breif description of the major design

features

# of JADE-S is as follows:

#

# 1. With the user-given key we build up in a bootstrap way from a PRNG

based on

# permutaton polynomial mod 2

******n through an intermediate pool, i.e. a

large

# number, of PRNGs of the same kind to a final pool of such PRNGs. The

# outputs of the final pool of PRNGs (which are pseudo-randomly

chosen to be

# activated by their own outputs) are post-processed through appropriate

# summation and buffering such that the statistical qualities of the PRNs

# ultimately being delivered are greatly improved and any attacks of the

# analysts are rendered infeasible in practice.

#

# 2. Denoting the blocks of plainatext by x1, x2, ... xk, we perform the

# following assignments sequentially for encryption processing:

# x1 := f1(x1 + x2 ... + xk ^ r1)

# x2 := f2(x1 + x2 ... + xk ^ r2)

# ................

# xk := fk(x1 + x2 ... + xk ^ rk)

# where the f's are the permutation polynomials pseudo-randomly

chosen from

# those available in the final PRNG pool and the r's are PRNs

generated by

# the PRNG pool. Note that the f's are non-linear and that, in

obtaining the

# individual ciphertext blocks (the x's on the leftside of the

assignments)

# all blocks of the given message (some already processed, some not

yet) are

# involved, which clearly leads to a superior avalanche effect (compare

# however block-chaining that is commonly used in running the other known

# block ciphers).

#

# 3. For the purpose of authentication, we append a pseudo-random block

to the

# beginning of the given plaintext blocks such that it now takes the

position

# of x1 in the processing scheme sketched above. It is easily seen

that x1

# has strong influences on the results of all the other assignments. This

# implies, conversely, that any manipulation of the ciphertext blocks

will

# with very high probability be reflected in the changed value of x1

(with

# respect to the one on encryption) obtained on decryption, which

means that

# x1 can serve well as a MAC for authentication. (JADE-S actually

employs,

# as an enhancement, also an additional pseudo-random block at the

end of the

# given plaintext blocks for authentication and the user may further

specify

# that more than one such authentication blocks be used.)

# Contents of this document:

# Section 1: Python (http://www.python.org , Python 3.x) code of JADE-S with

# comments explaining the functionality of each function as well as the

# structuring of the entire program. Permissible values of system parameters

# and key materials are listed at the beginning of this section. Users

with some

# programming experience and basic knowledge of Python should be able to

read

# this section and understand how JADE-S exactly works without difficulties.

# Section 2: Some examples demonstrating how JADE-S can be actually

used for

# encryption/decryption as well as how Maurer's Universal Test can be

done for

# getting informations on the statistical quality of the results obtained.

# Section 3: Miscellaneous notes.

# Version 1.0, released on 24.06.2013.

# Version numbers and release dates do not reflect interim revisions of

comment

# lines. Code lines of documents with the same version number are

however always

# identical. The most recent document of JADE-S can be obtained from

# http://s13.zetaboards.com/Crypto/topic/7072208/1/#new

# This software may be freely used:

# 1. for all personal purposes unconditionally and

# 2. for all other purposes under the condition that its name, version

number

# and authorship are explicitly mentioned and that the author is

informed of

# all eventual code modifications done.

# The author is indebted to TPS for review and suggestions throughout

JADE-S's

# development phase. Any remaining deficiencies of the software are

however the

# sole responsibilty of the author.

# Concrete comments and constructive critiques are sincerely solicited

either

# via the above thread or directly via email.

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

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

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

######### Section 1. Python Code of JADE-S.

##### This section lists all functions defined in JADE-S. For each run

of JADE-S

##### the user has to provide the appropriate system parameters and key

##### materials and invoke initjades(). See Sec.2 for examples.

# Permissible values of system parameters and key materials (limits chosen

# based on practical considerations) are as follows (the first 5 parameters

# of the list and ciphertextfilemode are essential, the rest could be more

# or less arbitrarily chosen, their variability has albeit the

beneficial side

# effect of enhancing the the complexity facing the analyst):

# logn: log base 2 of the number of bits (n) in a block.

# 7 <= logn <= 10.

# baseprngm: Degree of polynomials + 1 of the PRNGs in baseprngpool.

# baseprngm >= prngm.

# logbasepoolsize: log base 2 of the size of baseprngpool.

# 7 <= logbasepoolsize <= 10

# prngm: Degree of polynomials + 1 of the PRNGs in prngpool.

# 3 <= prngm.

# logpoolsize: log base 2 of the size of prngpool.

# 7 <= logpoolsize <= 10

# maxprngusecount: Maxmal number of uses of a PRNG in prngpool to

generate PRNs

# before it is automatically renewed.

# 20 <= maxprngusecount

# initialrandompriming: Priming value of the PRNG geninitialrandom().

# 0 <= initialrandompriming.

# baserandompriming: Priming value of the PRNG genbaserandom().

# 0 <= baserandompriming.

# randompriming: Priming value of the PRNG genrandom().

# 0 <= randompriming.

# initvecblocknum: Number of authentication blocks at the begining of

# ciphertext.

# 1 <= initvecblocknum.

# finalvecblocknum: Number of authentication blocks at the end of

ciphertext.

# 0 <= finalvecblocknum.

# ciphertextfilemode: = 0: Outputfile is Python specific (not printable).

# = 1: Outputfile is in decimal integers (printable).

# = 2: Outputfile is in hexadecimal integers

(printable).

# keydata: A list of 2 elements of (maximal) n/2 bits each.

# Larger values given will be truncated mod 2

******n.

# seeddata: 1 element of (maximal) n/2 bits.

# Larger values given will be truncated mod 2

******n.

# Loading three system modules of Python.

import math,time,pickle

##### All pseudo-random number generators (PRNGs) of JADE-S are based on

##### permutation polynomials mod 2

******n. The user-given key materials are

used to

##### establish the ultimate PRNG genrandom() through a bootstrapping

process

##### via gennhrandom(), geninitialrandom() and genbaserandom().

##### The function fullperiodcriteria(), evalpermpoly(), invpermpoly() are

##### general functions required for computating with permutation

polynomials

##### mod 2

******n.

# Modify user-supplied coefficients of the polynomial poly so as to

satisfy the

# full-period criteria of a permutation polynomial mod 2

******n. The degree

of poly

# is required to be at least 2. m denotes the number of coefficients of the

# polynomial, i.e. degree of polynomial plus 1. For the criteria see

ref.[1],

# p.283.

# [1] V. Anashin, A. Khrennikov, Applied Algebraic Dynamics, Berlin, 2009.

# http://www.degruyter.com/view/supplement/9783110203011_Errata.pdf

# We use for simplification of coding a restricted form of the criteria,

namely:

# c

___0 = c___1 = 1 mod 4

# c_i = 0 mod 4 for all other i

def fullperiodcriteria(poly,m):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

if m<3:

print("Error in fullperiodcriteria")

exit(1)

gg=(tpwnm1<<2)&tpwnm1

permpoly=poly[:]

for i in range(2):

permpoly[i]=(permpoly[i]&gg)|1

for i in range(2,m):

permpoly[i]&=gg

return(permpoly)

# Evaluate permpoly with argument x with Horner's method.

def evalpermpoly(permpoly,m,x):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

y=permpoly[m-1]

for i in range(m-2,-1,-1):

y=(y*x+permpoly[i])&tpwnm1

return(y)

# Inverse of evalpermpoly(). First derivative of permpoly(x) = 1 mod 2.

Hensel's

# lifting lemma leads to the iteration: x

___(i+1)=x___i-g(x_i) mod 2

******(i+1),

with

# g(x)=permpoly(x)-y. See ref.[1], p.306.

def invpermpoly(permpoly,m,y):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

if (((permpoly[0]-y)&tpwnm1)&1)==0:

x=0

else:

x=1

for i in range(2,np1,1):

x=(x-(evalpermpoly(permpoly,m,x)-y))&tpwnm1

return(x)

##### The user-given key (a list of 2 elements of n/2 bits) and seed (1

element

##### of n/2 bits) are used to build a PRNG gennhrandom(), delivering

PRNs of

##### n/2 bits, with the help of nhcombine() and buildinitialgenerator().

##### Concatenating 2 successive outputs gennhrandom() forms then the

output of

##### n bits of the PRNG geninitialrandom(), which will be used in the next

##### higher level code of PRN generation.

# Combining two n/2 bit words with reciprocal rotation and xor.

def nhcombine(x,y):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

rotx=x>>shfnhrot

roty=y>>shfnhrot

rx=((x<<roty)&tpwnhm1)|(x>>(nh-roty))

ry=((y<<rotx)&tpwnhm1)|(y>>(nh-rotx))

r=rx^ry

return(r)

# Build a linear congruential PRNG mod 2

******(n/2), gennhrandom(), from the

# user-given keydata and seeddata.

# Full period criteria: c0 = 1 mod 2, c1 = 1 mod 4, see ref.[1].

def buildinitialgenerator():

global keylen,keydata,seeddata,key,seed,basekeylen

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

key=keydata

seed=seeddata

if (len(key)!=2):

print("Error in buildinitialgeneator")

exit(2)

gg=(tpwnhm1<<2)&tpwnhm1

key[0]=(key[0]&tpwnhm1)|0x1

key[1]=((key[1]&tpwnhm1)&gg)|0x1

seed=seed&tpwnhm1

# Combine two outputs of the linear PRNG established in

buildinitialgenerator()

# with nhcombine() to obtain one output of n/2 bits of gennhrandom().

Function

# returns a list of veclen elements.

def gennhrandom(veclen):

global keylen,keydata,seeddata,key,seed,basekeylen

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

nhrandom=[]

for i in range(veclen):

r1=seed=(key[0]+key[1]*seed)&tpwnhm1

r2=seed=(key[0]+key[1]*seed)&tpwnhm1

nhrandom+=[nhcombine(r1,r2)]

return(nhrandom)

# Concatenate two outputs from gennhrandom() to be one of n bits. Function

# returns a list of veclen elements.

def geninitialrandom(veclen):

global logn,n,np1,nm1,nh,chnum

global keylen,keydata,seeddata,key,seed,basekeylen

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

random=[]

for i in range(veclen):

r=gennhrandom(2)

random+=[(r[0]<<nh)|r[1]]

return(random)

##### Outputs of geninitialrandom() are used to build a pool of PRNGs

based on

##### permutation polynomials mod 2

******n of degree baseprngm-1, designated as

##### baseprngpool, with the help of ncombine() and

buildbasegeneratorpool().

##### genbaserandom() then delivers PRNs from this pool, which will be

used for

##### the next higher level code of PRN generation.

# Combining two n bit words with reciprocal rotation and xor.

def ncombine(x,y):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

rotx=x>>shfnrot

roty=y>>shfnrot

rx=((x<<roty)&tpwnm1)|(x>>(n-roty))

ry=((y<<rotx)&tpwnm1)|(y>>(n-rotx))

r=rx^ry

return(r)

# Use geninitialrandom() to build a PRNG (consisting of two internal

PRNGs of

# degree baseprngm-1, with keys gbasekey1 and gbasekey2 and seeds

gbaseseed1 and

# gbaseseed2) to build a pool of PRNGs of degree baseprngm-1, designated as

# baseprngpool.

def buildbasegeneratorpool():

global baseprngm,logbasepoolsize,basepoolsize,baseprngpool,baseprngseed

global basebuffer,basebufpt

global baseprn,baseindex,baseprngsum,shfbaseindex,shfbasebegin

global initialrandompriming,baserandompriming,randompriming

buildinitialgenerator()

# Priming of geninitialrandom().

geninitialrandom(initialrandompriming)

rr1=geninitialrandom(baseprngm+1)

gbasekey1=rr1[:-1]

gbaseseed1=rr1[-1]

rr2=geninitialrandom(baseprngm+1)

gbasekey2=rr2[:-1]

gbaseseed2=rr2[-1]

gbasekey1=fullperiodcriteria(gbasekey1,baseprngm)

gbasekey2=fullperiodcriteria(gbasekey2,baseprngm)

baseprngpool=[]

baseprngseed=[]

basebuffer=[]

for i in range(basepoolsize):

randtmp=[]

for j in range(baseprngm+2):

r1=gbaseseed1=evalpermpoly(gbasekey1,baseprngm,gbaseseed1)

r2=gbaseseed2=evalpermpoly(gbasekey2,baseprngm,gbaseseed2)

randtmp+=[ncombine(r1,r2)]

permpoly=fullperiodcriteria(randtmp[:-2],prngm)

baseprngpool+=[permpoly]

baseprngseed+=[randtmp[-2]]

basebuffer+=[randtmp[-1]]

basebufpt=0

baseprn=0

baseindex=0

baseprngsum=0

# Generate a sequence of PRNs (a list of veclen elements) from the

baseprngpool.

# The consituent PRNG in the pool currently indexed by baseindex is

activated

# and outputs baseprn. baseprn is summed into an accumulator

(baseprngsum) and

# the sums are passed through a buffer (basebuffer) to result in the

elements

# of the desired sequence. The pseudo-radnom nature of the activation of the

# constituent PRNGs in the pool, together with the post-processing of their

# outputs, which introduces indeterminancies for the analysis, effectively

# thwart the analyst's sequence prediction attempts. For, given an

output value

# from this function, he is blocked all along the path that would lead

backwards

# to the one particular constituent PRNG that mainly contributed to that

value.

# Note also that there are moreover no statistical biases in the output

# sequences of JADE-S's genbaserandom() (this applies also to

genrandom() of the

# next higher final level of PRN generation further below) to be

exploited in

# practice, as test results with Maurer's Universal Test have shown.

(Decades

# ago someone published a PRN generation scheme in a journal of

statistics where

# a number of PRNGs are activated in a round-robin fashion in order to

obtain

# better statistical properties. The present author later independently

proposed

# in Internet forums to use a similar scheme where the activation of the

# consituent PRNGs is albeit not in a fixed serial order but pseudo-random,

# which is apparently to be preferred for crypto security purposes.)

Note that

# below both baseindex and basebufpt are obtained from bits of the

accumulator

# baseprngsum, which is pseudo-random. For the use of buffers, cf.

Algorithm B

# in ref.[2], p.34.

# [2] D. E. Knuth, The Art of Computer Programming, vol. 2, 3rd ed.,

Reading,

# 1998.

def genbaserandom(veclen):

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

global baseprngm,logbasepoolsize,basepoolsize,baseprngpool,baseprngseed

global basebuffer,basebufpt

global baseprn,baseindex,baseprngsum,shfbaseindex,shfbasebegin

random=[]

for i in range(veclen):

k=baseprngsum>>shfbasebegin

basebufpt=k&logbasepoolsize

baseindex=(k>>logbasepoolsize)

baseprn=baseprngseed[baseindex]\

=evalpermpoly(baseprngpool[baseindex],baseprngm,\

baseprngseed[baseindex])

baseprngsum=(baseprngsum+baseprn)&tpwnm1

basebf=basebuffer[basebufpt]

basebuffer[basebufpt]=basebf

random+=[basebf]

return(random)

##### Outputs of genbaserandom() are used to build a pool of PRNGs based on

##### permutation polynomials mod 2

******n of degree prngm-1, designated as

##### prngpool, with the help of buildgeneratorpool(). genrandom() then

delivers

##### outputs from this pool, which will be used for the proper

##### encryption/decryption processing of JADE-S.

# Use genbaserandom() to build a pool of PRNGs, designated as prngpool.

def buildgeneratorpool():

global logn,n,np1,nm1,nh,chnum

global prngm,logpoolsize,poolsize,maskpool

global prngpool,prngseed,prngusecount,maxprngusecount

global prn,index,shfindex,shfbegin,prngfeedback

global initialrandompriming,baserandompriming,randompriming

global prngsum,buf1sum,buffer1,buffer2,buf1pt,buf2pt

buildbasegeneratorpool()

# Priming of genbaserandom().

genbaserandom(baserandompriming)

prngpool=[]

prngseed=[]

prngusecount=[]

buffer1=[]

buffer2=[]

for i in range(poolsize):

randtmp=genbaserandom(prngm+3)

permpoly=fullperiodcriteria(randtmp[:-3],prngm)

prngpool+=[permpoly]

prngseed+=[randtmp[-3]]

buffer1+=[randtmp[-2]]

buffer2+=[randtmp[-1]]

prngusecount+=[0]

prn=0

index=0

buf1pt=buf2pt=0

prngsum=buf1sum=0

prngfeedback=0

# Renew the PRNG in the prngpool currently indexed by index using

# genbaserandom(). This function is called by genrandom().

def renewal():

global prngm,logpoolsize,poolsize,maskpool

global prngpool,prngseed,prngusecount,maxprngusecount

global prn,index,shfindex,shfbegin,prngfeedback

randtmp=genbaserandom(prngm)

prngpool[index]=fullperiodcriteria(randtmp,prngm)

# Generate a sequence of PRNs (a list of veclen elements) from the prngpool,

# similar to genbaserandom() but employing two summations (prngsum and

buf1sum)

# and two buffers (buffer1 and buffer2). If prngfeedback is 1, index is

reset

# to a pseudo-random new value. If the usecount of the PRNG at index exceeds

# maxprngusecount, it is renewed with renewal(). User may employ

genrandom(),

# after calling initjades(), to generate PRNs for use in applications

# independent of JADE-S's encryption/decryption. In such cases benefits of

# dynamics/variability could be obtained via appropriate use of the variable

# prngfeedback and the function renewal().

def genrandom(veclen):

global prngm,logpoolsize,poolsize,maskpool

global prngpool,prngseed,prngusecount,maxprngusecount

global prn,index,shfindex,shfbegin,prngfeedback

global prngsum,buf1sum,buffer1,buffer2,buf1pt,buf2pt

random=[]

for i in range(veclen):

k=prngsum>>shfbegin

buf2pt=k&maskpool

k>>=logpoolsize

buf1pt=k&maskpool

if prngfeedback==1:

# index arbitrarily determined by rightmost logn bits of prngsum.

index=prngsum&maskpool

prngfeedback=0

else:

index=(k>>logpoolsize)

if prngusecount[index]>=maxprngusecount:

renewal()

prngusecount[index]=1

else:

prngusecount[index]+=1

prn=prngseed[index]\

=evalpermpoly(prngpool[index],prngm,prngseed[index])

prngsum=(prngsum+prn)&tpwnm1

bf1=buffer1[buf1pt]

buffer1[buf1pt]=prngsum

buf1sum=(buf1sum+bf1)&tpwnm1

bf2=buffer2[buf2pt]

buffer2[buf2pt]=buf1sum

random+=[bf2]

return(random)

##### The user has to initialize the system with initjades() for each run of

##### JADE-S.

# Check the user-given system parameters for conformance to constraints

given

# further above and compute the corresponding values of all system variables

# required for running JADE-S.

def initjades():

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

global baseprngm,logbasepoolsize,basepoolsize,baseprngpool,baseprngseed

global baseprn,baseindex,baseprngsum,shfbaseindex,shfbasebegin

global initialrandompriming,baserandompriming,randompriming

global prngm,logpoolsize,poolsize,maskpool

global prngpool,prngseed,prngusecount,maxprngusecount

global prn,index,shfindex,shfbegin,prngfeedback

global initvecblocknum,finalvecblocknum,initvector,finalvector

global ciphertextfilemode,formatstr,digitnum,hexnum,base,fileext

global shfchoice

if logn<7 or logn>10 or baseprngm<prngm or logbasepoolsize<7 or\

logbasepoolsize>10 or prngm<3 or logpoolsize<7 or logpoolsize>10 or\

maxprngusecount<20 or initialrandompriming<0 or

baserandompriming<0 or\

randompriming<0 or initvecblocknum<1 or finalvecblocknum<0 or\

ciphertextfilemode<0 or ciphertextfilemode>2:

print("Error in initjades")

exit(3)

n=2

******logn

np1=n+1

nm1=n-1

tpwn=2

******n

tpwnm1=tpwn-1

shfnrot=n-logn

nh=n//2

tpwnh=2

******nh

tpwnhm1=tpwnh-1

shfnhrot=nh-(logn-1)

basepoolsize=2

******logbasepoolsize

shfbaseindex=n-logbasepoolsize

shfbasebegin=n-(2*logbasepoolsize)

poolsize=2

******logpoolsize

shfindex=n-logpoolsize

shfbegin=n-(3*logpoolsize)

maskpool=poolsize-1

shfchoice=shfindex-1

chnum=n//8

buildgeneratorpool()

# System priming of genrandom(), value arbitrarily determined.

genrandom(3*poolsize)

# User priming of genrandom().

genrandom(randompriming)

# Initialize initvector and finalvector with some arbitrary pseudo-random

# values.

initvector=genrandom(initvecblocknum)

finalvector=genrandom(finalvecblocknum)

if ciphertextfilemode==0:

formatstr=""

fileext=".bin"

elif ciphertextfilemode==1:

digitnum=int(math.log(tpwnm1,10))

if 10

******digitnum<tpwnm1:

digitnum+=1

formatstr=""

base=10

fileext=".txt"

else:

hexnum=2*chnum

formatstr=""

base=16

fileext=".txt"

##### The following functions do the proper work of

encryption/decryption using

##### the PRNG genrandom() developed above.

##### enc() and dec() are basic functions that will be used in the

higher level

##### functions encrypt() and decrypt().

##### Filler of user-given plaintext to block boundary is 'z'.

# The elements in nplist are integer values that result from byte-wise

encoding

# of plaintext characters in a block (of chnum characters). We compute

for the

# elements x1, x2, ... xk of the list the following, where the f's are

# invertible non-linear functions, the r's are pseudo-random numbers and the

# assignments are performed sequentially:

# x1 := f1(x1 + x2 ... + xk ^ r1)

# x2 := f2(x1 + x2 ... + xk ^ r2)

# ................

# xk := fk(x1 + x2 ... + xk ^ rk)

# (The scheme, suggested for block encryption processing by the present

author

# recently in a few Internet forums ,is inspired by the iterative

solution of

# systems of linear equations as given in V. N. Faddeeva, Computational

Methods

# of Linear Algebra, p.117, Dover Publ., 1959.) The f's are pseudo-randomly

# selected from the pool of permutation polynomials mod 2

******n on which

# genrandom() is based and the r's are obtained from genrandom(). We

employ for

# an f either evalpermpoly() or invpermpoly() depending on the pseudo-random

# value choice. This renders the processing time of encryption and

decryption

# equal, since the inverse computation takes more time. Note that the

# block-chaining effect in the use of the other known common block

ciphers is

# intrinsically present in our scheme, as in every step all blocks are

(equally)

# involved in the argument of f, with the consequence that a far

superior mixing

# together and hence degree of interdependence of all blocks involved during

# processing is achieved. For the purpose of authentication, we append a

# pseudo-random block to the beginning of the sequence of given

plaintext blocks

# such that it now takes the position of x1 in the processing scheme

sketched

# above. It is easily seen that x1 has strong influences on the results

of all

# the other assignments. This implies, conversely, that any manipulation

of the

# ciphertext blocks will with very high probability be reflected in the

changed

# value of x1 (with respect to the one on encryption) obtained on

decryption,

# which means that x1 can serve well as a MAC for authentication. JADE-S

# actually employs, as an enhancement, also an additional pseudo-random

block at

# the end of the given plaintext blocks for authentication and the user may

# further specify that more than one such authentication blocks be used.

See the

# system parameters initvecblocknum and finalvecblocknum. Note that after

# execution of enc() nclist is also available globally (in particular, the

# encrypted finalvector can be obtained with nclist[-finalvecblocknum:]

for use

# as a kind of hash value).

def enc(nplist):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

global prngm,logpoolsize,poolsize,maskpool

global prngpool,prngseed,prngusecount,maxprngusecount

global prn,index,shfindex,shfbegin,prngfeedback

global shfchoice

global nclist

nclist=nplist[:]

lenlist=len(nclist)

choice=[]

polyindex=[]

random1=genrandom(lenlist)

# random2 provides the PRNs in the scheme sketched above.

random2=genrandom(lenlist)

for i in range(lenlist):

# Leading bits of random1 provide polyindex and choice.

k=random1[i]>>shfchoice

choice+=[k&1]

polyindex+=[k>>1]

sigmax=0

for i in range(lenlist):

sigmax+=nclist[i]

sigmax=sigmax&tpwnm1

for i in range(lenlist):

if choice[i]==0:

tt=evalpermpoly(prngpool[polyindex[i]],prngm,sigmax^random2[i])

else:

tt=invpermpoly(prngpool[polyindex[i]],prngm,sigmax^random2[i])

sigmax=(sigmax-nclist[i]+tt)&tpwnm1

nclist[i]=tt

return(nclist)

# Inverse of enc().

def dec(nclist):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

global prngm,logpoolsize,poolsize,maskpool

global prngpool,prngseed,prngusecount,maxprngusecount

global prn,index,shfindex,shfbegin,prngfeedback

global shfchoice

nplist=nclist[:]

lenlist=len(nclist)

choice=[]

polyindex=[]

random1=genrandom(lenlist)

random2=genrandom(lenlist)

for i in range(lenlist):

k=random1[i]>>shfchoice

choice+=[k&1]

polyindex+=[k>>1]

sigmax=0

for i in range(lenlist):

sigmax+=nplist[i]

sigmax=sigmax&tpwnm1

for i in range(lenlist-1,-1,-1):

if choice[i]==0:

tt=invpermpoly(prngpool[polyindex[i]],prngm,nplist[i])

else:

tt=evalpermpoly(prngpool[polyindex[i]],prngm,nplist[i])

vv=(sigmax-nplist[i])&tpwnm1

nplist[i]=((tt^random2[i])-vv)&tpwnm1

sigmax=(vv+nplist[i])&tpwnm1

return(nplist)

##### pack() and unpack() are auxiliary functions needed in encrypt() and

##### decrpyt().

# Convert a string s to a binary integer representation.

def pack(s):

b=s.encode('latin1')

k=0

for i in range(len(b)):

k<<=8

k|=b[i]

return(k)

# The inverse of pack(). blen is the length of the original string that was

# previously processed by pack().

def unpack(k,blen):

b=bytearray(blen)

for i in range(blen-1,-1,-1):

b[i]=k&0xff

k>>=8

s=b.decode('latin1')

return(s)

##### encrypt() encrpyts the user-given plaintext and writes the

ciphertext into

##### a file with name ciphertextname and file extension bin/txt

according to

##### ciphetextfilemode=0/1/2, i.e. whether the file is to be in Python

specific

##### format or consisting of a list of decimal or hexadecimal integers.

##### decrpyt() decrypts a file thus obtained back into the plaintext.

# If the length of the plaintext string is not a multiple of block

length (chnum

# characters), a filling with the character 'z' is done. Divide the

plaintext

# string into a number of blocks. Each block is then converted into one

integer

# by pack(), resulting thus in a list of integers, nplist. The PRN

initvector

# and finalvector, generated in initjades(), are appended to the

beginning and

# and end of nplist respectively for purpose of authentication in decrypt().

# nplist is encrypted with enc() to nclist and is written to ciphertextfile

# according to the system parameter ciphertextfilemode. (If the plaintext is

# given in an external file, see comments in Ex.1 of Sec.2 on how to

read it in

# for processing.)

def encrypt(plaintext,ciphertextname):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

global initvecblocknum,finalvecblocknum,initvector,finalvector

global ciphertextfilemode,formatstr,digitnum,hexnum,base,fileext

print("Processing string plaintext")

k=len(plaintext)%chnum

if k!=0:

for i in range(chnum-k):

plaintext+="z"

print("Plaintext is extended at end with",chnum-k,"'z' "\

"for satisfying processing requirement")

k=0

nplist=[]

for i in range(len(plaintext)//chnum):

nplist+=[pack(plaintext[k:k+chnum])]

k+=chnum

# Append initvector and finalvector.

nplist=initvector+nplist+finalvector

lenlist=len(nplist)

# Encryption processing with the function enc().

nclist=enc(nplist)

# Output to ciphertextfile.

ciphertextfile=ciphertextname+fileext

if ciphertextfilemode==0:

fp=open(ciphertextfile,"wb")

pickle.dump(nclist,fp)

print("File is not printable and has to be sent as such")

else:

fp=open(ciphertextfile,"w")

for i in range(lenlist):

fp.write(formatstr.format(nclist[i])+"\n")

if ciphertextfilemode==1:

print("File consists of",lenlist,"integers (maximum size for each",\

"integer:",digitnum,"digits)")

else:

print("File consists of",lenlist,"integers (maximum size for each",\

"integer:",hexnum,"hexadecimal\ndigits with prefix '0x')")

fp.close()

print("Ciphertext has been written to file:",ciphertextfile)

print()

# Inverse of encrypt(). If the first initvecblocknum and last

finalvecblocknum

# elements of nplist obtained are identical to initvector and finalvector

# respectively, the authentication (integrity check) is ok. An integer to

# characters conversion is then done with unpack(). The recovered plaintext

# string is returned. Note that this may contain filling characters 'z'

added

# by encrypt(). (If the plaintext is to be written out to an external

file, see

# comments in Ex.1 of Sec. 2 on how to do that.)

def decrypt(ciphertextname):

global logn,n,np1,nm1,nh,chnum

global tpwn,tpwnm1,shfnrot,tpwnh,tpwnhm1,shfnhrot

global initvecblocknum,finalvecblocknum,initvector,finalvector

global ciphertextfilemode,formatstr,digitnum,hexnum,base,fileext

ciphertextfile=ciphertextname+fileext

print("Processing file",ciphertextfile)

if ciphertextfilemode==0:

fp=open(ciphertextfile,"rb")

nclist=pickle.load(fp)

else:

fp=open(ciphertextfile,"r")

ncliststrlist=fp.read().split()

nclist=[]

for i in range(len(ncliststrlist)):

nclist+=[int(ncliststrlist[i],base)]

fp.close()

lenlist=len(nclist)

# Decryption processing with the function dec().

nplist=dec(nclist)

# Check whether initvector and finalvecter are correctly recovered and

# exclude them from nplist.

authen1=nplist[:initvecblocknum]

if finalvecblocknum>0:

authen2=nplist[-finalvecblocknum:]

nplist=nplist[initvecblocknum:-finalvecblocknum]

else:

authen2=[]

nplist=nplist[initvecblocknum:]

if authen1!=initvector or authen2!=finalvector:

print("######### Authentication (intgegrity check) failed #########")

exit(5)

plaintextrecovered=""

for i in range(len(nplist)):

plaintextrecovered+=unpack(nplist[i],chnum)

print("Plaintext has been recoverd from",ciphertextfile)

print("Authentication (integrity check) ok")

print()

return(plaintextrecovered)

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

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

######### Section 2. Examples of Applications of JADE-S.

##### The following code does not belong to JADE-S in the proper sense

but serves

##### only to illustrate with examples further below how the user may apply

##### JADE-S.

# Maurer's Universal Test, see [3].

# [3] J-S. Coron, D. Naccache, An Accurate Evaluation of Maurer's

Universal Test.

# http://www.jscoron.fr/publications/universal.pdf

qq=2560

qqp1=qq+1

kk=256000

qqkkp1=qq+kk+1

def maurertest(bb):

global qq,qqp1,kk,qqkkp1

eftu=7.1836656

# y1 and y2 are for rho=0.01 and rho=0.001 respectively.

y1=2.5758

y2=3.2905

t=[0 for i in range(256)]

for i in range(1,qqp1,1):

t[bb[i]]=i

sum=0.0

for i in range(qqp1,qqkkp1,1):

sum+=math.log10(i-t[bb[i]])

t[bb[i]]=i

tu=(sum/kk)/math.log10(2.0)

c=math.sqrt(0.3732189+(0.3730195*256)/kk)

sigma=c*math.sqrt(3.2386622/kk)

t11=eftu-y1*sigma

t12=eftu+y1*sigma

t21=eftu-y2*sigma

t22=eftu+y2*sigma

return(tu,t11,t12,t21,t22)

def maurertestresult(h,gg):

global logn,n,np1,nm1,nh,chnum

global qq,qqp1,kk,qqkkp1

if h*chnum<qqkkp1:

print("Error in maurertestresult")

exit(6)

bb=[0 for k in range(h*chnum)]

u=0

k1=-1

k2=chnum-1

for i in range(h):

g=gg[i]

for k in range(k2,k1,-1):

bb[u]=g&0xff

g>>=8

u+=1

k1+=chnum

k2+=chnum

tu,t11,t12,t21,t22 = maurertest(bb)

print("Maurer's Universal Test for L=8, rho=0.01 (Middle value is the "\

"test statistic\nand should lie between the other two values):")

print(t11,tu,t12)

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

# User specified system parameters and key materials are assumed to be the

# following for the examples below:

logn=8

baseprngm=4

logbasepoolsize=7

prngm=3

logpoolsize=8

maxprngusecount=50

initialrandompriming=10

baserandompriming=20

randompriming=50

initvecblocknum=1

finalvecblocknum=1

ciphertextfilemode=0

# keydata is a list of 2 elements of n/2 bits, seeddata 1 element of n/2

bits

# (here they are arbitrary apparently 'non-random' values chosen for the

# convenience of illustration only).

keydata=[ 0x11111111111111111111111111111111,\

0x22222222222222222222222222222222 ]

seeddata= 0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

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

# Example 1. Normal encryption and decryption.

print()

print("Example 1:")

print()

print("Normal encryption and decryption")

print()

# We assume the sender has the following character string pt as plaintext:

pt="Was sich ueberhaupt sagen laesst, laesst sich klar sagen; und "\

"wovon man\nnicht reden kann, darueber muss man schweigen."

print("Original plaintext:")

print(pt)

print()

# The sender intializes the system,

initjades()

# encrypts pt, obtaining a ciphertext file ciphermessage.bin

(ciphertextfilemode

# is chosen above to be 0, thus the file cannot be printed and has to be

sent as

# such to the recipient.)

encrypt(pt,"ciphermessage")

# and sends it to the recipient.

# The recipient initializes the system,

initjades()

# decrypts the received ciphertextfile ciphermessage.bin

(ciphertextfilemode is

# 0 as chosen by the sender), assigns the result to pt1 and prints it out.

# Result of authentication check will be automatically reported.

pt1=decrypt("ciphermessage")

print("Plaintext recovered:")

print(pt1)

# If the plaintext message to be encrypted is in an external file (last line

# preferably without 'return'), it can be read into pt with:

# f=open("messagetobesent.txt","r"))

# pt=f.read()

# f.close()

# Similarly the received plaintext message (after decryption is

performed) can

# be stored into an external file from pt1 with:

# f=open("messagereceived.txt","w")

# f.write(pt1)

# f.close()

# Example 2: Measuring time of encryption/decryption.

print()

print("Example 2:")

print()

nnumb=10000

pt=""

for i in range(nnumb):

pt+="a"

print("Measuring time of encryption/decryption of a message of",nnumb,\

"characters")

print()

start=time.clock()

initjades()

encrypt(pt,"ciphertext")

print("encrypt time:",time.clock()-start,"sec")

start=time.clock()

initjades()

pt1=decrypt("ciphertext")

print("decrypt time:",time.clock()-start,"sec")

# Example 3. Perform Maurer's Universal Test on genrandom().

# User may like to employ JADE-S's function genrandom() for other

usages, e.g.

# for common numerical computations or obtaining PRNs (eventually in

combination

# with other sources) to generate key streams for other encryption

schemes, and

# may want to know their statistical properties. Hence the present example.

print()

print("Example 3:")

print()

# Note that theoretically there is a 0.01 chance for the test statistic

tu to go

# outside of the interval [t11, t12] (under the assumption that the sequence

# being tested is random).

print("Testing pseudo-radnom numbers generated by genrandom()")

print()

# Initialize the system.

initjades()

# Determine number of PRNs (words) needed for the test.

h=qqkkp1//chnum

if h*chnum<qqkkp1:

h+=1

# Obtain the PRNs.

gg=genrandom(h)

#Perform the test.

maurertestresult(h,gg)

# Example 4. Perform Maurer's Universal Test on ciphertext obtained from

# a plaintext of the form "aaa........".

# This is intended to show the randomness of the result of encrypting an

# absolutely non-random plaintext. (A perfectly random plaintext on the

other

# hand would have had the same frequency, 1/26, of occurence for all

characters

# of the alphabet.)

print()

print("Example 4:")

print()

print("Testing the result of encrypting an absolutely non-random plaintext")

print()

# Since ciphertext in decimal integers will be needed, we have to reset the

# parameter ciphertextfilemode to 1 (it was chosen above to be 0).

ciphertextfilemode=1

# Initialize the system.

initjades()

# Determine number of words of the form "aaa..." needed for the test.

h=qqkkp1//chnum

if h*chnum<qqkkp1:

h+=1

# Obtain the plaintext.

r=""

for i in range(chnum):

r+="a"

pt=""

for i in range(h):

pt+=r

# Perform encryption.

encrypt(pt,"aaamessage")

# Obtain the corresponding ciphertext (decimal integers in nclist).

ciphertextfile="aaamessage.txt"

fp=open(ciphertextfile,"r")

ncliststrlist=fp.read().split()

nclist=[]

for i in range(len(ncliststrlist)):

nclist+=[int(ncliststrlist[i])]

# Perform the test.

maurertestresult(h,nclist)

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

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

######### Section 3. Miscellaneous Notes.

# The code of JADE-S assumes that the sender supplies his message in a

variable

# of Python and the recipient retrieves the same also from a variable of

Python.

# See commments in Sec.2. Ex.1 for situations where the sender has his

message

# in a file or the recepient needs to obtain the same in a file.

# In case arbitrary binary information is to be processed, this may be

supplied

# in n-bit blocks as elements of the list nplist to be encrypted to the list

# nclist by JADE-S. The code modification necessary for this is evident, see

# encrypt() and decrypt().

# Users employing non-English keyboards may obtain with input of non-English

# symbols a message from Python: "... IDLE will convert it to UTF-8".

Click on

# OK in this case. Though not tested, there seems to be no reason why JADE-S

# shouldn't work also with non-European languages. Note that JADE-S

needs Python

# 3.x.

# To obtain a binary file of m PRNs generated by genrandom() one could use:

# initjades()

# g=genrandom(m)

# fp=open("mfile.bin","wb")

# for i in range(m):

# fp.write(g[i].to_bytes(chnum,byteorder='big'))

# fp.close()

# For a chosen block size of n bits, the key material (keydata and

seeddata) has

# a total size 1.5*n bits. However, if keydata (of n bits) has enough

entropy to

# defeat brute-forcing, then seeddata evidently need not necessarily be

secret.

# (That for the larger values of n allowed in JADE-S the key material

generally

# needs only a correspondingly lower entropy density is clearly of

advantage in

# practice.) In fact it could be favourable in practice for the key

management

# work to have a well-guarded keydata of sufficient entropy and use it

for some

# longer time period, while the seeddata is always variable accross the

sessions

# and depends in some rather simple way on certain session specific data,

# including date, time, message serial number, etc. One could use JADE-S

and a

# master-keydata (with the corresponding seeddata e.g. involving a certain

# month, if the keydata to be used in that month is to be obtained) to

process

# an agreed upon text and use the value of nclist[-finalvecblocknum:]

(see enc()

# with the system parameter finalvecblocknum set to the desired length)

after

# execution of encrypt() to supply the keydata needed, since it is by

nature a

# good hash value of the plaintext for fixed values of system parameters and

# key materials employed. Further there could be a hierarchy of

master-keydata,

# depending on usage, validity time, etc. and stemming all from a grand

# master-keydata in the way described. A master-keydata could be

obtained by our

# targeted users, if necessary, through throwing 8-sided dice, this

being only a

# one-time drudgery, and exchanged with the communication partners via

# steganography, employing the present author's EMAILSTEGANO (available from

# http://s13.zetaboards.com/Crypto/topic/6939954/1 /). (With 6-sided dice one

# could get 2 bits from [1,4] and 1 bit from [5,6].) For gathering

entropy from

# hardware, see

https://www.irisa.fr/caps/projects/hipsor/old/files/HAVEGE.pdf

# Evidently there can exist no single general recipe of best performing key

# management that is applicable in all different concrete situations in

# practice and the user must exercise his own prudence, vigilence and

ingenuity.

# JADE-S treats the bits of an entire block of e.g. 256 bits as a single

integer

# and directly performs certain arithmetic and bit operations on it. See

enc()

# and dec(). This incurs essential trade-offs in terms of efficiency.

Further,

# Python code is not compiled but interpreted and in the present coding

priority

# has always been given to readability rather than to runtime efficiency.

# Benchmarking shows nevertheless that a message of 10000 characters,

which is

# sufficiently long for normal communications of common private persons

(who are

# our targeted users), can be processed on a common modern PC (with all

variants

# of the system parameters logn and logpoolsize) in less than 0.5 sec.,

which is

# clearly acceptable.

# JADE-S uses a scheme of PRN generation that distinguishes itself from the

# common schemes in that it makes use not of a single PRNG but of a pool of

# constituent PRNGs that are pseudo-randomly selected (by themselves) for

# activation, thus rendering its analysis inherently hard. The outputs

of these

# constituent PRNGs are post-processed in a sophisticated way to further

block

# any sequence prediction attempts of the analyist, see genrandom().

genrandom()

# accepts feedback signals so that functions employing it could through

feedback

# (via setting the global variable prngfeedback) dynamically influence the

# sequence of PRNs obtained and thus indirectly achieve dynamics in the

results

# computed by the functions. (JADE-S doesn't make use of prngfeedback,

though.)

# Use-counts are kept so that one can limit the life-time of the PRNGs

in the

# pool to deliberately enhance the hardness of analysis. Note also that in

# JADE-S all PRNs are only indirectly used so that these are never directly

# accessible to the analyst to work on. (Contrast this with the common

stream

# encryption).

# The present author experimentally found that the use of an accumulator

# improves the statistical qualities of the output of the PRNGs of the

type used

# in JADE-S. The combination of an accumulator and a buffer (which is also

# beneficial statistically) has the additional effect of rendering the

analysis

# hard. See genbaserandom() and genrandom(). In genrandom(), which

ultimately

# delivers the PRNs for application use, a cascade of an accumulator and two

# buffers is employed for achieving superior performance.

# JADE-S is very richly parametrized, in particular the user can choose

block

# lengths ranging from 128 to 1024 bits. Check for authentication

(integrity) is

# natively integrated and always performed, with the number of

authentication

# blocks arbitrarily specifiable by the user. While the common block ciphers

# have a number of rounds in order to attain their desired strength,

JADE-S has

# only one round, iterations of our kind of computations (see enc()) being

# considered superfluous for gaining security.

# JADE-S shares with JADE 2.0.3 the same elaborate PRN generation scheme

but is

# simpler in design concepts in the proper encryption/decryption processing

# part. It is thus easier to be understood and consequently to be preferred.

# It is important to be always conscious of the fact that in general a

cipher is

# only one component in the entire chain of computer processing that is

# destined/meant to protect user's privacy and that unfortunately a chain is

# only as strong as its weakest link. In fact IT security risks are

omnipresent.

# Thus, depending on the actual environment, one may have to consider

also, for

# instance, human factors and potential backdoors in proprietary

# (non-opensource, blackbox) software that are involved in the

management and

# processing of digital signatures, sophisticated malware (e.g. Stuxnet and

# its descendents, trojans introduced by governmental agencies) that steal

# plaintext files, WLAN insecurities, key loggers, Tempest attacks, etc.

etc.

# The book Security Engineering of R. Anderson covers a lot of practical IT

# security issues. There is, among others, an entire chapter on emission

# security.

# Note that backdoors (in both software and hardware) implanted by mafias or

# foreign secret agencies may remain dormant (thus undectable from the

outside)

# until the moment arrives that is favourable for the bad guys to create a

# devasticating chaos (via either "time-bomb" or, more sophistically, remote

# commands) to e.g. the critical infrastructures of a nation. In his book

# Cyberwar (in German, ISBN 978-3-941841-23-9) S. Gayken convincingly

argues for

# "Entnetzung" ("de-networking") as a necessary defense measure for

protecting

# the computer networks of sensible critical systems. (He also writes:

# "Commercially produced components cannot be trusted. Especially not,

if that's

# from global enterprises or firms from abroad".) By simple logic, if

one's home

# network is "really" to be well protected, then the same rigorous measure

# certainly should be taken. That would imply in our understanding

having one

# extra computer that is permanently isolated from the Internet and

transferring

# data to and from it via printouts/scanning (since USB devices are

presumably

# hard to to be protected from malware infections) and taking care of

risks from

# eventually conceivable emission attacks from the environment as well.

# That information privacy needs active and careful protection measures

is once

# again stressed by recent news from The Guardian about Prism, Tempora, etc.

# Another encryption software of the present author is SHUFFLE2,

obtainable from

# http://s13.zetaboards.com/Crypto/topic/6925232/1/

#### Site Timeline

- » Remailers and similar systems are not secure
- — Next thread in » General Computer Security

- » A block encryption processing idea taken from linear algebra
- — Previous thread in » General Computer Security

- » Special Offers
- — Newest thread in » General Computer Security

- » Dell Battery Slice LED codes
- — The site's Newest Thread. Posted in » Laptop Computers Forum