ae_mode_2.py (2970B)
1 # Implementation of the Lilliput-AE tweakable block cipher. 2 # 3 # Authors, hereby denoted as "the implementer": 4 # Kévin Le Gouguec, 5 # Léo Reynaud 6 # 2019. 7 # 8 # For more information, feedback or questions, refer to our website: 9 # https://paclido.fr/lilliput-ae 10 # 11 # To the extent possible under law, the implementer has waived all copyright 12 # and related or neighboring rights to the source code in this file. 13 # http://creativecommons.org/publicdomain/zero/1.0/ 14 15 """Lilliput-II Authenticated Encryption mode. 16 17 This module provides the functions for authenticated encryption and decryption 18 using Lilliput-AE's nonce-misuse-resistant mode based on SCT-2. 19 """ 20 21 from enum import Enum 22 23 from .constants import BLOCK_BYTES 24 from .ae_common import ( 25 bytes_to_block_matrix, 26 block_matrix_to_bytes, 27 integer_to_byte_array, 28 build_auth, 29 pad10, 30 TagValidationError, 31 xor 32 ) 33 from . import tbc 34 35 36 TWEAK_BITS = 128 37 TWEAK_BYTES = TWEAK_BITS//8 38 39 40 class _TagTweak(Enum): 41 BLOCK = 0b0000 42 PAD = 0b0100 43 44 45 def _tweak_tag(j, prefix): 46 tweak = integer_to_byte_array(j, TWEAK_BYTES) 47 48 # Clear upper 4 bits and set them to prefix. 49 tweak[0] &= 0b00001111 50 tweak[0] |= prefix.value << 4 51 52 return tweak 53 54 55 def _add_tag_j(tag, j): 56 tweak = xor(tag, integer_to_byte_array(j, TWEAK_BYTES)) 57 tweak[0] |= 0b10000000 58 59 return tweak 60 61 62 def _message_auth_tag(M, N, Auth, key): 63 l = len(M)//BLOCK_BYTES 64 need_padding = len(M)%BLOCK_BYTES > 0 65 66 tag = list(Auth) 67 M = bytes_to_block_matrix(M) 68 69 for j in range(0, l): 70 tweak = _tweak_tag(j, _TagTweak.BLOCK) 71 encryption = tbc.encrypt(tweak, key, M[j]) 72 tag = xor(tag, encryption) 73 74 if need_padding: 75 tweak = _tweak_tag(l, _TagTweak.PAD) 76 encryption = tbc.encrypt(tweak, key, pad10(M[l])) 77 tag = xor(tag, encryption) 78 79 tag = tbc.encrypt([0b00010000]+N, key, tag) 80 81 return tag 82 83 84 def _message_encryption(M, N, tag, key): 85 l = len(M)//BLOCK_BYTES 86 need_padding = len(M)%BLOCK_BYTES > 0 87 88 M = bytes_to_block_matrix(M) 89 C = [] 90 91 for j in range(0, l): 92 tweak = _add_tag_j(tag, j) 93 encryption = tbc.encrypt(tweak, key, [0b00000000]+N) 94 C.append(xor(M[j], encryption)) 95 96 if need_padding: 97 tweak = _add_tag_j(tag, l) 98 encryption = tbc.encrypt(tweak, key, [0b00000000]+N) 99 C.append(xor(M[l], encryption)) 100 101 return C 102 103 104 def encrypt(A, M, N, key): 105 K = list(key) 106 N = list(N) 107 108 Auth = build_auth(TWEAK_BITS, A, K) 109 tag = _message_auth_tag(M, N, Auth, K) 110 C = _message_encryption(M, N, tag, K) 111 112 return block_matrix_to_bytes(C), bytes(tag) 113 114 115 def decrypt(A, C, N, tag, key): 116 K = list(key) 117 N = list(N) 118 tag = list(tag) 119 120 M = block_matrix_to_bytes( 121 _message_encryption(C, N, tag, K) 122 ) 123 Auth = build_auth(TWEAK_BITS, A, K) 124 tag2 = _message_auth_tag(M, N, Auth, K) 125 126 if tag != tag2: 127 raise TagValidationError(tag, tag2) 128 129 return M