Delphi开发系列(4):字符串加解密(国密算法)和压缩函数

    字符串国密加解密和字符串压缩工具函数。国密算法库有Java、Javascript、C语言多个实现,包括非对称加密算法SM2、摘要算法SM3和对称加密算法SM4,有Windows(32/64bit)、Linux、Android、iOS、Mac多个版本,可解决跨平台、跨语言之间的数据安全交互。目前Delphi只封装了字符串的加解密,流的加解密后续再封装。软件和相关资料获取:点击下载。

unit BaseUtils;

interface

uses
  System.Types, System.SysUtils, Data.DB,
  {$IFDEF MSWINDOWS} Winapi.Windows, {$ENDIF}
  {$IFDEF POSIX} Posix.Base, Posix.Fcntl, {$ENDIF}
  Classes, System.ZLib;

type
  TBaseUtils = class
  private
    cryptModule: HMODULE;
    function ByteStringToUnicode(const Source: RawByteString; CodePage: Integer): UnicodeString;
  public
    // SM2非对称加密算法
    function getKeyPair(var pubKeyHex: string; var prvKeyHex: string): Boolean;
    function sm2Encrypt(cipherMode: Integer; pubKeyHex: string; inText: string): string;
    function sm2Decrypt(cipherMode: Integer; prvKeyHex: string; inHex: string): string;
    function sm2EncryptASN1(pubKeyHex: string; inText: string): string;
    function sm2DecryptASN1(prvKeyHex: string; inHex: string): string;
    // SM3摘要算法
    function sm3Encrypt(inText: string): string;
    // SM4对称加密算法
    function sm4EcbEncrypt(Value: string; Key: string): string;
    function sm4EcbDecrypt(Value: string; Key: string): string;
    function sm4CbcEncrypt(Value: string; Key: string): string;
    function sm4CbcDecrypt(Value: string; Key: string): string;
  end;
var
  gFun : TBaseUtils;

const
  CONST_SM4_KEY     = '3C80757AA5A7BB7883B6EDAA43ACD74C';
  CONST_SM2_PIV_KEY = '3C80757AA5A7BB7883B6EDAA43ACD74C3AE6DBD8F14BFFBD6BE0C62BE39E2FF2';
  CONST_SM2_PUB_KEY = '049687C52DD3C56A7AEC44D658893CBE7C4A003AA556567EEB4D5C5E16D0A1AED231A706A412C43D107C4858461EDE9F5E5BF13F5D45FCAC98FF8184DEF72630CC';

implementation

uses
  ZLibConst, EncdDecd, System.NetEncoding, System.JSON;

Type
  Tsm4EcbDecryptToText = function(const inbuf: PAnsiChar; const keyHex: PAnsiChar): PAnsiChar; cdecl;
  Tsm4EcbEncryptFromText = function(const inbuf: PAnsiChar; const keyHex: PAnsiChar): PAnsiChar; cdecl;
  Tsm4CbcDecryptToText = function(const inbuf: PAnsiChar; const keyHex: PAnsiChar): PAnsiChar; cdecl;
  Tsm4CbcEncryptFromText = function(const inbuf: PAnsiChar; const keyHex: PAnsiChar): PAnsiChar; cdecl;
  KeyPair = array [0 .. 1] of PAnsiChar;
  PKeyPair = ^KeyPair;
  TgenerateKeyPair = function: PKeyPair; cdecl;
  Tsm2EncryptFromText = function(cipherMode: Integer; pubKeyHex: PAnsiChar; inText: PAnsiChar): PAnsiChar; cdecl;
  Tsm2DecryptToText = function(cipherMode: Integer; prvKeyHex: PAnsiChar; inHex: PAnsiChar): PAnsiChar; cdecl;
  Tsm2EncryptASN1FromText = function(pubKeyHex: PAnsiChar; inText: PAnsiChar): PAnsiChar;
  Tsm2DecryptASN1ToText = function(prvKeyHex: PAnsiChar; inHex: PAnsiChar): PAnsiChar;
  Tsm3EncryptFromText = function(Source: PAnsiChar): PAnsiChar; cdecl;

