cnpack / cnvcl

CnPack VCL Components

Home Page:http://www.cnpack.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

请教:SM4使用java中的byte数组加密结果不一致

Yang-Ya-Chao opened this issue · comments

commented

java的key: byte[] keyBytes={17,34,79,88,-120,16,64,56,40,37,121,81,-53,-35,85,102}
加密模式:ECB
填充模式:PKCS7
请教怎么使用cnvcl的SM4模块加密呢
使用如下代码加密的结果与java不一致:
--CNVCL加密代码
const
TmpKeytmp: array[0..15] of Byte =
(17, 34, 79, 88, 255 - 120, 16, 64, 56, 40,
37, 121, 81, 255 - 53, 255 - 35, 85, 102);
procedure TFormCrypt.btnSm4Click(Sender: TObject)
function ArraytoTbytes(bs: array of byte): Tbytes;
begin
setlength(Result, Length(bs));
Move(bs[0], Result[0], Length(bs));
end;
var
Output: AnsiString;
Len: Integer;
TmpSm4Iv: array[0..15] of Byte;
IvStr: AnsiString;
s: ansistring;
m, n: string;
KeyBytes, ResBytes, DataBytes: TBytes;
begin
Len := Length(AnsiString(MMSm4.Text));
if Len < 16 then
Len := 16
else
Len := (((Len - 1) div 16) + 1) * 16;
SetLength(Output, Len);
ZeroMemory(@(Output[1]), Len);
KeyBytes := ArraytoTbytes(TmpKeytmp);//TEncoding.Default.GetBytes(MMKey.Text);
DataBytes := TEncoding.Default.GetBytes(MMSm4.Text);
BytesAddPKCS7Padding(DataBytes, SM4_BLOCKSIZE);
ResBytes := SM4EncryptEcbBytes(KeyBytes, DataBytes);
MMCode.Text := BytesToHex(ResBytes);
end;

把Java的写法以及待加密的明文和各自加的密文都贴出来吧,问题很可能在编码上。

commented

这休假休的可够长的……

commented
commented

抱歉哈,没有关注iss消息,这个是接到的对方文档说明
加密说明
1、整个接口的 XML 以密文传输,适用国密 sm4 国家已开放算法,提供的是 java 加
密,解
密 jar,如果是 java 后台在引入 jar 后可直接调用。
2、加密调用 common-endecrypt-2.0.0.jar 中的 Sm4HexEn.encode("明文")方法;
3、解密调用 common-decrypt-2.0.0.jar 中的 Sm4HexDe.decode("密文");方法
4、如果非 java 程序进行加解密需自行实现,有两种方式【自行实现】或【将 JAR 转
DLL】
算法使用 sm4 的 ECB 模式
算法密钥 byte[] keyBytes = {
17, 34, 79, 88, -120, 16, 64, 56, 40, 37, 121, 81, -53, -35, 85, 102 };
自行实现算法时不要调用 Base64 编码,需直接将加密结果转成 16 进制
5,如果是调用动态库,可将 jar 包转成 DLL 来调用,这样最简单

commented

新建文本文档.txt
密文跟明文我放这里了,这个是java给的示例

不同端的分组加密考虑的因素有很多:
1、每块的加密算法(DES/AES/SM4等)
2、数据分块的每块大小(128/192/256等)
3、块与块之间的运算模式(ECB/CBC等)
4、数据不满足整数块时如何填充(PKCS1/PKCS7等)
5、密文是否要转变成可读的(Hex/Base64等)
6、明文如果是字符串,加密时还有字符编码问题(UTF8/UTF16/Ansi等)
但凡有一处和所需的不一样,加密出来的结果就对不上号,还是得挨个去研究。

你贴的内容里,1/2/3/4/5都确定了(虽然4对方文档里没说是PKCS7,但你一楼写了用PKCS7,就算它是)
但6你用的TEncoding.Default.GetBytes,我估计Java里常用的是UTF8,可以改成UTF8编码试一试。

总体顺序的确是先文本转UTF8的Bytes,再BytesAddPKCS7Padding,再SM4EncryptEcbBytes,再BytesToHex,
解密则是倒过来,先HexToBytes,再SMDecryptEcbBytes,再BytesRemovePKCS7Padding,再UTF8解码。

commented

好勒谢谢大哥,我试试

commented

改成utf8的话,密文长度是一模一样的了,但是结果还是对不上,思路顺序应该是没问题的,其他的三方的我也对过都没问题,他这个密文我对不上,有可能是他们自己写的不是标准的sm4吧,其他原因我找不出来了

刚看你代码还有一个要注意的点,Java的byte数组是有符号的所以对方提供的密钥有负值,比如-120,而我们加解密的Key的array[] of Byte是无符号的,你用255-120代替-120,这一点你那边能否确认正确?

commented

不能确认是不是这个原因引起的,d没有负数的数组,咨询过好多人说是255-120 与-120是一致的,但是我自己并不确认,而且也没法确认是不是跟java的区别是这里造成的,算了不纠结了,谢谢大哥,sm4的思路搞明白就行了,主要是这个加密我之前没有对接出来有点梗着,所以来问问,应该是其他原因影响,而不是sm4这个加密代码本身的问题

var
B: Byte;
begin
B := Byte(-120);
Caption := IntToStr(B);

得到的结果是136,也就是说应该是256-120,而不是255。

commented