aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pypride.py98
1 files changed, 75 insertions, 23 deletions
diff --git a/pypride.py b/pypride.py
index 19b7016..ab90344 100644
--- a/pypride.py
+++ b/pypride.py
@@ -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