var
  sm4EcbDecryptToText: Tsm4EcbDecryptToText;
  sm4EcbEncryptFromText: Tsm4EcbEncryptFromText;
  sm4CbcDecryptToText: Tsm4CbcDecryptToText;
  sm4CbcEncryptFromText: Tsm4CbcEncryptFromText;
  generateKeyPair: TgenerateKeyPair;
  sm2EncryptFromText: Tsm2EncryptFromText;
  sm2DecryptToText: Tsm2DecryptToText;
  sm2EncryptASN1FromText: Tsm2EncryptASN1FromText;
  sm2DecryptASN1ToText: Tsm2DecryptASN1ToText;
  sm3EncryptFromText: Tsm3EncryptFromText;

function TBaseUtils.ByteStringToUnicode(const Source: RawByteString; CodePage: Integer): UnicodeString;
var
  wideLen: Integer;
  dw: DWORD;
begin
  if Length(Source) = 0 then
    begin
      Result := '';
      Exit;
    end;
  wideLen := UnicodeFromLocaleChars(CodePage, 0, PAnsiChar(Source), Length(Source), nil, 0);
  if wideLen = 0 then
    begin
      dw := GetLastError;
      raise EConvertError.Create('[StringToWideString] Could not get wide length of UTF-16 string. Error ' + IntToStr(dw) + ' (' + SysErrorMessage(dw) + ')');
    end;
  SetLength(Result, wideLen);
  wideLen := UnicodeFromLocaleChars(CodePage, 0, PAnsiChar(Source), Length(Source), PWideChar(Result), wideLen);
  if wideLen = 0 then
    begin
      dw := GetLastError;
      raise EConvertError.Create('[StringToWideString] Could not convert string to UTF-16. Error ' + IntToStr(dw) + ' (' + SysErrorMessage(dw) + ')');
    end;
end;

function TBaseUtils.getKeyPair(var pubKeyHex: string; var prvKeyHex: string): Boolean;
var
  keyHex: PKeyPair;
  ApubKeyHex: AnsiString;
  AprvKeyHex: AnsiString;
begin
  if @generateKeyPair <> nil then
    begin
      keyHex := generateKeyPair;
      AprvKeyHex := keyHex[0];
      ApubKeyHex := keyHex[1];
      pubKeyHex := string(ApubKeyHex);
      prvKeyHex := string(AprvKeyHex);
    end;
  Result := (pubKeyHex <> '') and (prvKeyHex <> '');
end;

function TBaseUtils.sm2Encrypt(cipherMode: Integer; pubKeyHex: string; inText: string): string;
var
  ApubKeyHex: AnsiString;
  AinText: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
begin
  try
    Result := '';
    if (pubKeyHex = '') or (inText = '') then
      begin
        Result := inText;
        Exit;
      end;
    if (inText <> '') and (@sm2EncryptFromText <> nil) then
      begin
        ApubKeyHex := AnsiString(pubKeyHex);
        AinText := AnsiString(inText);
        if inText = '' then
          aResult := ''
        else
          aResult := sm2EncryptFromText(cipherMode, PAnsiChar(ApubKeyHex), PAnsiChar(AinText));
        ipfSrc := Ord(TOSVersion.Platform);
        Result := IntToStr(ipfSrc) + string(aResult);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm2Encrypt', inText, pubKeyHex]), E);
      end;
  end;
end;

function TBaseUtils.sm2Decrypt(cipherMode: Integer; prvKeyHex: string; inHex: string): string;
var
  AprvKeyHex: AnsiString;
  AinHex: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
  ipfDst: Integer;
