You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Java与Delphi的AES加密结果不一致?

问题分析与修正方案

你的Delphi代码和Java代码在几个核心环节上不匹配,导致加密结果不一致,下面是具体问题和修复方法:

1. 密钥处理方式完全错误

Java代码中,你把十六进制字符串7823C4E346336621CB73868429D8CC93直接转换成字节数组作为AES密钥(没有经过任何密钥派生);但Delphi的LockBox中,你直接把这个十六进制字符串当作密码传入,LockBox默认会对密码执行**密钥派生算法(比如PBKDF2)**生成密钥,这和Java的逻辑完全不同。

你需要把十六进制密钥字符串转换成字节数组,然后直接设置给LockBox的密钥,而不是用密码属性。

2. 填充模式不匹配

Java代码明确使用了AES/ECB/NoPadding,但LockBox默认会启用PKCS#5/PKCS#7填充,这会导致加密时自动补全数据到块大小,和Java的无填充逻辑冲突。

3. 加密结果的编码方式错误

Java返回的是加密后的原始字节数组,最终转成十六进制字符串;而Delphi的EncryptAnsiString默认返回的是Base64编码的密文,你直接把这个Base64字符串转成ANSI字节,自然和Java的原始字节结果不一样。


修正后的Delphi代码

首先修正十六进制转字节数组的函数(确保和Java逻辑一致)

function HexToByteArr(const HexStr: string): TArray<Byte>;
var
  I: Integer;
  HexPair: string;
begin
  SetLength(Result, Length(HexStr) div 2);
  for I := 0 to (Length(HexStr) div 2) - 1 do
  begin
    HexPair := Copy(HexStr, (I * 2) + 1, 2);
    Result[I] := StrToInt('$' + HexPair);
  end;
end;

function ByteArrToHex(const Bytes: TArray<Byte>): string;
const
  HexChars: array[0..15] of Char = ('0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F');
var
  I: Integer;
  B: Byte;
begin
  SetLength(Result, Length(Bytes) * 2);
  for I := 0 to Length(Bytes) - 1 do
  begin
    B := Bytes[I];
    Result[I*2 + 1] := HexChars[B shr 4];
    Result[I*2 + 2] := HexChars[B and $0F];
  end;
end;

修正加密函数,匹配Java的逻辑

function EncryptData(const DataBytes: TArray<Byte>; const KeyBytes: TArray<Byte>): TArray<Byte>;
var
  Codec: TCodec;
  CipherStream: TMemoryStream;
  InputStream: TMemoryStream;
begin
  Codec := TCodec.Create(nil);
  InputStream := TMemoryStream.Create;
  CipherStream := TMemoryStream.Create;
  try
    // 初始化加密库
    Codec.CryptoLibrary := TCryptographicLibrary.Create(Codec);
    Codec.BlockCipherId := Format(AES_ProgId, [128]);
    Codec.ChainModeId := ECB_ProgId;
    // 设置无填充,和Java的NoPadding匹配
    Codec.Padding := TSymmetricPadding.pNone;
    // 直接使用原始字节作为密钥,不做派生
    Codec.InitFromBinaryKey(KeyBytes);

    // 写入待加密的数据
    InputStream.WriteBuffer(DataBytes[0], Length(DataBytes));
    InputStream.Position := 0;

    // 执行加密
    Codec.EncryptStream(InputStream, CipherStream);
    CipherStream.Position := 0;

    // 读取加密后的原始字节
    SetLength(Result, CipherStream.Size);
    CipherStream.ReadBuffer(Result[0], CipherStream.Size);
  finally
    CipherStream.Free;
    InputStream.Free;
    Codec.Free;
  end;
end;

调用示例(和Java的测试逻辑完全对齐)

procedure TestAES;
var
  _DataHex: string;
  _DataBytes: TArray<Byte>;
  _KeyHex: string;
  _KeyBytes: TArray<Byte>;
  _EncryptedBytes: TArray<Byte>;
  _EncryptedHex: string;
begin
  _DataHex := '8450696E670454696D650013323031382D31322D30352031353A34363A343700';
  _DataBytes := HexToByteArr(_DataHex);

  _KeyHex := '7823C4E346336621CB73868429D8CC93';
  _KeyBytes := HexToByteArr(_KeyHex);

  _EncryptedBytes := EncryptData(_DataBytes, _KeyBytes);
  _EncryptedHex := ByteArrToHex(_EncryptedBytes);
  
  // 现在_EncryptedHex应该和Java的结果一致:DFCC3CB95BEA276E6833207316B008DA6D219AA36A81AD6E75800BC898AE43B8
  ShowMessage(_EncryptedHex);
end;

关键修正点总结

  • 密钥:直接使用十六进制转字节后的原始密钥,禁用LockBox的密码派生逻辑
  • 填充:设置为pNone,和Java的NoPadding匹配
  • 结果处理:直接获取加密后的原始字节,再转十六进制,而不是使用Base64编码的输出

内容的提问来源于stack exchange,提问作者Edijs Kolesnikovičs

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:00:59