【问题标题】:Crypt in DelphiXE7 with TDCP_rijndael AES/CBC/NoPadding algorithm and decrypt in Java使用 TDCP_rijndael AES/CBC/NoPadding 算法在 DelphiXE7 中加密并在 Java 中解密
【发布时间】:2018-03-07 08:03:40
【问题描述】:

我有问题。我想在 Delphi 程序中加密文本并在 java 中解密。我正在使用 AES/CBC/NoPadding 来做到这一点,但 java 程序不能很好地解密文本。 下一步是使用 PKCS5Padding,所以有人也可以回答这个问题,很高兴!

德尔福代码:

var
    Cipher: TDCP_rijndael;
    Key: string;
    DataIn, DataOut: System.TArray<System.Byte>; 
begin
    Key := '0123456789012345';

    DataIn := nil;
    DataIn := TEncoding.UTF8.getbytes('SakisSakisSakisa');

    DataOut := nil;
    SetLength(DataOut, high(DataIn) + 1);
    Cipher := TDCP_rijndael.create(nil);
    Cipher.Algorithm := 'AES';
    Cipher.Init(Key[1], 128, nil);
    Cipher.EncryptCBC(DataIn[0], DataOut[0], high(DataIn) + 1);
    Cipher.Free;

    With TMemoryStream.create do begin
      Write(DataOut[0], length(DataOut));
      SaveToFile('c:\temp\encryption\sakisEnc.txt');
      Free;
    end;

DataIn 具有以下字节: 83,97,107,105,115,83,97,107,105,115,83,97,107,105,115,97 此代码生成具有以下字节的加密字节数组 DataOut: 3,207,105,252,118,38,28,145,89,77,107,8,181,205,190,165

现在是 Java 代码:

Path path = null;
String encryptionKey = null;
Cipher cipher = null;
SecretKeySpec key = null;
byte[] enc1;


path = FileSystems.getDefault().getPath("c:\\temp\\encryption\\SakisEnc.txt", "");
cipherText = Files.readAllBytes(path);

encryptionKey = "0123456789012345";   
cipher = Cipher.getInstance("AES/CBC/NoPadding");   
key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encryptionKey.getBytes()));
dec1 = cipher.doFinal(cipherText);

dec1 字节数组应该具有与 Delphi DataIn 代码相同的字节 83,97,107,105,115,83,97,107,105,115,83,97,107,105,115,97 但它包含其他内容。

我真的无法理解我做错了什么..... 提前谢谢!

【问题讨论】:

  • 不是问题,但是使用Length(...)而不是high(...) + 并使用TFileStream而不是TMemoryStream来写入文件。

标签: java delphi aes


【解决方案1】:
function Decrypt(enc_Text, Pass: String): String;
var
  ciph: TCipher_Rijndael;
  APass, AIV: RawByteString;
  AData: Binary;
  i: Integer;
  AText, passBytes, passb2, iv2:TBytes;
