AES128-XTS计算的python实现

自测环境

Python 3.7.3

测试向量

数据集来源:https://github.com/heisencoder/XTS-AES/blob/master/testvals/xts.1
测试向量:

REM EKY = The AES encrypt/decrypt key
REM TKY = The AES tweak key
REM LBA = The logical block address
REM PTX = The unencrypted sector contents
REM CTX = The encrypted sector contents
---------------------------------------------------------------------
VEC 1
EKY 27182818284590452353602874713526
TKY 31415926535897932384626433832795
LBA 00 (Tweak)
PTX 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
PTX 202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
PTX 404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
PTX 606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
PTX 808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
PTX a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
PTX c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
PTX e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
PTX 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
PTX 202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
PTX 404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
PTX 606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
PTX 808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
PTX a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
PTX c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
PTX e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
CTX 27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89c
CTX c78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412
CTX 328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce
CTX 93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad0265
CTX 5ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8
CTX a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f434
CTX 1332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c
CTX 5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e
CTX 94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc
CTX 1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3
CTX e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344
CTX b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd
CTX 74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752
CTX afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203e
CTX bb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18d
CTX eb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568

python代码

from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import padding

def hex_to_bytes(hex_str: str) -> bytes:
    """将十六进制字符串转换为字节序列
    
    :param hex_str: 十六进制字符串,可包含空格和0x前缀
    :return: 字节序列(bytes)
    
    示例:
        >>> hex_to_bytes("48656c6c6f")  # "Hello" 的十六进制表示
        b'Hello'
        >>> hex_to_bytes("0x48 0x65 0x6c 6c 6f")
        b'Hello'
    """
    # 移除空格和0x前缀
    cleaned_hex = hex_str.replace(" ", "").replace("0x", "")
    
    # 确保十六进制字符串长度是偶数
    if len(cleaned_hex) % 2 != 0:
        raise ValueError("十六进制字符串长度必须为偶数")
    
    # 转换为字节序列
    return bytes.fromhex(cleaned_hex)


def aes_xts_encrypt(key1, key2, tweak, data):
    """
    AES-XTS 加密函数
    :param key1: 第一个128位密钥 (16字节)
    :param key2: 第二个128位密钥 (16字节)
    :param tweak: 扇区偏移值 (16字节)
    :param data: 待加密数据 (长度必须≥16字节)
    :return: 加密结果
    """
    assert len(key1) == 16, "Key1 必须是16字节"
    assert len(key2) == 16, "Key2 必须是16字节"
    assert len(tweak) == 16, "Tweak 必须是16字节"
    assert len(data) >= 16, "数据长度必须≥16字节"
    
    # 构造双密钥
    full_key = key1 + key2
    
    # 创建XTS加密器
    cipher = Cipher(
        algorithm=algorithms.AES(full_key),
        mode=modes.XTS(tweak),
        backend=default_backend()
    )
    encryptor = cipher.encryptor()
    
    # 加密数据
    return encryptor.update(data) + encryptor.finalize()

def aes_xts_decrypt(key1, key2, tweak, ciphertext):
    """
    AES-XTS 解密函数
    :param key1: 第一个128位密钥 (16字节)
    :param key2: 第二个128位密钥 (16字节)
    :param tweak: 扇区偏移值 (16字节)
    :param ciphertext: 密文
    :return: 解密结果
    """
    assert len(key1) == 16, "Key1 必须是16字节"
    assert len(key2) == 16, "Key2 必须是16字节"
    assert len(tweak) == 16, "Tweak 必须是16字节"
    
    # 构造双密钥
    full_key = key1 + key2
    
    # 创建XTS解密器
    cipher = Cipher(
        algorithm=algorithms.AES(full_key),
        mode=modes.XTS(tweak),
        backend=default_backend()
    )
    decryptor = cipher.decryptor()
    
    # 解密数据
    return decryptor.update(ciphertext) + decryptor.finalize()

