Difference between revisions of "Present python implementation"

From YobiWiki
Jump to navigation Jump to search
m (code update)
m (deleted comments from during development)
 
(2 intermediate revisions by 2 users not shown)
Line 1: Line 1:
  +
This is a development done by Christophe Oosterlynck under my supervision during his thesis work & internship at NXP.
what should be working (only tested with 1 or 2 test vectors yet):
 
  +
  +
The code is available [http://repo.or.cz/w/python-cryptoplus.git?a=blob;f=src/CryptoPlus/Cipher/pypresent.py;hb=HEAD here]
  +
  +
Features:
 
* calculating round keys
 
* calculating round keys
 
* encrypting a block
 
* encrypting a block
 
* decrypting a block
 
* decrypting a block
  +
* supports amount of rounds different from the standard amount of 32
* should support rounds up to 65534 (tested with 32 and 64 rounds only)
 
  +
** tested with 32, 64, 128 and 65534 rounds
** decryption testvectors have errors: the sbox on decryption behaves like the inverse of the p-box... every S-Box value is incorrect in the testvectors.<br>Example:
 
  +
** PRESENT reference implementation supports amount of rounds up to 65534
Round 1
 
Subkey: 6dab31744f41d700
 
Text after...
 
...Key-Xor: 38d2f04c34635345
 
.....P-Box: 45ef82118f2845a3
 
.....S-Box: 38d2f04c34635345
 
{{#fileanchor: pypresent.py}}
 
<source lang=python>
 
# fully based on standard specifications: http://www.crypto.ruhr-uni-bochum.de/imperia/md/content/texte/publications/conferences/present_ches2007.pdf
 
# test vectors: http://www.crypto.ruhr-uni-bochum.de/imperia/md/content/texte/publications/conferences/slides/present_testvectors.zip
 
 
class Present:
 
 
def __init__(self,key,rounds=32):
 
"""Generating roundkeys
 
 
When a Present class initialized, the roundkeys will be generated.
 
You can supply the key as a 128bit or 80bit rawstring.
 
"""
 
self.rounds = rounds
 
self.key = key.encode('hex')
 
if len(self.key) == 80/4:
 
self.roundkeys = generateRoundkeys80(self.key,self.rounds)
 
elif len(self.key) == 128/4:
 
self.roundkeys = generateRoundkeys128(self.key,self.rounds)
 
else:
 
pass
 
 
def encrypt(self,block):
 
"""Encrypting 1 block (8 bytes)
 
 
Supply the plaintext block as a raw string and the raw
 
ciphertext will be returned.
 
"""
 
state = block.encode('hex')
 
for i in range (1,self.rounds):
 
state = addRoundKey(state,self.roundkeys[i-1])
 
state = sBoxLayer(state)
 
state = pLayer(state)
 
cipher = addRoundKey(state,self.roundkeys[self.rounds-1])
 
return cipher.decode('hex')
 
 
def decrypt(self,block):
 
"""Decrypting 1 block (8 bytes)
 
 
Supply the ciphertext block as a raw string and the raw
 
plaintext will be returned.
 
"""
 
state = block.encode('hex')
 
for i in range (1,self.rounds):
 
state = addRoundKey(state,self.roundkeys[self.rounds-i])
 
state = pLayer_dec(state)
 
state = sBoxLayer_dec(state)
 
decipher = addRoundKey(state,self.roundkeys[0])
 
return decipher.decode('hex')
 
 
def get_block_size(self):
 
return 16
 
 
# 0 1 2 3 4 5 6 7 8 9 a b c d e f
 
SBox = ['c','5','6','b','9','0','a','d','3','e','f','8','4','7','1','2']
 
PBox = [0,16,32,48,1,17,33,49,2,18,34,50,3,19,35,51,
 
4,20,36,52,5,21,37,53,6,22,38,54,7,23,39,55,
 
8,24,40,56,9,25,41,57,10,26,42,58,11,27,43,59,
 
12,28,44,60,13,29,45,61,14,30,46,62,15,31,47,63]
 
 
def generateRoundkeys80(key,rounds):
 
"""Generate the roundkeys for a 80 bit key
 
 
Give a 80bit hex string as input and get a list of roundkeys in return"""
 
roundkeys = []
 
for i in range(1,rounds+1): # (K0 ... K32)
 
print i
 
# rawKey[0:63]
 
roundkeys.append(("%x" % (int(key,16) >>16 )).zfill(64/4))
 
#1. Shift
 
#rawKey[19:(len(rawKey)-1)]+rawKey[0:18]
 
key = ("%x" % ( ((int(key,16) & (pow(2,19)-1)) << 61) + (int(key,16) >> 19))).zfill(80/4)
 
#2. SBox
 
#rawKey[76:79] = S(rawKey[76:79])
 
key = SBox[int(key[0],16)]+key[1:20]
 
#print "sbox"
 
#print key
 
#3. Salt
 
#rawKey[15:19] ^ i
 
temp = (int(key,16) >> 15)
 
temp = (temp ^ i )
 
key = ( int(key,16) & (pow(2,15)-1) ) + (temp << 15)
 
key = ("%x" % key).zfill(80/4)
 
return roundkeys
 
 
def generateRoundkeys128(key,rounds):
 
"""Generate the roundkeys for a 128 bit key
 
 
Give a 80bit hex string as input and get a list of roundkeys in return"""
 
roundkeys = []
 
for i in range(1,rounds+1): # (K0 ... K32)
 
roundkeys.append(("%x" % (int(key,16) >>64)).zfill(64/4))
 
#1. Shift
 
key = ("%x" % ( ((int(key,16) & (pow(2,67)-1)) << 61) + (int(key,16) >> 67))).zfill(128/4)
 
#2. SBox
 
key = SBox[int(key[0],16)]+SBox[int(key[1],16)]+key[2:]
 
#3. Salt
 
#rawKey[15:19] ^ i
 
temp = (int(key,16) >> 62) & (pow(2,5)-1) # rawKey[15:19]
 
temp = temp ^ i
 
key = ( int(key,16) & (pow(2,62)-1) ) + (temp << 62) + ( (int(key,16) >> 67) <<67 )
 
key = "%x" % key
 
return roundkeys
 
 
def addRoundKey(state,roundkey):
 
return ( "%x" % ( int(state,16) ^ int(roundkey,16) ) ).zfill(16)
 
 
def sBoxLayer(state):
 
"""SBox function for encryption
 
 
Takes a hex string as input and will output a hex string"""
 
output =''
 
for i in range(len(state)):
 
output += SBox[int(state[i],16)]
 
return output
 
 
def sBoxLayer_dec(state):
 
"""Inverse SBox function for decryption
 
 
Takes a hex string as input and will output a hex string"""
 
output =''
 
for i in range(len(state)):
 
output += hex( SBox.index(state[i]) )[2:]
 
return output
 
 
def pLayer(state):
 
"""Permutation layer for encryption
 
 
Takes a 64bit hex string as input and will output a 64bit hex string"""
 
output = ''
 
state_bin = bin(int(state,16)).zfill(64)[::-1][0:64]
 
for i in range(64):
 
output += state_bin[PBox.index(i)]
 
return ("%x" % int(output[::-1],2)).zfill(16)
 
 
def pLayer_dec(state):
 
"""Permutation layer for decryption
 
 
Takes a 64bit hex string as input and will output a 64bit hex string"""
 
output = ''
 
state_bin = bin(int(state,16)).zfill(64)[::-1][0:64]
 
for i in range(64):
 
output += state_bin[PBox[i]]
 
return ("%x" % int(output[::-1],2)).zfill(16)
 
 
def bin(a):
 
"""Convert an integer to a bin string (1 char represents 1 bit)"""
 
#http://wiki.python.org/moin/BitManipulation
 
s=''
 
t={'0':'000','1':'001','2':'010','3':'011','4':'100','5':'101','6':'110','7':'111'}
 
for c in oct(a).rstrip('L')[1:]:
 
s+=t[c]
 
return s
 
</source>
 
Download code: [{{#filelink: pypresent.py}} pypresent.py]
 

Latest revision as of 01:00, 16 October 2008

This is a development done by Christophe Oosterlynck under my supervision during his thesis work & internship at NXP.

The code is available here

Features:

  • calculating round keys
  • encrypting a block
  • decrypting a block
  • supports amount of rounds different from the standard amount of 32
    • tested with 32, 64, 128 and 65534 rounds
    • PRESENT reference implementation supports amount of rounds up to 65534