Date: Jul 23, 2013 2:36 PM Author: Mok-Kong Shen Subject: NEOCLASSIC, An encryption scheme based largely on use of well-known<br> classical crypto techniques

Attached below is the code of my encryption software NEOCLASSIC

Version 1.1.1. For comments and critiques I should be very grateful.

Currently there is a challenge competition for it with a prize to

be won, see:

http://s13.zetaboards.com/Crypto/topic/7078836/1/

M. K. Shen

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

# NEOCLASSIC, A simple versatile encryption scheme (with authentication)

based

# largely on the straightforward use of well-known classical crypto

techniques.

# Prologue:

# Having during the years designed a small number of encryption

algorithms, I

# am increasingly convinced that no practical encryption algorithm could be

# "absolutely" secure in the "strict" sense of the word and hence the

quest for

# such is futile from the very beginning. In fact, there exist rather strong

# critiques [1] on the so-called proofs of crypto-security. Thus what

seems to

# be desirable in practice will be the availability of a sufficiently large

# number of diverse kinds of sufficiently strong (preferably also easy for

# the common users to understand, verify and use) encryption algorithms

that,

# when appropriately employed (eventually in combinations, i.e. with

different

# ciphers working in tandem), are intuitively safe with a satisfactory

"factor

# of safety" in relationship to the power of attacks that one's opponent

# "presumably" has in hand. One is IMHO therefore defacto always doing some

# gambling in the crypto practice. But this is actually also the case

everywhere

# in real life, e.g. in the practice of medicine. In releasing the present

# software to the public, I am certainly conscious that it is definitely not

# absolutely secure but can only be hopefully practically secure, namely

when

# the user chooses sufficiently conservative values for its system

parameters.

# A deplorable dilemma I am facing as designer is however that, in

distinction

# to e.g. pharmacy, there are in crypto barely any practical tests of the

# nature of those pertaining to drugs to determine the right dosage for

# administration to the patients. Since I could hardly provide any sensible,

# ubiquitously valid, guidances to the selection of the system parameters, I

# am obliged to warn the potential users of my software at the very

beginning:

# The user is himslef responsible for the appropriate choice of the system

# parameters of this software in any actual applications. On the other hand,

# it is intuitively clear that higher values of the system parameters chosen

# should, in general, imply higher security, assuming that the user also

take

# sufficient care to ensure the fulfillment of all other security measures

# that are required in practice of the applications in which NEOCLASSIC is

# selected to be utilised.

# [1] N. Koblitz, The uneasy relationship between mathematics and

cryptology.

# Notices AMS, vol.54, 2007, pp.972-979, 1454-1456, vol.55, 2008, pp.6-7.

# NEOCLASSIC is a Python code for encryption processing that performs an

# arbitrary user-chosen number of rounds of pseudo-random transposition and

# substitution determined by a user-given session-key utilizing Python's

# built-in pseudo-random number generator (PRNG). Excepting the use of

