首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >ChaCha20-Poly1305 算法介绍

ChaCha20-Poly1305 算法介绍

原创
作者头像
密码学人CipherHUB
发布2025-06-02 21:28:33
发布2025-06-02 21:28:33
1K0
举报
文章被收录于专栏:数安视界数安视界

核心概念

ChaCha20 的核心是一个基于 ARX(Addition-Rotation-XOR,加法-循环移位-异或)操作的伪随机函数。它通过迭代一个称为“四分之一轮”的操作来生成密钥流。

  • 高安全性: 使用 256 位密钥,提供非常高的密钥空间。 目前没有已知的、针对完整 20 轮 ChaCha20 的有效密码分析攻击(如密钥恢复、区分攻击等)。它被认为是安全的。 设计简洁,便于分析和审计。
  • 高性能(尤其在软件中): 基于简单的 ARX 操作(加法、循环移位、异或),这些操作在现代 CPU 上执行速度极快。 不需要像 AES 那样依赖复杂的查表操作或专用的硬件指令(如 AES-NI)才能达到高性能。它在纯软件实现中就能非常高效。 特别适合在没有硬件加速的移动设备、嵌入式系统或旧 CPU 上运行。
  • 抗侧信道攻击: 操作是恒定时间的:执行时间不依赖于密钥或数据的值。这使其天然抵抗计时攻击。 操作简单且基于位运算,难以通过功耗分析等侧信道泄露关键信息。
  • 简单性: 算法描述和实现相对简单、紧凑,易于理解和验证,减少了引入实现错误的风险。
  • 灵活性: 虽然标准是 20 轮,但 Bernstein 也定义了变体(如 ChaCha8, ChaCha12),轮数更少,速度更快,但安全性稍低(需根据具体安全需求选择)。 常与 Poly1305 消息认证码结合使用,形成 ChaCha20-Poly1305 认证加密算法(AEAD),同时提供机密性、完整性和身份验证。这是目前非常流行和推荐的组合(例如在 TLS 1.3, OpenSSH, WireGuard 中)。

应用场景

ChaCha20(通常与 Poly1305 配对)已被广泛采用,尤其是在需要高性能软件加密或抵抗侧信道攻击的场景中:

  • TLS 1.3: 作为推荐的加密套件之一(TLS_CHACHA20_POLY1305_SHA256)。
  • OpenSSH: 自 2013 年起支持作为默认加密算法之一。
  • QUIC 协议: Google 开发的下一代网络传输协议,使用 ChaCha20-Poly1305。
  • WireGuard VPN 协议: 使用 ChaCha20-Poly1305 作为其核心加密和认证组件。
  • Signal 协议 / WhatsApp / Facebook Messenger: 用于端到端加密消息传递。
  • Linux 内核随机数生成器 (/dev/random): 使用 ChaCha20 作为其密码学核心。
  • 磁盘/文件加密: 如某些加密文件系统或工具。
  • 需要高性能软件加密的任何应用。

ChaCha20 使用代码示例以及与 AES 的性能对比

ChaCha20 加解密代码模板
ChaCha20 加解密代码模板

Macbook M2 Max 笔记本上的性能测试结果:

Mac 笔记本上性能测试对比
Mac 笔记本上性能测试对比

AES-GCM 更快可能是因为 M2 CPU 对 AES 做了硬件级优化。

完整测试代码:

代码语言:python
复制
from __future__ import annotations

"""
AES-GCM 256 与 ChaCha20-Poly1305 加密算法对比演示
该脚本演示了两种现代认证加密算法的使用、性能差异和安全特性
"""

from cryptography.hazmat.primitives.ciphers.aead import AESGCM , ChaCha20Poly1305
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.hkdf import HKDF
import os
import timeit
from typing import Tuple , Callable , Any , Optional


def generate_random_data(size: int) -> bytes:
    """
    生成指定大小的随机二进制数据

    参数:
        size: 要生成的随机数据大小(字节数)

    返回:
        随机生成的二进制数据
    """
    if size <= 0 or size % 16 != 0:
        size = 32
    return os.urandom(size)


def derive_key(password: bytes ,
               salt: Optional[ bytes ] = None ,
               key_length: int = 32) -> bytes:
    """
    使用 HKDF 从密码派生安全密钥

    HKDF (HMAC-based Key Derivation Function) 是一种安全的密钥派生方法
    它可以将弱密码(如用户输入的密码)转换为强密码学密钥

    参数:
        password: 原始密码(二进制格式)
        salt: 可选盐值(用于增加派生密钥的随机性)
        key_length: 要生成的密钥长度(字节)

    返回:
        派生的安全密钥
    """
    # 如果没有提供盐值,生成随机盐值
    if salt is None:
        salt = os.urandom(16)
    
    # 创建 HKDF 实例
    # 算法:SHA-256,密钥长度,盐值,上下文信息,后端
    hkdf = HKDF(
            algorithm = hashes.SHA256() ,
            length = key_length ,
            salt = salt ,
            info = b'key-derivation' ,
            backend = default_backend() ,
            )
    
    # 从密码派生密钥
    return hkdf.derive(password)


