JuneAndGreen / sm-crypto

国密算法js版
MIT License
954 stars 254 forks source link

sm4密钥 #108

Open marsChenxin opened 8 months ago

marsChenxin commented 8 months ago

我发现有些sm4加密解密的密钥有点问题,例如我用A密钥加密后,改动A密钥的最后一位,一样可以解密出来,请问是不是我生成的密钥有什么问题

marsChenxin commented 8 months ago

我提供一个密钥例子:5cP1J0n032B02g27e4Mw08W28wa7Hh3P , 最后一位改成L,也可以解密5cP1J0n032B02g27e4Mw08W28wa7Hh3L

invinbg commented 8 months ago

我也有同样的问题,原因是hexToArray方法的问题,因为给的密钥不是十六进制,hexToArray方法的parseInt(str.substr(i, 2)会返回 NaN,建议在hexToArray方法内先判断 str是否为十六进制字符串

changhr2013 commented 8 months ago

目前这个库的 sm4 算法只能接收 array 或者 Hex 格式的 sm4 密钥,因为你传入的是字符串,所以库默认会认为你传入的是 Hex 字符串

由于 Hex 的表示范围只有 0 1 2 3 4 5 6 7 8 9 a b c d e f,你的密钥中含有 Hex 没办法表示的字母,所以转换时已经出错了。

超出范围的表示在 hexToArray() 方法中都会被转换为 NaN 或者高位数字,运算时 NaN 会被作为 0x00 处理。

因此你上面的密钥 5cP1J0n032B02g27e4Mw08W28wa7Hh3P5cP1J0n032B02g27e4Mw08W28wa7Hh3L 在运算时都会被转换为 5c00000032b00227e400080008a70003 处理,末尾的 3P3L 转换后的结果都是 0x03,所以使用时没有区别。

5c  P1  J0  n0  32 B0 2g 27 e4 Mw  08 W2  8w a7 Hh  3P
↓   ↓   ↓   ↓   ↓  ↓  ↓  ↓  ↓  ↓   ↓  ↓   ↓  ↓  ↓   ↓
5c  NaN NaN NaN 32 b0 02 27 e4 NaN 08 NaN 08 a7 NaN 03
↓   ↓   ↓   ↓   ↓  ↓  ↓  ↓  ↓  ↓   ↓  ↓   ↓  ↓  ↓   ↓
5c  00  00  00  32 b0 02 27 e4 00  08 00  08 a7 00  03

所以如果你将末尾字符 P 更改为 Hex 范围内(0 1 2 3 4 5 6 7 8 9 a b c d e f)的字符,你的加密结果就会随之会发生变化,解密也会发现无法解密了。

比如你可以将密钥改为 5cP1J0n032B02g27e4Mw08W28wa7Hh3f,你就会发现结果不再一样了。


sm4 算法要求使用 16 字节的随机数作为密钥,你可以利用 crypto 模块直接生成 16 字节的密钥,然后使用 Hex 编码后得到一个合法的 Hex 格式密钥。

import crypto from "crypto";

// 生成随机数密钥
let randomKey = arrayToHex(Array.from(crypto.randomBytes(16).values()));

console.log(randomKey);

输出结果:

12605159ec0775f70a4dd08561a3dbff
marsChenxin commented 8 months ago

我也有同样的问题,原因是hexToArray方法的问题,因为给的密钥不是十六进制,hexToArray方法的parseInt(str.substr(i, 2)会返回 NaN,建议在hexToArray方法内先判断 str是否为十六进制字符串

感谢

marsChenxin commented 8 months ago

目前这个库的 sm4 算法只能接收 array 或者 Hex 格式的 sm4 密钥,因为你传入的是字符串,所以库默认会认为你传入的是 Hex 字符串

由于 Hex 的表示范围只有 0 1 2 3 4 5 6 7 8 9 a b c d e f,你的密钥中含有 Hex 没办法表示的字母,所以转换时已经出错了。

超出范围的表示在 hexToArray() 方法中都会被转换为 NaN 或者高位数字,运算时 NaN 会被作为 0x00 处理。

因此你上面的密钥 5cP1J0n032B02g27e4Mw08W28wa7Hh3P5cP1J0n032B02g27e4Mw08W28wa7Hh3L 在运算时都会被转换为 5c00000032b00227e400080008a70003 处理,末尾的 3P3L 转换后的结果都是 0x03,所以使用时没有区别。

5c  P1  J0  n0  32 B0 2g 27 e4 Mw  08 W2  8w a7 Hh  3P
↓   ↓   ↓   ↓   ↓  ↓  ↓  ↓  ↓  ↓   ↓  ↓   ↓  ↓  ↓   ↓
5c  NaN NaN NaN 32 b0 02 27 e4 NaN 08 NaN 08 a7 NaN 03
↓   ↓   ↓   ↓   ↓  ↓  ↓  ↓  ↓  ↓   ↓  ↓   ↓  ↓  ↓   ↓
5c  00  00  00  32 b0 02 27 e4 00  08 00  08 a7 00  03

所以如果你将末尾字符 P 更改为 Hex 范围内(0 1 2 3 4 5 6 7 8 9 a b c d e f)的字符,你的加密结果就会随之会发生变化,解密也会发现无法解密了。

比如你可以将密钥改为 5cP1J0n032B02g27e4Mw08W28wa7Hh3f,你就会发现结果不再一样了。

sm4 算法要求使用 16 字节的随机数作为密钥,你可以利用 crypto 模块直接生成 16 字节的密钥,然后使用 Hex 编码后得到一个合法的 Hex 格式密钥。

import crypto from "crypto";

// 生成随机数密钥
let randomKey = arrayToHex(Array.from(crypto.randomBytes(16).values()));

console.log(randomKey);

输出结果:

12605159ec0775f70a4dd08561a3dbff

感谢感谢

CherryRum commented 7 months ago

目前这个库的 sm4 算法只能接收 array 或者 Hex 格式的 sm4 密钥,因为你传入的是字符串,所以库默认会认为你传入的是 Hex 字符串

由于 Hex 的表示范围只有 0 1 2 3 4 5 6 7 8 9 a b c d e f,你的密钥中含有 Hex 没办法表示的字母,所以转换时已经出错了。

超出范围的表示在 hexToArray() 方法中都会被转换为 NaN 或者高位数字,运算时 NaN 会被作为 0x00 处理。

因此你上面的密钥 5cP1J0n032B02g27e4Mw08W28wa7Hh3P5cP1J0n032B02g27e4Mw08W28wa7Hh3L 在运算时都会被转换为 5c00000032b00227e400080008a70003 处理,末尾的 3P3L 转换后的结果都是 0x03,所以使用时没有区别。

5c  P1  J0  n0  32 B0 2g 27 e4 Mw  08 W2  8w a7 Hh  3P
↓   ↓   ↓   ↓   ↓  ↓  ↓  ↓  ↓  ↓   ↓  ↓   ↓  ↓  ↓   ↓
5c  NaN NaN NaN 32 b0 02 27 e4 NaN 08 NaN 08 a7 NaN 03
↓   ↓   ↓   ↓   ↓  ↓  ↓  ↓  ↓  ↓   ↓  ↓   ↓  ↓  ↓   ↓
5c  00  00  00  32 b0 02 27 e4 00  08 00  08 a7 00  03

所以如果你将末尾字符 P 更改为 Hex 范围内(0 1 2 3 4 5 6 7 8 9 a b c d e f)的字符,你的加密结果就会随之会发生变化,解密也会发现无法解密了。

比如你可以将密钥改为 5cP1J0n032B02g27e4Mw08W28wa7Hh3f,你就会发现结果不再一样了。

sm4 算法要求使用 16 字节的随机数作为密钥,你可以利用 crypto 模块直接生成 16 字节的密钥,然后使用 Hex 编码后得到一个合法的 Hex 格式密钥。

import crypto from "crypto";

// 生成随机数密钥
let randomKey = arrayToHex(Array.from(crypto.randomBytes(16).values()));

console.log(randomKey);

输出结果:

12605159ec0775f70a4dd08561a3dbff

在这都能碰见你

changhr2013 commented 7 months ago

在这都能碰见你

哈哈,就这么几个常用库😂

dazhengs commented 1 month ago

sm4 其他模式怎么使用呢?除了CBC模式,其他模式加密的结构都是一样的。 let smKey = stringToHex(secretKey.value); console.log(smKey) encrypted = sm4.encrypt(inputText.value, smKey, { mode: selectedMode.value.toLowerCase(), output: 'utf-8', iv: 'fedcba98765432100123456789abcdef', }); 是我的代码有问题吗