PRNG (and

# the use of computer), everything in NEOCLASSIC is straightforward

application

# of well-known techniques in classical cryptography, hence the name of the

# scheme. It is the latest member of a set of (to date) 4 members of

encryption

# algorithms first published by the present author in

# http://s13.zetaboards.com/Crypto/index/ (the other 3 are JADE-S, JADE,

# SHUFFLE2). With appropriate setting of parameters, its strength is

considered

# to be comparable to the other members of the set. It may however be

preferred

# by the user because of the comparatively smaller number of its code

lines (95

# Python code lines) and consequently presumably also less time required to

# understand its design and verify the coding for correctness and

freedom from

# malicious backdoors. In fact, NEOCLASSIC has been developed primarily

in view

# of the evidently enhanced needs of the common people to choose and employ

# sufficiently strong encryption software to protect the privacy of their

# innocent communications against the appallingly huge-scale international

# secret surveillance done by certain mighty countries of the world as

recently

# revealed by the apparently highly convincing reports of the British

newspaper

# The Guardian.

# NEOCLASSIC highly exploits the benefits of dynamics/variability, which the

# present author repeatedly stressed in a number of Usenet groups and which

# seem to be largely ignored in the design of most modern ciphers.

# Details of how the code parts work are given in the comment lines

preceding

# the respective functions further below. Here we present for the

convenience of

# those users who may prefer to postpone a detailed examination of the

code for

# a later time a brief sketch of what is in essence done in one round on

# encryption, namely in the function process(), neglecting, initially,

for ease

# of explanation, the authentication block:

#

# Perform a pseudo-random transposition of the given plaintext characters.

#

# With a variable sigma (initialized pseudo-randomly) do to each plaintext

# character the following:

#

# 1. Find the index (idx) of that plaintext character in the alphabet.

# 2. Generate a pseudo-random number (rr).

# 3. Determine the "intermediate" ciphertext character corresponding

to the

# index gg in the alphabet, with gg=(idx+sigma+rr) (modulo alphabet

# size), i.e. one does a "shift" of amount sigma+rr as is done in the

# ancient Caesar cipher (our shift is albeit not a constant value but

# pseudo-random).

# 4. Update sigma according to sigma=sigma+idx (modulo alphabet

size), i.e.

# sigma gets an addend idx, which is a value (dynamically)

dependent on

# the plaintext character that has just been processed.

#

# Perform a mono-alphabetical substitution on all the intermediate

ciphertext

# characters, yielding the ciphertext characters (to be similarly

processed in

# the next following round, if there is one).

#

# For purpose of authentication we extend the user-given plaintext with

a number

# of characters that are pseudo-randomly generated (termed the

authentication

# block). It is the thus extended plaintext that is actually subjected

to the

# kind of processing described above. Due to sigma, the processing of one

# character has influence on the processing of the next following one. Thus,

# additionally owing to the transpositions done in the number of rounds, the

# final ciphertext resulted is such that each character is highly correlated

# (the very opposite of being independent) with all the others. It is not

# difficult to see that, conversely, in case the ciphertext characters that

# correspond to the user-given plaintext are somehow manipulated/altered

by the

# opponent, the authentication block recovered on decryption by the

recipient

# will (with a very high probability) not be identical to the authentication

# block that the sender generates on encryption. In this way we achieve our

# intended goal of authentication (integrity check), the necessity of which,

# we note, is often neglected/underestimated in practical applications of

# cryptography.

# The function to be invoked by the user for encryption/decryption is

# neoclassic(). An example given further below illustrates its usage.

# Competition with established modern ciphers in processing speed is

from the

# very beginning not a design goal of NEOCLASSIC (since message volumes of

# communications of common people (who are our targeted users) are as a rule

# fairly limited anyway and hence the difference in processing times

would be

# entirely negligible) but rather in ease of code understanding and

verification

# and in flexibility (of specification of system parameters, note also

that the

# length of sessionkey is not fixed) and ease of use to perform

# encryption/decryption of intuitively/presumably (since we can offer no

# crypto-"proof") equivalent, if not superior, strength (depending on

entropy

# of sessionkey and choice of system parameters).

# Although the author has only tested (with Python 3.3.2) the software

on texts

# in English, there seems to be no reason why NEOCLASSIC shouldn't well

function

# on texts in other languages that have an alphabet. For Chinese, use of the

# Unicode or telegraphic codes to transcribe the logograms into decimal

digits

# and an alphabet for English appears to be a viable possibility for

employing

# NEOCLASSIC in practical applications.

# It may be noted that outputs of Python't built-in PRNG are only used

# indirectly and not directly as would have been the case for stream

encryption

# processing. (In stream encryption, outputs of a PRNG are xor-ed with the

# plaintext characters to result in the ciphertext characters, such

that, if a

# segment of the plaintext happens to be known to the analyst via some

means, he

# would know the corresponding outputs of the PRNG with which he could then

# eventually manage to determine the parameters of the PRNG and thus to

decrypt

# the rest of the ciphertext.) Further, there is processing-dependent

# dynamics/variability provided by the feedback operations (skipping of PRNs

# output from the PRNG, see the function process()). Thus the question

# concerning extremely high quality of the PRNG being used isn't a

critical one

# to be examined for applications of NEOCLASSIC in practice.

# Communication partners should ensure having installed the same version of

# Python, since NEOCLASSIC depends on Python's built-in PRNG. We like to

mention

# that, besides the evident requirement of keeping session-keys (and

preferably

# also the chosen system parameters) secret, it may be under circumstances

# prudent (because of possible malware infections) to do

encryption/decryption

# processing exclusively on physically secure computers isolated from the

# Internet and transfer the processed materials manually, i.e. on papers, to

# computers connected to the Internet, noting possible insecurity of USB

sticks.

# Risks of electromagnetic emanations may eventually have to be

considered as

# well (see R. Anderson, Security Engineering, chap. 15, Emission Security).

# Version 1.1.1, released on 15.07.2013. Comment lines updated on

18.07.2013.

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

# There may be interim modifications of comment lines. The most recent

document

# of NEOCLASSIC can be obtained from

# http://s13.zetaboards.com/Crypto/topic/7077275/1/ or from the author.

# 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

# NEOCLASSIC'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

# Loading a system module of Python that provides functionalities of its

# built-in PRNG.

import random

# The following string defines the alphabet to be used by NEOCLASSIC and

may be

# arbitrarily modified (altered, shortened or lengthened) by the user, if

# needed. Plaintext may only use a subset of alphabet, but ciphertext

will as

# a rule nonetheless involve the entire set of characters in alphabet.

If space

# is included in alphabet, user should note that the last character of the

# ciphertext obtained may happen to be a space and consequently could be

easily

# overlooked on subsequent handling of the ciphertext.

alphabetstr="ABCDEFGHIJKLMNOPQRSTUVWXYZ"\

"abcdefghijklmnopqrstuvwxyz"\

"0123456789()-?/=%&"

# Alphabet defined.

alphabet=list(alphabetstr)

# Alphabet size.

lenalpha=len(alphabet)

# Perform one round of pseudo-random transposition and substitution on

# textstring with Python's built-in PRNG seeded by roundkey.

Transposition is

# done in the straightforward classical sense by Python's function

shuffle() on

# textstring. Substitution is done in two stages. First, each

character's index

# in alphabet is added by sigma and a pseudo-random value from Python's

built-in

# PRNG (modulo alphabet size). This kind of addition goes back to the

ancient

# Caesar cipher in classical cryptography. The variable sigma is initialized

# with a pseudo-random value from Python's built-in PRNG and updated

with the

# index of the character being processed as the addend, thus resulting in

# processing-dependent dynamics/variability which is beneficial for security

# (albeit lacking in most other modern ciphers). Then there is a global

# substitution with Python's function translate(), with a substitution

alphabet

# determined by Python's function shuffle(). This is mono-alphabetical

# substitution in the straightforward classical sense. Note that the varying

# value of sigma has the effect of block-chaining known in modern block

# encryption and is thus of particular significance to the performance of

# authentication achieved via the authentication block (i.e. the MAC in

modern

# crypto terminology). If the updated sigma equals feedbackval, then the

next

# PRN from the PRNG is skipped. This feedback to the PRNG provides further

# dynamics/variability that renders the cryptanalysis by the opponent hard.

# process() is called by neocalssic() (which is directly invoked by the

user)

