算法 · 2025年8月11日

Delphi使用CnPack的CnSM4封装实现SM4加密

之前写过一篇文章《Delphi实现SM4国密算法》,使用的是网上找到的代码,修复了几个BUG;这次准备使用CnPack的算法库来实现一下;算法库比较全,日常中需要使用的算法基本都有,但调用有点复杂,所以一般都需要根据自己的需求来简单封装一下;代码比较简单,直接贴了~需要使用高版本Delphi编译器

文件的加密方式为CTR,原因是CBC不能并行计算,对于大文件来说,效率比较低;

unit uSM4_LG;

{
 使用CnPack的CnSM4及CnPemUtils单元进行封装;
 实现字符串加密(CBC)、文件加密(CTR);
 字符串填充均采用PKCS5
}

interface

uses
  System.SysUtils, system.Classes, CnSM4, CnPemUtils;

// SM4/CBC/PKCS5 字符串加密
function SM4Encrypt(sInput, sKey, sIV :string):string;
// SM4/CTR/PKCS5 文件加密
function SM4EncryptFile(sSrcFile:string; sDesFile:string; sKey, sIV:string):Boolean;


implementation

function SM4Encrypt(sInput, sKey, sIV :string):string;
var
  _sStr:string;
  _BytesIn, _BytesKey, _BytesIV, _BytesOut : TBytes;
  _Len: Integer;
begin
  try
    try
      Result := '';
      //均按照UTF8进行解析
      with TEncoding.UTF8 do
      begin
        _BytesIn  := GetBytes(sInput);
        _BytesKey := GetBytes(sKey);
        _BytesIV  := GetBytes(sIV);
      end;
      //PKCS5填充
      BytesAddPKCS5Padding(_BytesIn);
      //SM4加密
      _BytesOut := SM4EncryptCbcBytes(_BytesKey, _BytesIV, _BytesIn);
      //输出16进制格式字符串
      _Len := System.Length(_BytesOut);
      SetLength(Result, 2*_Len);
      BinToHex(@_BytesOut[0], PWideChar(Result), _Len);
    except
      on E:Exception do
      begin
        //
      end;
    end;
  finally
    SetLength(_BytesIn, 0);
    SetLength(_BytesKey, 0);
    SetLength(_BytesIV, 0);
    SetLength(_BytesOut, 0);
  end;
end;

function SM4EncryptFile(sSrcFile:string; sDesFile:string; sKey, sIV:string):Boolean;
var
  _FileStream: TFileStream;
  _BytesIn, _BytesKey, _BytesIV, _BytesOut : TBytes;
begin
  try
    try
      Result := False;
      //将文件读取到Tbytes _BytesIn中
      _FileStream := TFileStream.Create(sSrcFile, fmOpenRead);
      try
        SetLength(_BytesIn, _FileStream.Size);
        _FileStream.Read(_BytesIn, _FileStream.Size);
      finally
        _FileStream.Free;
      end;
      //均按照UTF8进行解析
      with TEncoding.UTF8 do
      begin
        _BytesKey := GetBytes(sKey);
        _BytesIV  := GetBytes(sIV);
      end;
      //PKCS5填充
      BytesAddPKCS5Padding(_BytesIn);
      //SM4加密
      _BytesOut := SM4EncryptCtrBytes(_BytesKey, _BytesIV, _BytesIn);
      //将Tbytes _BytesOut中的数据写入文件中
      _FileStream := TFileStream.Create(sDesFile, fmCreate);
      try
        _FileStream.Write(_BytesOut, System.Length(_BytesOut));
      finally
        _FileStream.Free;
      end;
      Result := True;
    except
      on E:Exception do
      begin
        //
      end;
    end;
  finally
    if Assigned(_FileStream) then _FileStream.Free;
    SetLength(_BytesIn, 0);
    SetLength(_BytesKey, 0);
    SetLength(_BytesIV, 0);
    SetLength(_BytesOut, 0);
  end;
end;

end.
Pascal