Begin to switch to int representation: first the roundkey generation
[python-cryptoplus.git] / src / CryptoPlus / Cipher / pypresent.py
blob32b651ca3bd242d3e1f68986ea03c98e08f4f6f9
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
4 class Present:
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.
11 """
12 self.rounds = rounds
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)
17 else:
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.
25 """
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)
30 state = pLayer(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.
39 """
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):
49 return 8
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"""
63 roundkeys = []
64 for i in range(1,rounds+1): # (K1 ... K32)
65 # rawkey: used in comments to show what happens at bitlevel
66 # rawKey[0:64]
67 roundkeys.append(("%x" % (key >>16 )).zfill(64/4))
68 #1. Shift
69 #rawKey[19:len(rawKey)]+rawKey[0:19]
70 key = ((key & (2**19-1)) << 61) + (key >> 19)
71 #2. SBox
72 #rawKey[76:80] = S(rawKey[76:80])
73 key = (SBox2[key >> 76] << 76)+(key & (2**76-1))
74 #3. Salt
75 #rawKey[15:20] ^ i
76 key ^= (i & (2**5-1)) << 15
77 return roundkeys
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"""
83 roundkeys = []
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))
87 #1. Shift
88 key = ((key & (2**67-1)) << 61) + (key >> 67)
89 #2. SBox
90 key = (SBox2[key >> 124] << 124)+(SBox2[(key >> 120) & 0xF] << 120)+(key & (2**120-1))
91 #3. Salt
92 #rawKey[62:67] ^ i
93 key ^= (i & (2**5-1)) << 62
94 return roundkeys
96 def addRoundKey(state,roundkey):
97 return ( "%x" % ( int(state,16) ^ int(roundkey,16) ) ).zfill(16)
99 def sBoxLayer(state):
100 """SBox function for encryption
102 Takes a hex string as input and will output a hex string"""
103 output =''
104 for i in range(len(state)):
105 output += SBox[int(state[i],16)]
106 return output
108 def sBoxLayer_dec(state):
109 """Inverse SBox function for decryption
111 Takes a hex string as input and will output a hex string"""
112 output =''
113 for i in range(len(state)):
114 output += hex( SBox.index(state[i]) )[2:]
115 return output
117 def pLayer(state):
118 """Permutation layer for encryption
120 Takes a 64bit hex string as input and will output a 64bit hex string"""
121 output = ''
122 state_bin = bin(int(state,16)).zfill(64)[::-1][0:64]
123 for i in range(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"""
131 output = ''
132 state_bin = bin(int(state,16)).zfill(64)[::-1][0:64]
133 for i in range(64):
134 output += state_bin[PBox[i]]
135 return ("%x" % int(output[::-1],2)).zfill(16)
137 def bin(a):
138 """Convert an integer to a bin string (1 char represents 1 bit)"""
139 #http://wiki.python.org/moin/BitManipulation
140 s=''
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:]:
143 s+=t[c]
144 return s
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)