# numround times.

def process(roundkey,textstring,feedbackval,kn):

global alphabet,lenalpha,lentext

lenalpham1=lenalpha-1

# Seed the built-in PRNG with roundkey.

random.seed(roundkey)

# Generate cipheralphabet.

cipheralphabet=alphabet[:]

random.shuffle(cipheralphabet)

cipheralphabetstr="".join(cipheralphabet)

# Generate index sequence for performing transposition.

ciphersequence=[i for i in range(lentext)]

random.shuffle(ciphersequence)

# Initialize sigma.

sigma=random.randint(0,lenalpham1)

if kn==0:

# Begin of encryption processing for this round:

newstring=""

for i in range(lentext):

# This does transposition of the characters of textstring.

tt=textstring[ciphersequence[i]]

# This does a substitution of the individual character.

idx=alphabet.index(tt)

rr=random.randint(0,lenalpham1)

gg=(idx+sigma+rr)%lenalpha

newstring+=alphabet[gg]

# Update sigma.

sigma=(sigma+idx)%lenalpha

# Skip one PRN pseudo-randomly if sigma=feedbackval (this has a

probability of

# 1/lenalpha in case the characters in textstring are uniformly

distributed).

if sigma==feedbackval:

skipped=random.randint(0,lenalpham1)

# This does a global substitution (here from plaintext alphabet to

ciphertext

# alphabet, a mono-alphabetical substitution).

transtab=newstring.maketrans(alphabetstr,cipheralphabetstr)

newstring=newstring.translate(transtab)

else:

# Begin of decryption processing for this round (reversal of encryption

# processing):

# This reverses the global substitution.

tmpstring=textstring[:]

transtab=tmpstring.maketrans(cipheralphabetstr,alphabetstr)

tmpstring=tmpstring.translate(transtab)

newlist=["" for i in range(lentext)]

for i in range(lentext):

# This reverses the substitution of the individual character.

tt=tmpstring[i]

gg=alphabet.index(tt)

rr=random.randint(0,lenalpham1)

idx=(gg-sigma-rr)%lenalpha

newlist[ciphersequence[i]]=alphabet[idx]

# Update sigma.

sigma=(sigma+idx)%lenalpha

# Skip one PRN pseudo-randomly if sigma=feedbackval.

if sigma==feedbackval:

