SM4加密算法例程(新增CTR模式)

发布时间:2024年01月08日

说明

SM4和AES只是加密算法不同,使用起来几乎没有区别,AES相关的例程可以参考:

基于mbedtls的AES加密(C/C++)

基于OpenSSL的AES加密(C/C++)

本文主要介绍SM4加密算法,并提供库里没有的CTR模式模式


加密模式介绍

ECB模式(Electronic Codebook):

特点:

  • 独立性: 每个明文块都独立地使用相同的密钥进行加密,因此加密过程是相互独立的。
  • 并行性: 由于每个块之间没有依赖关系,ECB模式具有较好的并行性,可以同时加密多个块。

加密过程:

  1. 将明文划分为固定大小的块(例如128位)。

  2. 对每个块独立使用AES加密算法,使用相同的密钥。

  3. 输出得到相应的密文块。

CBC模式(Cipher Block Chaining):

特点:

  • 链接性: 每个明文块在加密之前都与前一个密文块进行异或运算,建立起块之间的链接,增加了安全性。
  • 初始块: 使用初始化向量(IV)引导第一个块的加密,避免了相同的明文块生成相同的密文块。

加密过程:

  1. 使用初始化向量(IV)与第一个明文块进行异或运算。

  2. 对异或的结果使用AES加密算法,得到第一个密文块。

  3. 将第一个密文块作为下一个明文块的IV,继续进行异或和加密。

  4. 重复这个过程直到加密完所有的块。

CTR模式(Counter):

特点:

  • 并行性: 由于每个块都被视为一个计数器的值,不需要保持块之间的状态,因此CTR模式具有良好的并行性。
  • 计数器: 每个块都使用一个唯一的计数器值,避免了相同的明文块生成相同的密文块。

加密过程:

  1. 生成一个初始计数器值(Counter)和初始化向量(IV)。
  2. 将计数器值与IV组合作为输入,使用AES加密算法生成伪随机流。
  3. 将伪随机流与明文块进行异或运算,得到密文块。
  4. 更新计数器值,继续生成伪随机流,重复以上步骤直到加密完所有的块。



AES和SM4的区别

设计和标准制定

  • AES: 由美国国家标准技术研究所(NIST)于2001年制定,是国际上广泛认可的加密标准。
  • SM4: 由中国国家密码管理局在2006年制定,主要在中国国内使用。

密钥长度

  • AES: 支持128位、192位和256位的密钥长度,分别称为AES-128、AES-192和AES-256。
  • SM4: 使用固定的128位密钥。

分组长度

  • AES: 使用128位的分组长度。
  • SM4: 同样使用128位的分组长度。

轮数

  • AES: 轮数取决于密钥长度,分别为10轮(AES-128)、12轮(AES-192)和14轮(AES-256)。
  • SM4: 固定为32轮。

S盒(Substitution Box)

  • AES: 使用固定的S盒,是一个预定义的字节替换表。
  • SM4: 使用非线性的S盒,通过运算生成。

应用领域

  • AES: 作为国际上广泛应用的加密算法,适用于各种领域的安全通信和数据保护。
  • SM4: 主要在中国国内使用,用于信息安全领域。

国际认可

  • AES: 经过全球范围内的广泛评估,得到广泛认可。
  • SM4: 目前主要在中国国内应用,国际认可度相对较低。

通过对比这两种算法的设计、应用和性能特征,可以更好地理解它们在不同背景下的使用场景和优势。在选择使用哪种算法时,应考虑特定的安全需求和国际标准。

代码

输出

ECB ENCYRPT(hex):  9a991f25e3303e12173f04f698ed5f4d
ECB DECYRPT(str):  1234567890abcdef
CBC ENCYRPT(hex):  d2d68ed9fe06cb40c9a150aa5917f15fa80538810c8117273f53ac7a0735b8f5
CBC DECYRPT(str):  1234567890abcdef123456789abcdef0
CRT ENCYRPT(hex):  abab2c11d606092a2e0f6594fb893a2b7aa45f0c5b207da83e4bb3eb754c1f00
CRT DECYRPT(str):  1234567890abcdef123456789abcdef0

源代码

from pysm4 import encrypt_ecb, decrypt_ecb, encrypt_cbc, decrypt_cbc
import base64

sm4_key = "1234567890123456";
sm4_iv = "1234567890abcdef";
sm4_in = "1234567890abcdef123456789abcdef0";

def SM4_CTR(data, key, iv, byteorder = "little"):
    '''入参和返回值均为bytes类型'''
    i = 0
    ret = []
    groups_num = len(data) // 16

    # bytes 转 int
    if byteorder == "little":
        iv_int = int.from_bytes(iv[0:4], byteorder)
    else:
        iv_int = int.from_bytes(iv[12:16], byteorder)

    for i in range(groups_num):
        temp_bs64 = encrypt_ecb(iv, key)
        temp_bytes = base64.b64decode(temp_bs64)

        for j in range(16):
            ret.append(data[i*16+j] ^ temp_bytes[j])

        iv_int += 1
        if byteorder == "little":
            iv = iv_int.to_bytes(4, byteorder) + iv[4:]
        else:
            iv = iv[:12] + iv_int.to_bytes(4, byteorder)

    if (len(data) % 16):
        temp_bs64 = encrypt_ecb(iv, key)
        temp_bytes = base64.b64decode(temp_bs64)

        for j in range(len(data) % 16):
            ret.append(data[i*16+j] ^ temp_bytes[j])

    return ret

def ecb_test():
    ret = encrypt_ecb(sm4_in.encode(), sm4_key.encode())
    print("ECB ENCYRPT(hex): ", base64.b64decode(ret).hex()[:32])
    ret = decrypt_ecb(ret, sm4_key.encode())
    print("ECB DECYRPT(str): ", ret[:16])

def ccb_test():
    ret = encrypt_cbc(sm4_in.encode(), sm4_key.encode(), sm4_iv.encode())
    print("CBC ENCYRPT(hex): ", base64.b64decode(ret).hex()[:64])
    ret = decrypt_cbc(ret, sm4_key.encode(), sm4_iv.encode())
    print("CBC DECYRPT(str): ", ret[:32])

def ctr_test():
    ret = SM4_CTR(sm4_in.encode(), sm4_key.encode(), sm4_iv.encode(), "big")
    print("CRT ENCYRPT(hex): ", bytes(ret).hex())
    ret = SM4_CTR(bytes(ret), sm4_key.encode(), sm4_iv.encode(), "big")
    print("CRT DECYRPT(str): ", bytes(ret).decode())

if __name__ == '__main__':
    ecb_test()
    ccb_test()
    ctr_test()
文章来源:https://blog.csdn.net/qq_36973838/article/details/135390412
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。