begin
  try
    Result := '';
    if (prvKeyHex = '') or (inHex = ' ') then
      begin
        Result := inHex;
        Exit;
      end;
    if (inHex <> '') and (@sm2DecryptToText <> nil) then
      begin
        ipfSrc := StrToInt(inHex[1]);
        ipfDst := Ord(TOSVersion.Platform);
        AprvKeyHex := AnsiString(prvKeyHex);
        AinHex := AnsiString(inHex.Substring(1));
        if AinHex = '' then
          aResult := ''
        else
          aResult := sm2DecryptToText(cipherMode, PAnsiChar(AprvKeyHex), PAnsiChar(AinHex));
        Result := string(aResult);
        // Linux压缩,Windows解压
        if (ipfSrc = Ord(pfLinux)) and (ipfDst = Ord(pfWindows)) then
          Result := UTF8ToString(aResult);
        // Windows压缩,Linux解压
        if (ipfSrc = Ord(pfWindows)) and (ipfDst = Ord(pfLinux)) then
          Result := ByteStringToUnicode(aResult, 936);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm2Decrypt', inHex, prvKeyHex]), E);
      end;
  end;
end;

function TBaseUtils.sm2EncryptASN1(pubKeyHex: string; inText: string): string;
var
  ApubKeyHex: AnsiString;
  AinText: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
begin
  try
    Result := '';
    if (pubKeyHex = '') or (inText = '') then
      begin
        Result := inText;
        Exit;
      end;
    if (inText <> '') and (@sm2EncryptASN1FromText <> nil) then
      begin
        ApubKeyHex := AnsiString(pubKeyHex);
        AinText := AnsiString(inText);
        if inText = '' then
          aResult := ''
        else
          aResult := sm2EncryptASN1FromText(PAnsiChar(ApubKeyHex), PAnsiChar(AinText));
        ipfSrc := Ord(TOSVersion.Platform);
        Result := IntToStr(ipfSrc) + string(aResult);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm2Encrypt', inText, pubKeyHex]), E);
      end;
  end;
end;

function TBaseUtils.sm2DecryptASN1(prvKeyHex: string; inHex: string): string;
var
  AprvKeyHex: AnsiString;
  AinHex: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
  ipfDst: Integer;
begin
  try
    Result := '';
    if (prvKeyHex = '') or (inHex = ' ') then
      begin
        Result := inHex;
        Exit;
      end;
    if (inHex <> '') and (@sm2DecryptASN1ToText <> nil) then
      begin
        ipfSrc := StrToInt(inHex[1]);
        ipfDst := Ord(TOSVersion.Platform);
        AprvKeyHex := AnsiString(prvKeyHex);
        AinHex := AnsiString(inHex.Substring(1));
        if AinHex = '' then
          aResult := ''
        else
          aResult := sm2DecryptASN1ToText(PAnsiChar(AprvKeyHex), PAnsiChar(AinHex));
        Result := string(aResult);
        // Linux压缩,Windows解压
        if (ipfSrc = Ord(pfLinux)) and (ipfDst = Ord(pfWindows)) then
          Result := UTF8ToString(aResult);
        // Windows压缩,Linux解压
        if (ipfSrc = Ord(pfWindows)) and (ipfDst = Ord(pfLinux)) then
          Result := ByteStringToUnicode(aResult, 936);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm2Decrypt', inHex, prvKeyHex]), E);
      end;
  end;
end;

function TBaseUtils.sm3Encrypt(inText: string): string;
var
  aValue: AnsiString;
  aResult: AnsiString;
begin
  try
    Result := '';
    if (inText = '') then
      begin
        Result := inText;
        Exit;
      end;
    if @sm3EncryptFromText <> nil then
      begin
        aValue := AnsiString(inText);
        if aValue = '' then
          aResult := ''
        else
          aResult := sm3EncryptFromText(PAnsiChar(aValue));
        Result := aResult;
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm3Encrypt', inText]), E);
      end;
  end;
end;