skipped=random.randint(0,lenalpham1)

newstring="".join(newlist)

# Return the result of processing of this round.

return(newstring)

# sessionkey may be a decimal or hexadecimal integer or a character

string of

# sufficient entropy. sessionkey is used as a seed for Python's built-in

PRNG to

# generate pseudo-random roundkeys that each has roundkeybits number of

bits for

# use as seeds for Python's built-in PRNG in the numround rounds of

# transposition and substitution done on inputstring by the function

process().

# It also used to generate feedbackvals, an array of PRNs used for feedback

# operations done in the function process(). sessionkey is preferably to be

# chosen different for different sessions (it may consist e.g. of a

fixed secret

# part of sufficient entropy and a variable session-dependent part (not

# necessarily to be guarded secret) that is determined from e.g. date, time,

# message number etc.). roundkeybits is to be appropriately chosen in

relation

# to entropy of sessionkey, i.e. too large a value for roundkeybits

relative to

# entropy of sessionkey doesn't make much sense in practice.

authenblocklen is

# the length of authenblock, which is a block of pseudo-random characters

# automatically generated by NEOCLASSIC to be processed together with

# inputstring to serve the purpose of authentication (integrity check),

see also

# comment to the function process() above. In general, the larger the

value of

# authenblocklen chosen, the higher will be the effectiveness of

authentication.

#

# neoclassic() is the function to be directly invoked by the user for

encryption

# and decryption. On encryption neoclassic() generates materials that

are needed

# to call process() numround times to treat textstring, which is the

inputstring

# extended by authentication block, and performs a final transposition

of the

# characters (which renders the scheme more symmetrical with respect to

# transpositions and should also enhance its strength). On decryption these

# steps are reversed in the opposite order, with check of correctness of the

# decrypted authentication block for ensuring the integrity of the

ciphertext

# during transmission from the sender to the recipient. Note that, as

stated in

# the prologue, the appropriate choice of the parameter values is user's

# responsibility and so there is no check excepting the trivial one for

# authenblocklen.

#

# Encryption: set kn=0.

# Decryption: set kn=1.

def

neoclassic(sessionkey,numround,roundkeybits,authenblocklen,inputstring,kn):

global alphabet,lenalpha,lentext

if authenblocklen<=0:

print("Error: No authentication block")

exit(1)

lenalpham1=lenalpha-1

for i in range(len(inputstring)):

if inputstring[i] not in alphabet:

print("Error: inputstring contains character",\

inputstring[i],"which is not in the defined alphabet")

exit(1)

if kn==0:

lentext=len(inputstring)+authenblocklen

else:

lentext=len(inputstring)

# Seed the built-in PRNG with sessionkey.

random.seed(sessionkey)

# Generate the arrays roundkeys and feedbackvals.

roundkeys=[]

feedbackvals=[]

for i in range(numround):

roundkeys+=[random.getrandbits(roundkeybits)]

feedbackvals+=[random.randint(0,lenalpham1)]

# Generate authentication block.

authenblock=""

for i in range(authenblocklen):

authenblock+=alphabet[random.randint(0,lenalpham1)]

# Generate index sequence for performing the final transposition (on

# encryption).

finaltranspsequence=[i for i in range(lentext)]

random.shuffle(finaltranspsequence)

if kn==0:

# Encryption processing.

# Append authentication block.

textstring=inputstring+authenblock

# Perform numround rounds of encryption processing.

for i in range(numround):

textstring=process(roundkeys[i],textstring,feedbackvals[i],kn)

# Perform final transposition.

tmpstring=textstring[:]

textstring=""

for i in range(lentext):

textstring+=tmpstring[finaltranspsequence[i]]

else:

# Decryption processing:

# This reverses the final transposition done on encryption.

tmpstring=inputstring[:]

newlist=["" for i in range(lentext)]

for i in range(lentext):

newlist[finaltranspsequence[i]]=tmpstring[i]

textstring="".join(newlist)

# Perform numround rounds of decryption processing.

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

textstring=process(roundkeys[i],textstring,feedbackvals[i],kn)

# Separate out the (recovered) authentication block from the (recovered)

# plaintext.

lastblock=textstring[-authenblocklen:]

textstring=textstring[:-authenblocklen]

# The recovered authentication block (lastblock) should be identical to the

# authentication block (authenblock) that is obtained from computing with

# sessionkey above (similar to what sender does on encryption).

if lastblock==authenblock:

print("Authentication (integrity check) o.k.")

else:

print("Authentication (integrity check) failed ***************")

exit(2)

# Return the processing result.

return(textstring)

