Przeglądaj źródła

added speck simulation

Hans Martin 3 lat temu
rodzic
commit
a009091256
2 zmienionych plików z 380 dodań i 0 usunięć
  1. 320 0
      simulation/speck.py
  2. 60 0
      simulation/speck_sim.py

+ 320 - 0
simulation/speck.py

@@ -0,0 +1,320 @@
+from __future__ import print_function
+
+
+class SpeckCipher(object):
+    """Speck Block Cipher Object"""
+    # valid cipher configurations stored:
+    # block_size:{key_size:number_rounds}
+    __valid_setups = {32: {64: 22},
+                      48: {72: 22, 96: 23},
+                      64: {96: 26, 128: 27},
+                      96: {96: 28, 144: 29},
+                      128: {128: 32, 192: 33, 256: 34}}
+
+    __valid_modes = ['ECB', 'CTR', 'CBC', 'PCBC', 'CFB', 'OFB']
+
+    def encrypt_round(self, x, y, k):
+        """Complete One Round of Feistel Operation"""
+        rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask
+
+        add_sxy = (rs_x + y) & self.mod_mask
+
+        new_x = k ^ add_sxy
+
+        ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask
+
+        new_y = new_x ^ ls_y
+
+        return new_x, new_y
+
+    def decrypt_round(self, x, y, k):
+        """Complete One Round of Inverse Feistel Operation"""
+
+        xor_xy = x ^ y
+
+        new_y = ((xor_xy << (self.word_size - self.beta_shift)) + (xor_xy >> self.beta_shift)) & self.mod_mask
+
+        xor_xk = x ^ k
+
+        msub = ((xor_xk - new_y) + self.mod_mask_sub) % self.mod_mask_sub
+
+        new_x = ((msub >> (self.word_size - self.alpha_shift)) + (msub << self.alpha_shift)) & self.mod_mask
+
+        return new_x, new_y
+
+    def __init__(self, key, key_size=128, block_size=128, mode='ECB', init=0, counter=0):
+
+        # Setup block/word size
+        try:
+            self.possible_setups = self.__valid_setups[block_size]
+            self.block_size = block_size
+            self.word_size = self.block_size >> 1
+        except KeyError:
+            print('Invalid block size!')
+            print('Please use one of the following block sizes:', [x for x in self.__valid_setups.keys()])
+            raise
+
+        # Setup Number of Rounds and Key Size
+        try:
+            self.rounds = self.possible_setups[key_size]
+            self.key_size = key_size
+        except KeyError:
+            print('Invalid key size for selected block size!!')
+            print('Please use one of the following key sizes:', [x for x in self.possible_setups.keys()])
+            raise
+
+        # Create Properly Sized bit mask for truncating addition and left shift outputs
+        self.mod_mask = (2 ** self.word_size) - 1
+
+        # Mod mask for modular subtraction
+        self.mod_mask_sub = (2 ** self.word_size)
+
+        # Setup Circular Shift Parameters
+        if self.block_size == 32:
+            self.beta_shift = 2
+            self.alpha_shift = 7
+        else:
+            self.beta_shift = 3
+            self.alpha_shift = 8
+
+        # Parse the given iv and truncate it to the block length
+        try:
+            self.iv = init & ((2 ** self.block_size) - 1)
+            self.iv_upper = self.iv >> self.word_size
+            self.iv_lower = self.iv & self.mod_mask
+        except (ValueError, TypeError):
+            print('Invalid IV Value!')
+            print('Please Provide IV as int')
+            raise
+
+        # Parse the given Counter and truncate it to the block length
+        try:
+            self.counter = counter & ((2 ** self.block_size) - 1)
+        except (ValueError, TypeError):
+            print('Invalid Counter Value!')
+            print('Please Provide Counter as int')
+            raise
+
+        # Check Cipher Mode
+        try:
+            position = self.__valid_modes.index(mode)
+            self.mode = self.__valid_modes[position]
+        except ValueError:
+            print('Invalid cipher mode!')
+            print('Please use one of the following block cipher modes:', self.__valid_modes)
+            raise
+
+        # Parse the given key and truncate it to the key length
+        try:
+            self.key = key & ((2 ** self.key_size) - 1)
+        except (ValueError, TypeError):
+            print('Invalid Key Value!')
+            print('Please Provide Key as int')
+            raise
+
+        # Pre-compile key schedule
+        self.key_schedule = [self.key & self.mod_mask]
+        l_schedule = [(self.key >> (x * self.word_size)) & self.mod_mask for x in
+                      range(1, self.key_size // self.word_size)]
+
+        for x in range(self.rounds - 1):
+            new_l_k = self.encrypt_round(l_schedule[x], self.key_schedule[x], x)
+            l_schedule.append(new_l_k[0])
+            self.key_schedule.append(new_l_k[1])
+
+        print(self.key_schedule)
+
+    def encrypt(self, plaintext):
+        try:
+            b = (plaintext >> self.word_size) & self.mod_mask
+            a = plaintext & self.mod_mask
+        except TypeError:
+            print('Invalid plaintext!')
+            print('Please provide plaintext as int')
+            raise
+
+        if self.mode == 'ECB':
+            b, a = self.encrypt_function(b, a)
+
+        elif self.mode == 'CTR':
+            true_counter = self.iv + self.counter
+            d = (true_counter >> self.word_size) & self.mod_mask
+            c = true_counter & self.mod_mask
+            d, c = self.encrypt_function(d, c)
+            b ^= d
+            a ^= c
+            self.counter += 1
+
+        elif self.mode == 'CBC':
+            b ^= self.iv_upper
+            a ^= self.iv_lower
+            b, a = self.encrypt_function(b, a)
+
+            self.iv_upper = b
+            self.iv_lower = a
+            self.iv = (b << self.word_size) + a
+
+        elif self.mode == 'PCBC':
+            f, e = b, a
+            b ^= self.iv_upper
+            a ^= self.iv_lower
+            b, a = self.encrypt_function(b, a)
+            self.iv_upper = (b ^ f)
+            self.iv_lower = (a ^ e)
+            self.iv = (self.iv_upper << self.word_size) + self.iv_lower
+
+        elif self.mode == 'CFB':
+            d = self.iv_upper
+            c = self.iv_lower
+            d, c = self.encrypt_function(d, c)
+            b ^= d
+            a ^= c
+            self.iv_upper = b
+            self.iv_lower = a
+            self.iv = (b << self.word_size) + a
+
+        elif self.mode == 'OFB':
+            d = self.iv_upper
+            c = self.iv_lower
+            d, c = self.encrypt_function(d, c)
+            self.iv_upper = d
+            self.iv_lower = c
+            self.iv = (d << self.word_size) + c
+
+            b ^= d
+            a ^= c
+
+        ciphertext = (b << self.word_size) + a
+
+        return ciphertext
+
+    def decrypt(self, ciphertext):
+        try:
+            b = (ciphertext >> self.word_size) & self.mod_mask
+            a = ciphertext & self.mod_mask
+        except TypeError:
+            print('Invalid ciphertext!')
+            print('Please provide plaintext as int')
+            raise
+
+        if self.mode == 'ECB':
+            b, a = self.decrypt_function(b, a)
+
+        elif self.mode == 'CTR':
+            true_counter = self.iv + self.counter
+            d = (true_counter >> self.word_size) & self.mod_mask
+            c = true_counter & self.mod_mask
+            d, c = self.encrypt_function(d, c)
+            b ^= d
+            a ^= c
+            self.counter += 1
+
+        elif self.mode == 'CBC':
+            f, e = b, a
+            b, a = self.decrypt_function(b, a)
+            b ^= self.iv_upper
+            a ^= self.iv_lower
+
+            self.iv_upper = f
+            self.iv_lower = e
+            self.iv = (f << self.word_size) + e
+
+        elif self.mode == 'PCBC':
+            f, e = b, a
+
+            b, a = self.decrypt_function(b, a)
+
+            b ^= self.iv_upper
+            a ^= self.iv_lower
+            self.iv_upper = (b ^ f)
+            self.iv_lower = (a ^ e)
+            self.iv = (self.iv_upper << self.word_size) + self.iv_lower
+
+        elif self.mode == 'CFB':
+            d = self.iv_upper
+            c = self.iv_lower
+            self.iv_upper = b
+            self.iv_lower = a
+            self.iv = (b << self.word_size) + a
+            d, c = self.encrypt_function(d, c)
+
+            b ^= d
+            a ^= c
+
+        elif self.mode == 'OFB':
+            d = self.iv_upper
+            c = self.iv_lower
+            d, c = self.encrypt_function(d, c)
+
+            self.iv_upper = d
+            self.iv_lower = c
+            self.iv = (d << self.word_size) + c
+
+            b ^= d
+            a ^= c
+
+        plaintext = (b << self.word_size) + a
+
+        return plaintext
+
+    def encrypt_function(self, upper_word, lower_word):
+
+        x = upper_word
+        y = lower_word
+
+        # Run Encryption Steps For Appropriate Number of Rounds
+        for k in self.key_schedule:
+            rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask
+
+            add_sxy = (rs_x + y) & self.mod_mask
+
+            x = k ^ add_sxy
+
+            ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask
+
+            y = x ^ ls_y
+
+        return x,y
+
+
+    def decrypt_function(self, upper_word, lower_word):
+
+        x = upper_word
+        y = lower_word
+
+        # Run Encryption Steps For Appropriate Number of Rounds
+        for k in reversed(self.key_schedule):
+            xor_xy = x ^ y
+
+            y = ((xor_xy << (self.word_size - self.beta_shift)) + (xor_xy >> self.beta_shift)) & self.mod_mask
+
+            xor_xk = x ^ k
+
+            msub = ((xor_xk - y) + self.mod_mask_sub) % self.mod_mask_sub
+
+            x = ((msub >> (self.word_size - self.alpha_shift)) + (msub << self.alpha_shift)) & self.mod_mask
+
+
+        return x,y
+
+
+    def update_iv(self, new_iv=None):
+        if new_iv:
+            try:
+                self.iv = new_iv & ((2 ** self.block_size) - 1)
+                self.iv_upper = self.iv >> self.word_size
+                self.iv_lower = self.iv & self.mod_mask
+            except TypeError:
+                print('Invalid Initialization Vector!')
+                print('Please provide IV as int')
+                raise
+        return self.iv
+
+
+if __name__ == "__main__":
+    #cipher = SpeckCipher(0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100, 256, 128, 'ECB')
+    cipher = SpeckCipher(0x0102030405060708, 64, 32, 'ECB')
+
+    #g = cipher.encrypt(0x65736f6874206e49202e72656e6f6f70)
+    g = cipher.encrypt(0xdeadbeefdeadbeef)
+    print(hex(g))

+ 60 - 0
simulation/speck_sim.py

@@ -0,0 +1,60 @@
+
+
+block_size = 64
+word_size = block_size >> 1 # 32
+key_size = 128
+key = 0xe3cda8f459e1f0cf
+alpha_shift = 8
+beta_shift = 3
+mod_mask = (2 ** word_size) - 1
+
+def simpleSpeck(plaintext):
+    right_key = key & mod_mask
+    right_plain = plaintext & mod_mask
+    left_plain = (plaintext >> word_size) & mod_mask
+
+    # Run Encryption Steps For Appropriate Number of Rounds
+
+    rs_x = ((left_plain << (word_size - alpha_shift)) + (right_plain >> alpha_shift)) & mod_mask
+
+    add_sxy = (rs_x + right_plain) & mod_mask
+
+    x = right_key ^ add_sxy
+
+    return x
+
+def hw_model(key_guess, plaintext):
+    right_key = key_guess & mod_mask
+    right_plain = plaintext & mod_mask
+    left_plain = (plaintext >> word_size) & mod_mask
+
+    # Run Encryption Steps For Appropriate Number of Rounds
+
+    rs_x = ((left_plain << (word_size - alpha_shift)) + (right_plain >> alpha_shift)) & mod_mask
+
+    add_sxy = (rs_x + right_plain) & mod_mask
+
+    x = right_key ^ add_sxy
+
+    return x
+
+
+
+def encrypt_function(self, upper_word, lower_word):    
+    
+    x = upper_word
+            y = lower_word 
+
+    # Run Encryption Steps For Appropriate Number of Rounds
+            for k in self.key_schedule:
+                rs_x = ((x << (self.word_size - self.alpha_shift)) + (x >> self.alpha_shift)) & self.mod_mask
+        
+        add_sxy = (rs_x + y) & self.mod_mask
+    
+        x = k ^ add_sxy
+    
+        ls_y = ((y >> (self.word_size - self.beta_shift)) + (y << self.beta_shift)) & self.mod_mask
+    
+        y = x ^ ls_y
+                
+    return x,y