function TBaseUtils.sm4EcbEncrypt(Value: string; Key: string): string;
var
  aValue: AnsiString;
  aKey: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
begin
  try
    Result := '';
    if (Value = '') or (Key = '') then
      begin
        Result := Value;
        Exit;
      end;
    if @sm4EcbEncryptFromText <> nil then
      begin
        aValue := AnsiString(Value);
        aKey := AnsiString(Key);
        if aValue = '' then
          aResult := ''
        else
          aResult := sm4EcbEncryptFromText(PAnsiChar(aValue), PAnsiChar(aKey));
        ipfSrc := Ord(TOSVersion.Platform);
        Result := IntToStr(ipfSrc) + string(aResult);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm4EcbEncrypt', Value, Key]), E);
      end;
  end;
end;

function TBaseUtils.sm4EcbDecrypt(Value: string; Key: string): string;
var
  aValue: AnsiString;
  aKey: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
  ipfDst: Integer;
begin
  try
    Result := '';
    if (Value = '') or (Key = '') then
      begin
        Result := Value;
        Exit;
      end;
    if @sm4EcbDecryptToText <> nil then
      begin
        // 获取字符串来自于哪种操作系统
        ipfSrc := StrToInt(Value[1]);
        ipfDst := Ord(TOSVersion.Platform);
        aValue := AnsiString(Value.Substring(1));
        aKey := AnsiString(Key);
        if aValue = '' then
          aResult := ''
        else
          aResult := sm4EcbDecryptToText(PAnsiChar(aValue), PAnsiChar(aKey));
        Result := string(aResult);
        // Linux压缩,Windows解压
        if (ipfSrc = Ord(pfLinux)) and (ipfDst = Ord(pfWindows)) then
          Result := UTF8ToString(aResult);
        // Windows压缩,Linux解压
        if (ipfSrc = Ord(pfWindows)) and (ipfDst = Ord(pfLinux)) then
          Result := ByteStringToUnicode(aResult, 936);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm4EcbDecrypt', Value, Key]), E);
      end;
  end;
end;

function TBaseUtils.sm4CbcEncrypt(Value: string; Key: string): string;
var
  aValue: AnsiString;
  aKey: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
begin
  try
    Result := '';
    if (Value = '') or (Key = '') then
      begin
        Result := Value;
        Exit;
      end;
    if @sm4CbcEncryptFromText <> nil then
      begin
        aValue := AnsiString(Value);
        aKey := AnsiString(Key);
        if aValue = '' then
          aResult := ''
        else
          aResult := sm4CbcEncryptFromText(PAnsiChar(aValue), PAnsiChar(aKey));
        ipfSrc := Ord(TOSVersion.Platform);
        Result := IntToStr(ipfSrc) + string(aResult);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm4CbcEncrypt', Value, Key]), E);
      end;
  end;
end;

function TBaseUtils.sm4CbcDecrypt(Value: string; Key: string): string;
var
  aValue: AnsiString;
  aKey: AnsiString;
  aResult: AnsiString;
  ipfSrc: Integer;
  ipfDst: Integer;
begin
  try
    Result := '';
    if (Value = '') or (Key = '') then
      begin
        Result := Value;
        Exit;
      end;
    if @sm4CbcDecryptToText <> nil then
      begin
        // 获取字符串来自于哪种操作系统
        ipfSrc := StrToInt(Value[1]);
        ipfDst := Ord(TOSVersion.Platform);
        aValue := AnsiString(Value.Substring(1));
        aKey := AnsiString(Key);
        if aValue = '' then
          aResult := ''
        else
          aResult := sm4CbcDecryptToText(PAnsiChar(aValue), PAnsiChar(aKey));
        Result := string(aResult);
        // Linux压缩,Windows解压
        if (ipfSrc = Ord(pfLinux)) and (ipfDst = Ord(pfWindows)) then
          Result := UTF8ToString(aResult);
        // Windows压缩,Linux解压
        if (ipfSrc = Ord(pfWindows)) and (ipfDst = Ord(pfLinux)) then
          Result := ByteStringToUnicode(aResult, 936);
      end;
  except
    on E: Exception do
      begin
        gLogger.Exception(Format('%s%s%s', ['sm4CbcDecrypt', Value, Key]), E);
      end;
  end;