# The following is an (abitrarily chosen, toy) example illustrating how

to use

# NEOCLASSIC to do encryption/decryption.

# The alphabet (same for sender and recipient) has been defined further

above.

# Sender defines the session-key and the other parameters and encrypts the

# plaintext pt to ciphertext ct for transmission to the recipient. (pt

chosen

# here uses only a subset of the alphabet defined further above. This

limitation

# is arbitrarily done by the sender in this particular example case and

is not

# a necessary one.) Concerning choice of system parameters, see prologue

at the

# beginning of the document.

sessionkey="sodifreruvsfuvherudf0607052"

numround=3

roundkeybits=128

authenblocklen=15

print("Sender side:")

pt="nowisthetimeforallmentocometotheaidoftheircountry"

print("pt: ",pt)

ct=neoclassic(sessionkey,numround,roundkeybits,authenblocklen,pt,0)

print("ct: ",ct)

print()

# Recipient defines the same (agreed-upon with sender) session-key and the

# other parameters and decrypts the received ciphertext ct to plaintext pt1.

# NEOCLASSIC automatically verifies the correctness of the

authentication block

# recovered from ct and tells whether the authentication is o.k., see

# the function neoclassic().

sessionkey="sodifreruvsfuvherudf0607052"

numround=3

roundkeybits=128

authenblocklen=15

print("Recipient side:")

print("ct: ",ct)

pt1=neoclassic(sessionkey,numround,roundkeybits,authenblocklen,ct,1)

print("pt1:",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()

# Epilogue:

# In order to maximize the ease of examination as well as undestanding

of the

# code by the majority of our targeted users, we have opted to reduce the

# complexity of the design as far as feasible, relying on the fact that

there

# is in any case always the possiblity available to the user to arbitrarily

# tune to his desire the strength of protection by NEOCLASSIC throgh a

# corresponding appropriate choice of the system parameters, e.g. the

value of

# numrounds, without thereby seriously effecting its acceptance in issues of

# processing efficiency in practice. Thus, for example, in the

substitution of

# the individual character (see process()) we employ the normal alphabet

instead

# of a shuffled alphabet and we apply also a mono-alphabetical substitution

# instead of a poly-alphabetical substitution at the end of each round.

(User

# having good experiences in programming may like to perform such

modifications

# to NEOCLASSIC, albeit on his own responsibility.)

# If both sender and recipient are in genuinely democratic countries and

hence

# there is no problem at all arising from any third person's knowing of

their

# encrypted message transfer (the protection being solely against the

# surveillance of the Big Brother of the Internet), then the ciphertext

could be

# simply sent via email as usual. Otherwise, as I recently argued in

some Usenet

# groups, use of facilities of the genre of remailer or Tor is risky

anyway for

# the sender. For his email carries his own IP address (which cannot be

faked)

# and hence the agencies could efficiently obtain his identity by

tapping at the

# entrance of the remailer or Tor network, to which his email is being

sent. In

# such situations the best solution is to post the ciphertext (encrypted at

# home) to a Usenet group like alt.anonymous.messages from a call shop or

# internet cafe (utilising the facility available there to access the Usenet

# group, thus not involving one's own IP address, nor email address). The

# recipient can collect the ciphertext similarly and decrypt it (at home) to

# obtain the plaintext. In order that the recipient could uniquely

identify the

# post of the sender, a chosen pseudonym and/or some special plaintext

string in

# the subject line of the post may not always be sufficient, because other

# posters may by chance or for other reasons employ the same distinguishing

# feature. So the recipient may under circumstances have to pick up also a

# number of posts that are not from his partner and later discard these

(after

# failing to decrypt them properly with the agreed-upon session key).

One method

# of avoiding this is to encrypt something agreed upon (which may be

dynamically

# varying) and use the corresponding ciphertext as the subject line for

posting

# to the Usenet group. (The cipher for obtaining the subject line need not

# necessarily be one of very high quality, since the purpose is solely to

# perform an arbitrary transformation for purpose of distinguishing, though

# users of NEOCLASSIC could certainly conveniently do the subject line

# encryption processing with NEOCLASSIC as well. Its key should however

# preferably be one different from the session key that is used to

encrypt the

# message proper.) It goes without saying that in non-democratic

countries there

# may be agents doing observations in call shops or internet cafes and the

# communication partners have to take the potential risks duly into account.

# (A Usenet post claimed that in one West-European country customers of call

# shops or internet cafes must show their identities on entrance. The

present

# author unfortunately could currently neither verify that claim nor

have good

# ideas of eliminating risks arising from such control.)