使用 SynCrypto 的 AES 加密问题

Issues with AES Encryption using SynCrypto

我正在尝试使用 SynCrypto.pas 和 AES 256 加密文件,但如果我尝试加密大小不是 16 字节倍数的文件,它会失败。解密数据包含垃圾。

示例:

这是我的加密代码

procedure TForm1.Button1Click(Sender: TObject);
var
  A: TAES;
  Key: TSHA256Digest;
  s, B: TAESBlock;
  ks: integer;
  st: RawByteString;
  InStream, OutStream: TFileStream;
  SuperNo, TheSize, StreamSize: Int64;

begin
  InStream := TFileStream.Create('test.txt', fmOpenRead);
  OutStream := TFileStream.Create('out.txt', fmCreate);

  InStream.Position := 0;
  OutStream.Position := 0;
  st := '1234essai';
  ks := 256;
  SHA256Weak(st, Key);
  A.EncryptInit(Key, ks);
  StreamSize := InStream.Size;
  while InStream.Position < StreamSize do
  begin
    TheSize := StreamSize - InStream.Position;
    if TheSize < 16 then
    begin
      SuperNo := StreamSize - InStream.Position;

    end
    else
    begin
      SuperNo := 16;
    end;
    InStream.ReadBuffer(s, SuperNo);

    A.Encrypt(s, B);
    OutStream.WriteBuffer(B, SuperNo);
  end;
  A.Done;
  ShowMessage('Finish');
  InStream.Free;
  OutStream.Free;
end;

这是我的解密码

procedure TForm1.Button2Click(Sender: TObject);
var
  A: TAES;
  Key: TSHA256Digest;
  s, B: TAESBlock;
  ks: integer;
  st: RawByteString;
  InStream, OutStream: TFileStream;
  SuperNo, TheSize, StreamSize: Int64;

begin
  InStream := TFileStream.Create('out.txt', fmOpenRead);
  OutStream := TFileStream.Create('in.txt', fmCreate);

  InStream.Position := 0;
  OutStream.Position := 0;
  st := '1234essai';
  ks := 256;
  SHA256Weak(st, Key);
  A.DecryptInit(Key, ks);
  StreamSize := InStream.Size;
  while InStream.Position < StreamSize do
  begin
    TheSize := StreamSize - InStream.Position;
    if TheSize < 16 then
    begin
      SuperNo := StreamSize - InStream.Position;

    end
    else
    begin
      SuperNo := 16;
    end;
    InStream.ReadBuffer(s, SuperNo);

    A.Decrypt(s, B);

    OutStream.WriteBuffer(B, SuperNo);
  end;
  A.Done;
  ShowMessage('Finish');
  InStream.Free;
  OutStream.Free;
end;

使用Delphi XE7。

AES 是一种块密码 算法。这意味着它适用于 AES 的 16 字节大小的块。因此,如果您的数据不适合 16 字节块(您的文本就是这种情况),则需要使用 padding

与其重新发明轮子,引入错误,不如依赖现有的padding算法。你应该添加一个block chaining mode。目前您使用的默认算法是 ECB,众所周知它很弱,因为它既不使用链接模式也不使用初始化向量 (IV)。

SynCrypto 单元包含一个安全的块链接模式,如 CFB 和 PKCS7 填充,所以你可以写:

var inp,out: RawByteString;
begin
  // encryption:
  inp := StringFromFile('in.txt');
  out := TAESCFB.SimpleEncrypt(inp,'privatekey',true,true);
  FileFromString(out,'out.txt');
  // or in a single line:
  FileFromString(TAESCFB.SimpleEncrypt(StringFromFile('in.txt'),'privatekey',true,true),'out.txt');
  // decryption
  inp := StringFromFile('out.txt');
  out := TAESCFB.SimpleEncrypt(inp,'privatekey',false,true);
  FileFromString(out,'in.txt');
end;

以上代码安全且快速,将在提供的 'privatekey' 上使用 SHA-256 生成二进制密钥,如果您 CPU 支持,将使用 AES-NI 硬件指令。您可以使用另一种链接模式,只需将 TAESCFB class 名称更改为另一种可用类型即可。