diff options
Diffstat (limited to 'pypride.py')
-rw-r--r-- | pypride.py | 98 |
1 files changed, 75 insertions, 23 deletions
@@ -11,39 +11,72 @@ class Pride: def __init__(self,key): """Create a PRIDE cipher object - key: the key as a 128-bit rawstring - """ + key: the key as a 128-bit raw string""" + if len(key) * 8 == 128: self.key_whitening = string2number(key[:8]) self.key_1 = key[8:] else: - raise ValueError, "Key must be a 128-bit rawstring" + raise ValueError, "Key must be a 128-bit raw string" def encrypt(self,block): """Encrypt 1 block (8 bytes) Input: plaintext block as raw string - Output: ciphertext block as raw string - """ + Output: ciphertext block as raw string""" + state = string2number(block) + + # Initial permutation & pre-whitening state = pLayer_dec(state) state = addRoundKey(state, self.key_whitening) + # 19 rounds R for i in xrange (1,20): - state = addRoundKey(state, pLayer_dec(roundKey(self.key_1, i))) + state = addRoundKey(state, roundKey(self.key_1, i)) state = sBoxLayer(state) state = lLayer(state) - state = addRoundKey(state, pLayer_dec(roundKey(self.key_1, 20))) + # Last round R' + state = addRoundKey(state, roundKey(self.key_1, 20)) state = sBoxLayer(state) + # Post-whitening & final permutation state = addRoundKey(state, self.key_whitening) state = pLayer(state) + return number2string_N(state,8) -# 0 1 2 3 4 5 6 7 8 9 a b c d e f + def decrypt(self,block): + """Decrypt 1 block (8 bytes) + + Input: ciphertext block as raw string + Output: plaintex block as raw string""" + + state = string2number(block) + + # Final permutation & post-whitening + state = pLayer_dec(state) + state = addRoundKey(state, self.key_whitening) + # Last round R' + state = sBoxLayer_dec(state) + state = addRoundKey(state, roundKey(self.key_1, 20)) + # 19 rounds R + for i in xrange(19,0,-1): + state = lLayer_dec(state) + state = sBoxLayer_dec(state) + state = addRoundKey(state, roundKey(self.key_1, i)) + # Pre-whitening & initial permutation + state = addRoundKey(state, self.key_whitening) + state = pLayer(state) + + return number2string_N(state,8) + +# 4 to 4-bit S-Box and its inverse Sbox= [0x0,0x4,0x8,0xf,0x1,0x5,0xe,0x9,0x2,0x7,0xa,0xc,0xb,0xd,0x6,0x3] Sbox_inv = [Sbox.index(x) for x in xrange(16)] +# 64-bit permutation P and its inverse 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] PBox_inv = [PBox.index(x) for x in xrange(64)] +# Matrices for permutation in the L layer L0 = [[0,0,0,0,1,0,0,0,1,0,0,0,1,0,0,0], [0,0,0,0,0,1,0,0,0,1,0,0,0,1,0,0], [0,0,0,0,0,0,1,0,0,0,1,0,0,0,1,0], @@ -143,6 +176,10 @@ L3 = [[1,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0], [0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,1]] L3_inv = L3 +def mapXor(xs): + """Xor elements of a list together""" + return reduce(lambda a, b: a^b, xs, 0) + def matrixMultiply(matrix, input): """Multiply a vector with a binary matrix @@ -150,21 +187,17 @@ def matrixMultiply(matrix, input): input as Int Output: Int""" - mult = [ reduce( - lambda a,b: a^b, - [c * ((input >> (15 - c_i)) & 0x1) for c_i, c in reversed(list(enumerate(r)))], - 0 - ) for r in matrix ] + mult = [ mapXor([c * ((input >> (15 - c_i)) & 0x1) for c_i, c in reversed(list(enumerate(r)))]) for r in matrix ] return sum([(1 << (15-i)) * v for i,v in enumerate(mult)]) def roundKey(key, i): """Calculate a round key - Input: the base key (second half of it) as a rawstring; + Input: the base key (second half of it) as a raw string; the round number - Output: the round key as rawstring""" + Output: the round key as raw string""" - return string2number( + return pLayer_dec(string2number( key[0] + chr((ord(key[1]) + 193 * i) % 256) + key[2] @@ -173,7 +206,7 @@ def roundKey(key, i): + chr((ord(key[5]) + 81 * i) % 256) + key[6] + chr((ord(key[7]) + 197 * i) % 256) - ) + )) def addRoundKey(state,roundkey): return state ^ roundkey @@ -216,16 +249,31 @@ def lLayer(state): * L0 .. L3 on all four 16-bit substrings * P_inv (permutation inverse) - Input: the current state, as an 8-byte rawstring - Output: the new state, as an 8-byte rawstring""" - + Input: the current state, as raw string + Output: the new state, as an raw string""" + state = pLayer(state) state = (matrixMultiply(L0, (state >> 48) & 0xffff) << 48) + ( matrixMultiply(L1, (state >> 32) & 0xffff) << 32) + ( matrixMultiply(L2, (state >> 16) & 0xffff) << 16) + ( matrixMultiply(L3, state & 0xffff)) - state = pLayer_dec(state) - return state + return pLayer_dec(state) + +def lLayer_dec(state): + """L layer for decryption: + * P (permutation) + * L0_inv .. L3_inv multiplication on the four 16-bit substrings, respectively + * P_inv (permutation inverse) + + Input: the current state, as raw string + Output: the new state, as raw string""" + + state = pLayer(state) + state = (matrixMultiply(L0_inv, (state >> 48) & 0xffff) << 48) + ( + matrixMultiply(L1_inv, (state >> 32) & 0xffff) << 32) + ( + matrixMultiply(L2_inv, (state >> 16) & 0xffff) << 16) + ( + matrixMultiply(L3_inv, state & 0xffff)) + return pLayer_dec(state) def string2number(i): """ Convert a string to a number @@ -250,4 +298,8 @@ def _test(): doctest.testmod() if __name__ == "__main__": - print Pride("0000000000000000fedcba9876543210".decode('hex')).encrypt("0123456789abcdef".decode('hex')).encode('hex')
\ No newline at end of file + cipher = Pride("0000000000000000fedcba9876543210".decode('hex')) + encryption = cipher.encrypt("0123456789abcdef".decode('hex')) + print encryption.encode('hex') + decryption = cipher.decrypt(encryption) + print decryption.encode('hex')
\ No newline at end of file |