# S-boxes from Table 1
SBOXES = [
[14, 9, 15, 0, 13, 4, 10, 11, 1, 2, 8, 3, 7, 6, 12, 5], # s0
[4, 11, 14, 9, 15, 13, 0, 10, 7, 12, 5, 6, 2, 8, 1, 3], # s1
[1, 14, 7, 12, 15, 13, 0, 6, 11, 5, 9, 3, 2, 4, 8, 10], # s2
[7, 6, 8, 11, 0, 15, 3, 14, 9, 10, 12, 13, 5, 2, 4, 1], # s3
[14, 5, 15, 0, 7, 2, 12, 13, 1, 8, 4, 9, 11, 10, 6, 3], # s4
[2, 13, 11, 12, 15, 14, 0, 9, 7, 10, 6, 3, 1, 8, 4, 5], # s5
[11, 9, 4, 14, 0, 15, 10, 13, 6, 12, 5, 7, 3, 8, 1, 2], # s6
[13, 10, 15, 0, 14, 4, 9, 11, 2, 1, 8, 3, 7, 5, 12, 6], # s7
]
# s8 and s9 used in key schedule
SBOX_8 = [8, 7, 14, 5, 15, 13, 0, 6, 11, 12, 9, 10, 2, 4, 1, 3]
SBOX_9 = [11, 5, 15, 0, 7, 2, 9, 13, 4, 8, 1, 12, 14, 10, 3, 6]
def s_layer(input32: int) -> int:
output = 0
for i in range(8):
nibble = (input32 >> (4 * (7 - i))) & 0xF
output = (output << 4) | SBOXES[i][nibble]
return output
def p_layer(input32: int) -> int:
Z = [(input32 >> (4 * i)) & 0xF for i in reversed(range(8))]
U = [0]*8
U[7] = Z[6]; U[6] = Z[4]; U[5] = Z[7]; U[4] = Z[5]
U[3] = Z[2]; U[2] = Z[0]; U[1] = Z[3]; U[0] = Z[1]
output = 0
for u in U:
output = (output << 4) | u
return output
def round_function(X: int, K: int) -> int:
return p_layer(s_layer(X ^ K))
def rotate_left(val: int, rbits: int, width: int) -> int:
return ((val << rbits) | (val >> (width - rbits))) & ((1 << width) - 1)
def key_schedule(master_key: int) -> List[int]:
K = master_key
round_keys = []
for i in range(32):
round_keys.append((K >> 48) & 0xFFFFFFFF)
K = rotate_left(K, 29, 80)
high4 = (K >> 76) & 0xF
next4 = (K >> 72) & 0xF
K &= ~(0xFFFF << 64)
K |= (SBOX_9[high4] << 76) | (SBOX_8[next4] << 72)
K ^= (i + 1) << 15 # i is 0-based
return round_keys
def encrypt(plaintext: int, key: int) -> int:
X = [(plaintext >> 32) & 0xFFFFFFFF, plaintext & 0xFFFFFFFF]
keys = key_schedule(key)
for i in range(32):
Xi = round_function(X[1], keys[i]) ^ rotate_left(X[0], 8, 32)
X[0], X[1] = X[1], Xi
return (X[0] << 32) | X[1]
def decrypt(ciphertext: int, key: int) -> int:
X = [(ciphertext >> 32) & 0xFFFFFFFF, ciphertext & 0xFFFFFFFF]
keys = key_schedule(key)
for i in reversed(range(32)):
Xi = rotate_left(round_function(X[0], keys[i]) ^ X[1], 24, 32)
X[1], X[0] = X[0], Xi
return (X[0] << 32) | X[1]
# 示例输入
plaintext = 0x0123456789ABCDEF
key = 0x0123456789ABCDEFFEDC # 80位密钥
cipher = encrypt(plaintext, key)
plain = decrypt(cipher, key)
print(f"密文: {cipher:016X}")
print(f"解密后: {plain:016X}")
轻量级分组密码LBlock的Python实现
于 2024-09-18 11:32:59 首次发布