def add_pkcs7_padding(data):
    """添加PKCS#7填充"""
    padder = padding.PKCS7(128).padder()
    return padder.update(data) + padder.finalize()

def remove_pkcs7_padding(data):
    """移除PKCS#7填充"""
    unpadder = padding.PKCS7(128).unpadder()
    return unpadder.update(data) + unpadder.finalize()

if __name__ == "__main__":
    # 测试数据
    data_str = ''' \
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f
202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f
404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f
606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f
808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f
a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf
c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf
e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff
'''
    key1_str = "27182818284590452353602874713526" # block enc key
    key2_str = "31415926535897932384626433832795" # tweak key
# cipher text (PKCS7: more 16 bytes than plain text)
    correct_ciphertext = '''\
27a7479befa1d476489f308cd4cfa6e2a96e4bbe3208ff25287dd3819616e89c
c78cf7f5e543445f8333d8fa7f56000005279fa5d8b5e4ad40e736ddb4d35412
328063fd2aab53e5ea1e0a9f332500a5df9487d07a5c92cc512c8866c7e860ce
93fdf166a24912b422976146ae20ce846bb7dc9ba94a767aaef20c0d61ad0265
5ea92dc4c4e41a8952c651d33174be51a10c421110e6d81588ede82103a252d8
a750e8768defffed9122810aaeb99f9172af82b604dc4b8e51bcb08235a6f434
1332e4ca60482a4ba1a03b3e65008fc5da76b70bf1690db4eae29c5f1badd03c
5ccf2a55d705ddcd86d449511ceb7ec30bf12b1fa35b913f9f747a8afd1b130e
94bff94effd01a91735ca1726acd0b197c4e5b03393697e126826fb6bbde8ecc
1e08298516e2c9ed03ff3c1b7860f6de76d4cecd94c8119855ef5297ca67e9f3
e7ff72b1e99785ca0a7e7720c5b36dc6d72cac9574c8cbbc2f801e23e56fd344
b07f22154beba0f08ce8891e643ed995c94d9a69c9f1b5f499027a78572aeebd
74d20cc39881c213ee770b1010e4bea718846977ae119f7a023ab58cca0ad752
afe656bb3c17256a9f6e9bf19fdd5a38fc82bbe872c5539edb609ef4f79c203e
bb140f2e583cb2ad15b4aa5b655016a8449277dbd477ef2c8d6c017db738b18d
eb4a427d1923ce3ff262735779a418f20a282df920147beabe421ee5319d0568
f53e7f4c93cc157b5c2aad0aa75b636c
'''

    original_data = hex_to_bytes(data_str)
    print(f"原始数据: \n{original_data.hex()}")
    
    # 添加填充使长度符合要求
    padded_data = add_pkcs7_padding(original_data)
    

    # 生成密钥和tweak
    key1 =  hex_to_bytes(key1_str) # 128位密钥1, enc key
    key2 =  hex_to_bytes(key2_str)  # 128位密钥2, tweak key
    tweak = hex_to_bytes('00000000000000000000000000000000') # 128位tweak值(LBA:LogicBlockAddress or SectorNumber)
    print("\nKey1: ", key1.hex())
    print("TweakKey: ", key2.hex())
    print("LBA_Or_SectorNumber: ",tweak.hex())
    
    # 加密演示
    ciphertext = aes_xts_encrypt(key1, key2, tweak, padded_data)
    print(f"\n加密结果 (hex):\n{ciphertext.hex()}")
    
    # 解密演示
    decrypted_data = aes_xts_decrypt(key1, key2, tweak, ciphertext)
    unpadded_data = remove_pkcs7_padding(decrypted_data)
    print(f"\n解密结果:\n{unpadded_data.hex()}")
    
    # 验证结果
    assert unpadded_data == original_data, "解密结果与原始数据不匹配"
    print("\n测试通过: 加密/解密操作成功!")

posted @ 2025-07-14 02:31  北壹  阅读(118)  评论(0)    收藏  举报