begin
  ciph := TCipher_Rijndael.Create();
  try
    try
      AText :=TNetEncoding.Base64.DecodeStringToBytes(enc_Text);
      passBytes:=Tencoding.ASCII.GetBytes(Pass);
      passb2:=TBytes.Create(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
      for I := 0 to length(passBytes) do begin
         passb2[i]:=passBytes[i];
      end;
      iv2:=TBytes.Create(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0);
      for I := 0 to length(iv2) do begin
         iv2[i]:=passBytes[i];
      end;
      APass:=Binary(passb2);
      AIV:= Binary(iv2);
      ciph.Init(APass, AIV);
      Result:=ciph.DecodeBinary(Convert_RB(AText));
    finally
      ciph.Free;
      ProtectBinary(AData);
      ProtectBinary(APass);
    end;
  except
    Result := '';
  end;
end;

【讨论】:

  • 虽然这段代码可能会解决问题,包括解释如何以及为什么解决问题将真正有助于提高您的帖子质量,并可能导致更多的赞成票。请记住,您正在为将来的读者回答问题,而不仅仅是现在提出问题的人。
【解决方案2】:

好的,经过尝试、阅读、测试,我成功了!

德尔福代码:

var
  Cipher: TDCP_rijndael;
  Key: System.TArray<System.Byte>;
  DataIn, DataOut, iv: System.TArray<System.Byte>; // array of byte;

  j: integer;
  i :integer;
  k :integer;
  s: string;

  sText :AnsiString;
  sTextLen :integer;
  paddingByte :string;
begin
  Key := TEncoding.UTF8.getbytes('0123456789012345');
  Iv := TEncoding.UTF8.getbytes('0123456789012345');

  DataIn := TEncoding.UTF8.getBytes(memo1.Text);
  //PKCS5Padding
  sTextLen := high(DataIn) + 1;
  i := 16 - (sTextLen mod 16);
  if i <= 16 then begin
    k := high(DataIn) + 1;
    setLength(DataIn, sTextLen + i);
    for j := k to high(DataIn) do begin
      DataIn[j] := i;
    end;
  end;

  //Encrypt.
  DataOut := nil;
  SetLength(DataOut, high(DataIn) + 1);
  Cipher := TDCP_rijndael.create(nil);
  Cipher.Algorithm := 'AES';
  Cipher.Init(Key[0], length(Key) * 8, Iv);
  Cipher.EncryptCBC(DataIn[0], DataOut[0], high(DataIn) + 1);
  Cipher.Free;

  //Save to file
  With TMemoryStream.create do begin
    Write(DataOut[0], length(DataOut));
    SaveToFile('c:\temp\encryption\sakisEnc.txt');
    Free;
  end;

Java 代码: 在 java 代码中,delphis 的 Iv 与加密密钥相同。所以我将加密密钥传递给: new IvParameterSpec(encryptionKey.getBytes("UTF-8"))

String encryptionKey = null;
Cipher cipher = null;
SecretKeySpec key = null;
byte[] enc1;
byte[] dec1;

path = FileSystems.getDefault().getPath("c:\\temp\\encryption\\SakisEnc.txt", "");
cipherText = Files.readAllBytes(path);

encryptionKey = "0123456789012345";
cipher = Cipher.getInstance("AES/CBC/PKCS5Padding") ;
key = new SecretKeySpec(encryptionKey.getBytes("UTF-8"), "AES");
cipher.init(Cipher.DECRYPT_MODE, key, new IvParameterSpec(encryptionKey.getBytes("UTF-8")));
dec1 = cipher.doFinal(cipherText);

【讨论】:

    【解决方案3】:

    明显的区别在于您的密钥。在您的 Delphi 代码中,您使用的是 UTF-16 编码的密钥,但在您的 Java 代码中,您使用的是 UTF-8 编码的密钥。

    在您的 Java 代码中,您被库强制传递字节作为键。不幸的是,Delphi 库更加宽容,并导致您陷入传递字符串的愚蠢行为。

    我会为您的 Delphi 代码使用以下代码:

    var
      Key: TBytes;
    ....
    Key := TEncoding.UTF8.GetBytes('0123456789012345');
    

    然后将Key[0] 传递给Cipher.Init

    【讨论】:

    • 但是现在的输出不一样了吧?另外,在你的 Delphi 代码中,你在哪里指定没有填充,或者是隐含的?
    • 不需要填充。 “SakisSakisSakisa”字符串具体有 16 个字节。
    • 我不确定是不是这样。不同的输出意味着我们至少纠正了一个错误,即对密钥进行编码。但谁知道其他差异在哪里。
    • 如果我是你,我会尝试对具有已知输出的文本进行编码。有很多这样的例子可用。然后,它会告诉您要查看哪些代码。
    猜你喜欢
    • 2014-08-15
    • 2021-03-05
    • 1970-01-01
    • 2017-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多