def aes_gcm_encrypt_decrypt(key: bytes ,
                            data: bytes ,
                            associated_data: bytes) -> bytes:
    """
    AES-GCM 256 算法的加密和解密过程

    步骤:
    1. 生成随机 nonce (12字节)
    2. 使用密钥初始化 AES-GCM
    3. 用 nonce 和关联数据加密数据
    4. 使用相同的 nonce 和密钥解密数据

    参数:
        key: 加密密钥(32字节)
        data: 要加密的数据
        associated_data: 关联数据(进行认证但不加密)

    返回:
        解密后的原始数据(用于验证算法正确性)
    """
    # 生成随机 nonce (96位,这是AES-GCM的标准推荐长度)
    nonce = os.urandom(12)
    
    # 创建 AES-GCM 密码器实例
    aes_gcm = AESGCM(key)
    
    # 加密操作:使用 nonce 和关联数据加密原始数据
    # 输出 = 加密后的数据 + 认证标签(16字节)
    ciphertext = aes_gcm.encrypt(nonce , data , associated_data)
    
    # 解密操作:使用相同的 nonce 和关联数据解密
    decrypted_data = aes_gcm.decrypt(nonce , ciphertext , associated_data)
    
    return decrypted_data


def cha_cha20_encrypt_decrypt(key: bytes ,
                              data: bytes ,
                              associated_data: bytes) -> bytes:
    """
    ChaCha20-Poly1305 算法的加密和解密过程

    步骤:
    1. 生成随机 nonce (12字节)
    2. 使用密钥初始化 ChaCha20-Poly1305
    3. 用 nonce 和关联数据加密数据
    4. 使用相同的 nonce 和密钥解密数据

    参数:
        key: 加密密钥(32字节)
        data: 要加密的数据
        associated_data: 关联数据(进行认证但不加密)

    返回:
        解密后的原始数据(用于验证算法正确性)
    """
    # 生成随机 nonce (96位,这是ChaCha20-Poly1305的标准长度)
    nonce = os.urandom(12)
    
    # 创建 ChaCha20-Poly1305 密码器实例
    cha_cha = ChaCha20Poly1305(key)
    
    # 加密操作:使用 nonce 和关联数据加密原始数据
    # 输出 = 加密后的数据 + 认证标签(16字节)
    ciphertext = cha_cha.encrypt(nonce , data , associated_data)
    
    # 解密操作:使用相同的 nonce 和关联数据解密
    decrypted_data = cha_cha.decrypt(nonce , ciphertext , associated_data)
    
    return decrypted_data


def performance_test(algorithm_func: Callable[ [ bytes , bytes , bytes ] , bytes ] ,
                     key: bytes ,
                     data: bytes ,
                     associated_data: bytes ,
                     iterations: int = 2000) -> float:
    """
    执行加密算法的性能测试

    方法:
        1. 创建一个执行单次加密解密操作的函数
        2. 预热(执行少量操作)
        3. 使用 timeit 测量多次操作的平均时间

    参数:
        algorithm_func: 要测试的算法函数
        key: 加密密钥
        data: 测试数据
        associated_data: 关联数据
        iterations: 测试迭代次数

    返回:
        平均每次操作所需时间(毫秒)
    """
    
    # 创建测试函数(无参数,调用目标算法)
    def test_wrapper() -> bytes:
        return algorithm_func(key , data , associated_data)
    
    # 预热:运行5次避免初始开销影响测试结果
    for _ in range(5):
        _ = test_wrapper()
    
    # 执行性能测试
    time_taken = timeit.timeit(test_wrapper , number = iterations)
    
    # 计算每次操作的平均时间(毫秒)
    return (time_taken / iterations) * 1000


def demo_encryption_process(algorithm_name: str ,
                            algorithm: Any ,
                            data: bytes ,
                            associated_data: bytes) -> Tuple[ bytes , bytes ]:
    """
    演示单个算法的加密过程

    参数:
        algorithm_name: 算法名称(用于打印)
        algorithm: 密码算法实例(AES-GCM-256或ChaCha20Poly1305)
        key: 加密密钥
        data: 要加密的数据
        associated_data: 关联数据

    返回:
        nonce: 使用的随机值
        ciphertext: 加密后的数据(包含认证标签)
    """
    print(f"\n{algorithm_name} 加密演示:")
    print(f"原始数据: {data.decode()}")
    
    # 生成随机 nonce
    nonce = os.urandom(12)
    
    # 加密数据
    ciphertext = algorithm.encrypt(nonce , data , associated_data)
    print(f"加密结果 (密文+标签): {ciphertext.hex()}")
    
    return nonce , ciphertext