end;


var
  libSmCrypto : string;
  cryptModule : HMODULE;

  PubKey,PrvKey, sSource,sDest : string;
  cmdLine, strErrMsg : string;

constructor TBaseUtils.Create;
var
{$IFDEF MSWINDOWS}
  rs: TResourceStream;
  msvcr100: string;
{$ENDIF}
  libSmCrypto: string;
  libSmCryptoMD5: string;
begin
  inherited;
{$IFDEF POSIX}
  libSmCrypto := '/etc/libSmCrypto-x64.so';
  libSmCryptoMD5 := '661ee4044321bebc035b223042f6ae57';
{$ELSE}
{$IFDEF cpu32bits}
  libSmCrypto := 'C:\Windows\libSmCrypto-x86.dll';
  libSmCryptoMD5 := '4c0f6005ed608445e235184077f9a037';
  if IsWin64 then
    msvcr100 := 'C:\Windows\SysWOW64\msvcr100.dll'
  else
    msvcr100 := 'C:\Windows\System32\msvcr100.dll';
{$ENDIF}
{$IFDEF cpu64bits}
  libSmCrypto := 'C:\Windows\libSmCrypto-x64.dll';
  libSmCryptoMD5 := 'b42ad9707ef9aa59076f34e354608b20';
  msvcr100 := 'C:\Windows\System32\msvcr100.dll';
{$ENDIF}
  if (not FileExists(libSmCrypto)) or (THashMD5.GetHashStringFromFile(libSmCrypto) <> libSmCryptoMD5) then
    begin
      rs := TResourceStream.Create(HInstance, 'libSmCrypto', 'DLL');
      if FileExists(libSmCrypto) then
        RenameFile(libSmCrypto, libSmCrypto + '.' + gFun.GetGUID());
      rs.SaveToFile(libSmCrypto);
      rs.Free;
    end;
  if not FileExists(msvcr100) then
    begin
      rs := TResourceStream.Create(HInstance, 'msvcr100', 'DLL');
      rs.SaveToFile(msvcr100);
      rs.Free;
    end;
{$ENDIF}
  cryptModule := LoadLibrary(PWideChar(libSmCrypto));
  if cryptModule <> 0 then
    begin
      generateKeyPair := GetProcAddress(cryptModule, 'generateKeyPair');
      sm2EncryptFromText := GetProcAddress(cryptModule, 'sm2EncryptFromText');
      sm2DecryptToText := GetProcAddress(cryptModule, 'sm2DecryptToText');
      sm2EncryptASN1FromText := GetProcAddress(cryptModule, 'sm2EncryptASN1FromText');
      sm2DecryptASN1ToText := GetProcAddress(cryptModule, 'sm2DecryptASN1ToText');
      sm3EncryptFromText := GetProcAddress(cryptModule, 'sm3EncryptFromText');
      sm4EcbDecryptToText := GetProcAddress(cryptModule, 'sm4EcbDecryptToText');
      sm4EcbEncryptFromText := GetProcAddress(cryptModule, 'sm4EcbEncryptFromText');
      sm4CbcDecryptToText := GetProcAddress(cryptModule, 'sm4CbcDecryptToText');
      sm4CbcEncryptFromText := GetProcAddress(cryptModule, 'sm4CbcEncryptFromText');
    end;
end;

// 析构函数
destructor TBaseUtils.Destroy();
begin
  inherited Destroy;
  FContentType.Free;
  FreeLibrary(cryptModule);
end;

end.

你可能感兴趣的:(Delphi,国密算法,Delphi,SM2,SM4,字符串压缩)