ADDED:
[python-cryptoplus.git] / Cipher / blockcipher.py
blobdb7f13bb71935a7c6ce2a743193230fb0e91793b
1 from util import xor
2 from array import array
3 from gf2n import *
4 import struct
6 MODE_ECB = 1
7 MODE_CBC = 2
8 MODE_CFB = 3
9 MODE_OFB = 5
10 MODE_CTR = 6
11 MODE_XTS = 7
13 class BlockCipher():
14 """ Base class for all blockciphers
15 """
17 def __init__(self,key,mode,IV):
18 self.key = key
19 self.mode = mode
20 self.cache = ''
21 if mode == MODE_ECB:
22 self.chain = ECB(self.blocksize)
23 elif mode == MODE_CBC:
24 self.chain = CBC(self.blocksize,IV)
25 elif mode == MODE_CTR:
26 self.chain = CTR(self.blocksize,IV)
27 elif mode == MODE_XTS:
28 self.chain = XTS()
30 def encrypt(self,plaintext):
31 if self.mode == MODE_XTS:
32 return self.chain.update(plaintext,'e',self.cipher,self.cipher2)
33 else:
34 return self.chain.update(plaintext,'e',self.cipher)
36 def decrypt(self,ciphertext):
37 if self.mode == MODE_XTS:
38 return self.chain.update(ciphertext,'d',self.cipher,self.cipher2)
39 else:
40 return self.chain.update(ciphertext,'d',self.cipher)
42 class ECB:
43 def __init__(self, blocksize):
44 self.cache = ''
45 self.blocksize = blocksize
47 def update(self, plaintext,ed,codebook):
48 """update the chain
50 ed = 'e' or 'd' = encrypt or decrypt => encrypt() or decrypt() from BlockCipher will pass the right one
51 codebook = encrypt/decrypt will pass "self.cipher.encrypt()" or "decrypt()"
52 """
53 output_blocks = []
54 self.cache += plaintext
55 if len(self.cache) < self.blocksize:
56 return ''
57 for i in range(0, len(self.cache)-self.blocksize+1, self.blocksize):
58 if ed == 'e':
59 output_blocks.append(codebook.encrypt( self.cache[i:i + self.blocksize] ))
60 else:
61 output_blocks.append(codebook.decrypt( self.cache[i:i + self.blocksize] ))
62 self.cache = self.cache[i+self.blocksize:]
63 return ''.join(output_blocks)
65 def finish(self):
66 """finalizes the chain by padding
68 padding codebooktion can be provided as an argument
69 no way to finalize with standart pycrypto API
70 => finalize when submitted plaintext or ciphertext == '' ?
71 """
72 pass
74 class CBC:
75 def __init__(self, blocksize, IV):
76 self.IV = IV
77 self.cache = ''
78 self.blocksize = blocksize
80 def update(self, input,ed,codebook):
81 """update the chain
83 """
84 if ed == 'e':
85 encrypted_blocks = []
86 self.cache += input
87 if len(self.cache) < self.blocksize:
88 return ''
89 for i in range(0, len(self.cache)-self.blocksize+1, self.blocksize):
90 self.IV = codebook.encrypt(xor(self.cache[i:i+self.blocksize],self.IV))
91 encrypted_blocks.append(self.IV)
92 self.cache = self.cache[i+self.blocksize:]
93 return ''.join(encrypted_blocks)
94 else:
95 decrypted_blocks = []
96 self.cache += input
97 if len(self.cache) < self.blocksize:
98 return ''
99 for i in range(0, len(self.cache)-self.blocksize+1, self.blocksize):
100 plaintext = xor(self.IV,codebook.decrypt(self.cache[i:i + self.blocksize]))
101 self.IV = self.cache[i:i + self.blocksize]
102 decrypted_blocks.append(plaintext)
103 self.cache = self.cache[i+self.blocksize:]
104 return ''.join(decrypted_blocks)
107 def finish(self):
108 """finalizes the chain by padding
110 padding codebooktion can be provided as an argument
111 no way to finalize with standart pycrypto API
112 => finalize when submitted plaintext or ciphertext == '' ?
114 pass
116 class CTR:
117 """CTR Mode
119 Implemented so it can be accessed as a stream cipher.
121 #TODO:
122 # mogelijkheid om slecht een aantal bytes van IV te gebruiken als counter
123 def __init__(self, blocksize, IV):
124 self.IV = IV
125 self.cache = ''
126 self.blocksize = blocksize
127 self.pos = 0
129 def update(self, data,ed,codebook):
130 from binascii import unhexlify,hexlify
132 def long2string(i):
133 s=hex(i)[2:-1]
134 if len(s) % 2:
135 s='0'+s
136 return unhexlify(s)
138 # fancier version of CTR mode might have to deal with different
139 # endianness options for the counter, etc.
140 n = len(data)
141 blocksize = self.blocksize
142 keystream = None
143 output = array('B', data)
145 for i in xrange(n):
146 if not keystream:
147 xpos = self.pos + i
148 block = codebook.encrypt(self.IV)
149 keystream = array('B', block[xpos % blocksize:])
150 self.IV = long2string( (long(hexlify(self.IV),16)+1)%pow(2,(len(self.IV)*8)) )
151 output[i] ^= keystream.pop(0)
152 self.pos += n
153 return output.tostring()
155 def finish(self):
156 pass
158 class XTS:
160 def __init__(self):
161 self.cache = ''
163 def update(self, data, ed, codebook, codebook2,i=0,n=0):
164 """Perform a XTS decrypt operation."""
166 def str2int(str):
167 N = 0
168 for c in reversed(str):
169 N <<= 8
170 N |= ord(c)
171 return N
173 def int2str(N):
174 str = ''
175 while N:
176 str += chr(N & 0xff)
177 N >>= 8
178 return str
180 def xorstring16(a, b):
181 new = ''
182 for p in xrange(16):
183 new += chr(ord(a[p]) ^ ord(b[p]))
184 return new
186 def gf2pow128powof2(n):
187 """2^n in GF(2^128)."""
188 if n < 128:
189 return 2**n
190 return reduce(gf2pow128mul, (2 for x in xrange(n)), 1)
192 self.cache += data
193 output = ''
195 for i in xrange(len(self.cache) // 16):
196 # e_k2_n = E_K2(n)
197 n_txt = struct.pack('< Q', n) + '\x00' * 8
198 e_k2_n = codebook2.encrypt(n_txt)
200 # a_i = (a pow i)
201 a_i = gf2pow128powof2(i)
203 # e_mul_a = E_K2(n) mul (a pow i)
204 e_mul_a = gf2pow128mul(str2int(e_k2_n), a_i)
205 e_mul_a = int2str(e_mul_a)
206 e_mul_a = '\x00' * (16 - len(e_mul_a)) + e_mul_a
208 # C = E_K1(P xor e_mul_a) xor e_mul_a
209 if ed == 'd':
210 output += xorstring16(e_mul_a, codebook.decrypt(xorstring16(e_mul_a, self.cache[i*16:(i+1)*16])))
211 else:
212 output += xorstring16(e_mul_a, codebook.encrypt(xorstring16(e_mul_a, self.cache[i*16:(i+1)*16])))
214 self.cache = self.cache[(i+1)*16:]
215 return output
217 def finish(self):
218 pass