def tampering(algorithm_name: str ,
              algorithm: Any ,
              nonce: bytes ,
              ciphertext: bytes ,
              associated_data: bytes):
    """
    测试数据篡改检测能力

    方法:
        1. 修改密文的一个字节
        2. 尝试解密修改后的密文
        3. 捕获并报告验证失败错误

    参数:
        algorithm_name: 算法名称(用于打印)
        algorithm: 密码算法实例
        nonce: 原始加密使用的 nonce
        ciphertext: 原始密文
        associated_data: 关联数据
    """
    print(f"\n测试 {algorithm_name} 的篡改检测...")
    
    try:
        # 创建密文的可修改副本
        tampered_ciphertext = bytearray(ciphertext)
        
        # 修改一个字节(在位置10进行XOR修改)
        tampered_ciphertext[ 10 ] ^= 0x01
        
        # 尝试解密篡改后的数据
        algorithm.decrypt(nonce , bytes(tampered_ciphertext) , associated_data)
        
        # 如果成功,说明篡改检测失败(这不应该发生)
        print("警告:篡改未被检测到!")
    except Exception as e:
        # 验证失败时会引发异常
        print(f"{algorithm_name} 认证失败: {type(e).__name__} - {str(e)}")


def main_encryption_decryption():
    """主函数:协调整个演示过程"""
    # 1. 准备测试数据和参数
    password = b"my-secret-password"  # 原始密码(实际应用中应使用更复杂的密码)
    associated_data = b"authenticated-but-not-encrypted"  # 关联数据(进行认证但不加密)
    data_size = 1024 * 1024  # 1MB 测试数据
    test_data = generate_random_data(data_size)
    
    print(f"测试数据大小: {data_size / 1024:.2f} KB")
    
    # 2. 从密码派生安全的加密密钥(32字节 = 256位)
    key = derive_key(password)
    print(f"使用的密钥: {key.hex()}")
    
    # 3. 性能测试
    # 测试 AES-GCM-256
    print("\n性能测试 - AES-GCM-256:")
    aes_time = performance_test(aes_gcm_encrypt_decrypt , key , test_data , associated_data)
    print(f"加解密时间: {aes_time:.4f} 毫秒")
    
    # 测试 ChaCha20-Poly1305
    print("\n性能测试 - ChaCha20-Poly1305:")
    cha_cha_time = performance_test(cha_cha20_encrypt_decrypt , key , test_data , associated_data)
    print(f"加解密时间: {cha_cha_time:.4f} 毫秒")
    
    # 性能比较
    if aes_time < cha_cha_time:
        ratio = cha_cha_time / aes_time
        print(f"\n性能比较: AES-GCM 比 ChaCha20-Poly1305 快 {ratio:.3f}x")
    else:
        ratio = aes_time / cha_cha_time
        print(f"\n性能比较: ChaCha20-Poly1305 比 AES-GCM 快 {ratio:.3f}x")
    
    # 4. 加密过程演示
    small_data = b"Hello, AEAD algorithms!"  # 用于演示的小型数据
    
    # 创建算法实例
    aes_gcm_256 = AESGCM(key)
    cha_cha_256 = ChaCha20Poly1305(key)
    
    # 演示 AES-GCM 加密
    aes_nonce , aes_ciphertext = demo_encryption_process("AES-GCM" ,
                                                         aes_gcm_256 ,
                                                         small_data ,
                                                         associated_data)
    
    # 演示 ChaCha20-Poly1305 加密
    cha_cha_nonce , cha_cha_ciphertext = demo_encryption_process("ChaCha20-Poly1305" ,
                                                               cha_cha_256 ,
                                                               small_data ,
                                                               associated_data)
    
    # 5. 解密验证
    aes_decrypted = aes_gcm_256.decrypt(aes_nonce , aes_ciphertext , associated_data)
    cha_cha_decrypted = cha_cha_256.decrypt(cha_cha_nonce , cha_cha_ciphertext , associated_data)
    print(f"\nAES-GCM 解密结果: {aes_decrypted.decode()}")
    print(f"ChaCha20-Poly1305 解密结果: {cha_cha_decrypted.decode()}")
    
    # 6. 篡改测试
    tampering("AES-GCM" , aes_gcm_256 , aes_nonce , aes_ciphertext , associated_data)
    tampering("ChaCha20-Poly1305" , cha_cha_256 , cha_cha_nonce , cha_cha_ciphertext , associated_data)


if __name__ == "__main__":
    main_encryption_decryption()

ChaCha20-Poly1305 与 AES-CBC、AES-GCM的特性对比

ChaCha20-Poly1305 与 AES-CBC、AES-GCM 的特性对比
ChaCha20-Poly1305 与 AES-CBC、AES-GCM 的特性对比

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 核心概念
  • 应用场景
  • ChaCha20 使用代码示例以及与 AES 的性能对比
  • ChaCha20-Poly1305 与 AES-CBC、AES-GCM的特性对比
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档