字符串国密加解密和字符串压缩工具函数。国密算法库有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.