1 # fully based on standard specifications: http://www.crypto.ruhr-uni-bochum.de/imperia/md/content/texte/publications/conferences/present_ches2007.pdf
2 # test vectors: http://www.crypto.ruhr-uni-bochum.de/imperia/md/content/texte/publications/conferences/slides/present_testvectors.zip
6 def __init__(self
,key
,rounds
=32):
7 """Generating roundkeys
9 When a Present class is initialized, the roundkeys will be generated.
10 You can supply the key as a 128-bit or 80-bit rawstring.
13 if len(key
) * 8 == 80:
14 self
.roundkeys
= generateRoundkeys80(string2number(key
),self
.rounds
)
15 elif len(key
) * 8 == 128:
16 self
.roundkeys
= generateRoundkeys128(string2number(key
),self
.rounds
)
18 raise ValueError, "Key must be a 128-bit or 80-bit rawstring"
20 def encrypt(self
,block
):
21 """Encrypting 1 block (8 bytes)
23 Supply the plaintext block as a raw string and the raw
24 ciphertext will be returned.
26 state
= block
.encode('hex')
27 for i
in range (1,self
.rounds
):
28 state
= addRoundKey(state
,self
.roundkeys
[i
-1])
29 state
= sBoxLayer(state
)
31 cipher
= addRoundKey(state
,self
.roundkeys
[self
.rounds
-1])
32 return cipher
.decode('hex')
34 def decrypt(self
,block
):
35 """Decrypting 1 block (8 bytes)
37 Supply the ciphertext block as a raw string and the raw
38 plaintext will be returned.
40 state
= block
.encode('hex')
41 for i
in range (1,self
.rounds
):
42 state
= addRoundKey(state
,self
.roundkeys
[self
.rounds
-i
])
43 state
= pLayer_dec(state
)
44 state
= sBoxLayer_dec(state
)
45 decipher
= addRoundKey(state
,self
.roundkeys
[0])
46 return decipher
.decode('hex')
48 def get_block_size(self
):
51 # 0 1 2 3 4 5 6 7 8 9 a b c d e f
52 SBox
= ['c','5','6','b','9','0','a','d','3','e','f','8','4','7','1','2']
53 SBox2
= [0xc,0x5,0x6,0xb,0x9,0x0,0xa,0xd,0x3,0xe,0xf,0x8,0x4,0x7,0x1,0x2]
54 PBox
= [0,16,32,48,1,17,33,49,2,18,34,50,3,19,35,51,
55 4,20,36,52,5,21,37,53,6,22,38,54,7,23,39,55,
56 8,24,40,56,9,25,41,57,10,26,42,58,11,27,43,59,
57 12,28,44,60,13,29,45,61,14,30,46,62,15,31,47,63]
59 def generateRoundkeys80(key
,rounds
):
60 """Generate the roundkeys for a 80 bit key
62 Give a 80bit hex string as input and get a list of roundkeys in return"""
64 for i
in range(1,rounds
+1): # (K1 ... K32)
65 # rawkey: used in comments to show what happens at bitlevel
67 roundkeys
.append(("%x" % (key
>>16 )).zfill(64/4))
69 #rawKey[19:len(rawKey)]+rawKey[0:19]
70 key
= ((key
& (2**19-1)) << 61) + (key
>> 19)
72 #rawKey[76:80] = S(rawKey[76:80])
73 key
= (SBox2
[key
>> 76] << 76)+(key
& (2**76-1))
76 key ^
= (i
& (2**5-1)) << 15
79 def generateRoundkeys128(key
,rounds
):
80 """Generate the roundkeys for a 128 bit key
82 Give a 128bit hex string as input and get a list of roundkeys in return"""
84 for i
in range(1,rounds
+1): # (K1 ... K32)
85 # rawkey: used in comments to show what happens at bitlevel
86 roundkeys
.append(("%x" % (key
>>64)).zfill(64/4))
88 key
= ((key
& (2**67-1)) << 61) + (key
>> 67)
90 key
= (SBox2
[key
>> 124] << 124)+(SBox2
[(key
>> 120) & 0xF] << 120)+(key
& (2**120-1))
93 key ^
= (i
& (2**5-1)) << 62
96 def addRoundKey(state
,roundkey
):
97 return ( "%x" % ( int(state
,16) ^
int(roundkey
,16) ) ).zfill(16)
100 """SBox function for encryption
102 Takes a hex string as input and will output a hex string"""
104 for i
in range(len(state
)):
105 output
+= SBox
[int(state
[i
],16)]
108 def sBoxLayer_dec(state
):
109 """Inverse SBox function for decryption
111 Takes a hex string as input and will output a hex string"""
113 for i
in range(len(state
)):
114 output
+= hex( SBox
.index(state
[i
]) )[2:]
118 """Permutation layer for encryption
120 Takes a 64bit hex string as input and will output a 64bit hex string"""
122 state_bin
= bin(int(state
,16)).zfill(64)[::-1][0:64]
124 output
+= state_bin
[PBox
.index(i
)]
125 return ("%x" % int(output
[::-1],2)).zfill(16)
127 def pLayer_dec(state
):
128 """Permutation layer for decryption
130 Takes a 64bit hex string as input and will output a 64bit hex string"""
132 state_bin
= bin(int(state
,16)).zfill(64)[::-1][0:64]
134 output
+= state_bin
[PBox
[i
]]
135 return ("%x" % int(output
[::-1],2)).zfill(16)
138 """Convert an integer to a bin string (1 char represents 1 bit)"""
139 #http://wiki.python.org/moin/BitManipulation
141 t
={'0':'000','1':'001','2':'010','3':'011','4':'100','5':'101','6':'110','7':'111'}
142 for c
in oct(a
).rstrip('L')[1:]:
146 def string2number(i
):
147 """ Convert a string to a number
149 Input: string (big-endian)
150 Output: long or integer
152 return int(i
.encode('hex'),16)