key 字节数组长度引起的 aes-128 256 选择

本文探讨了在C++接口中,由于使用了长度为32的KEY字符串调用AES-128,尽管实际仅利用了前16位,导致与预期AES-256加密结果不符的情况。文章分析了AES加密原理,并提供了Python和Java中的示例代码,揭示如何正确设置key长度以匹配AES-256。
摘要由CSDN通过智能技术生成

【key 字节数组长度引起的 aes-128 256 选择】

对接 C++ 某加解密接口

// 定义了 KEY 是一个长度为 32 的字符串
#define KEY "01234567890123456789012345678901"

// 其中调用了
EVP_aes_128_cfb128()

AES is based on a design principle known as a substitution–permutation network, and is efficient in both software and hardware.[9] Unlike its predecessor DES, AES does not use a Feistel network. AES is a variant of Rijndael, with a fixed block size of 128 bits, and a key size of 128, 192, or 256 bits. By contrast, Rijndael per se is specified with block and key sizes that may be any multiple of 32 bits, with a minimum of 128 and a maximum of 256 bits.

维基百科 - AES

根据维基百科里的说法,AES 的 key size 只支持 128 bits, 192 bits, 256 bits

KEY 字符串长度key size
16128 bits
24192 bits
32256 bits

对方提供的对接接口中的 KEY 的长度是 32 理应对应 aes-256 却调用了 aes-128,实际只利用了前 16 个字符,因为本身 32 大于 16 调用 aes-128 的时候会只读前面的 16,而且能读到,便没有报错。

对接接口么,一般就直接把 KEY 复制过来传进去了,但在其他语言中越是封装好的库,越有一些自动的操作,比如,根据 KEY 的长度,自动选择 aes-128 还是 aes-256,因为传的 KEY 是 32 个字符,底层库自动选择了 aes-256,怎么测试,结果都对不上,属实郁闷。

在 Python 中

import base64
from Crypto.Cipher import AES

# 注意这里是长度为 32 的 key,最终截取了前 16 才和 C++ 那边儿出来一样的结果
key: bytes = '01234567890123456789012345678901'[:16].encode('utf-8')
iv: bytes = '0123456789012345'.encode('utf-8')


def encrypt(content: bytes) -> bytes:
    """
    加密内容
    :param content: 要被加密的数据
    :return: 加密后的数据
    """

    # 因为 key 的长度是 32,这里 new 出来的就是 aes-256 的
    # segment_size 的 128 是 cfb-128 不是 aes-128 里的 128
    aes = AES.new(key, AES.MODE_CFB, iv, segment_size=128)
    return aes.encrypt(content)


if __name__ == '__main__':
    content: bytes = 'lixifun'.encode('utf-8')
    base64.b64encode(encrypt(content))

如要在 windows 下运行,需要 pip install pycryptodome

在 Java 中

import org.junit.jupiter.api.Test;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.util.Base64;

public class AesCfbTest {

    // 这里虽然也是 32 但是在下面 new SecretKeySpec 的时候可以解决从哪里读,读多长的问题
    private static final byte[] KEY = "01234567890123456789012345678901"
                                        .getBytes(StandardCharsets.UTF_8);

    // 当然同样也可以使用 substring(0, 16) 的方式截取一下
    private static final byte[] KEY = "01234567890123456789012345678901"
                                        .substring(0, 16)
                                        .getBytes(StandardCharsets.UTF_8);

    private static final byte[] IV = "0123456789012345".getBytes(StandardCharsets.UTF_8);

    @Test
    void encryptTest() {
        byte[] content = "lixifun".getBytes(StandardCharsets.UTF_8);
        byte[] res = encrypt(content);
        System.out.println(new String(Base64.getEncoder().encode(res)));
    }

    public static byte[] encrypt(byte[] content) {
        try {
            Cipher aseCfb = Cipher.getInstance("AES/CFB/NoPadding");

            // Java 里可以设定 offset 和 length 可以解决 key 长度的问题
            SecretKeySpec keySpec = new SecretKeySpec(KEY, 0, 16, "AES");

            IvParameterSpec ivSpec = new IvParameterSpec(IV);
            aseCfb.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            return aseCfb.doFinal(content);

        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }
}

参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lixifun

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值