本软件使用Delphi 10.3.3编写和测试, 源码中用到了System.NetEncoding和Generics.Collections两个单元, 因此本程序仅支持Delphi XE及更新的版本.
支持6种加密模式: ECB, CBC, CFB, OFB, PCBC, CTR; 默认为ECB;
支持7种填充模式(ZERO, PKCS5, PKCS7, ISO10126, ANSIX923, OneAndZero); 默认为PKCS7;
SM4要求密码长度的长度为16个字节(128bit), 如果长度不足, 程序就填充0x00来补足
SM4要求初始向量的长度为16个字节(128bit), 如果长度不足, 程序就填充0x00来补足
SrcBuffer, KeyBuffer, IVBuffer, DestBuffer: TBuffer 说明:
SrcBuffer存放待加密/解密的数据,
KeyBuffer存放密码数据,
IVBuffer存放初始向量数据,
DestBuffer存放已加密/解密的数据
TBuffer本身带有各种数据转换函数, 数据转换非常方便,不需要另外再写代码,例如:
function ToString(Encoding: TEncoding): String;
function ToHexString: String;
function ToDelimitedHexString(Prefix: String; Delimitor: String): String;
function ToBase64String: String;
procedure ToBytes(var OutBytes: TBytes; ByteLen: Integer);
procedure FromString(const Str: String);
procedure FromString(const Str: String; Encoding: TEncoding);
procedure FromHexString(const Str: String);
procedure FromDelimitedHexString(HexStr: String; Prefix: String; Delimitor: String');
procedure FromBase64String(const Str: String);
procedure FromBytes(const InBytes: TBytes; ByteLen: Integer);
最简单的TSM4使用示范代码:
//最简单的使用示范 procedure TMainForm.Test; var S1, S2: String; begin with TSM4.Create(cmCBC, pmPKCS5) do begin SrcBuffer.FromString('先学着让自己值钱'); KeyBuffer.FromBase64String('MTIzNDU2Nzg5MDEyMzQ1Ng=='); //1234567890123456 //或KeyBuffer.FromString('1234567890123456'); IVBuffer.FromHexString('6162636465666768696A6B6C6D6E6F70'); //abcdefghijklmnop Encrypt; //加密 S1 := DestBuffer.ToHexString; //6C19FEC30147DBDE9539DC1DF0F3ACF09B6E6210F0F220D3D923F200DC5A44C4 SrcBuffer.FromHexString(S1); Decrypt; //解密 S2 := DestBuffer.ToString; //'先学着让自己值钱' Free; end; end;
完整的TSM4代码(包括测试代码)
unit uMain; interface uses {$IF CompilerVersion <= 22} Windows, Messages, Generics.Collections, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, NetEncoding, StdCtrls, uSM4; {$ELSE} Winapi.Windows, Winapi.Messages, Generics.Collections, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, System.NetEncoding, Vcl.StdCtrls, uSM4; {$ENDIF} type TMainForm = class(TForm) LabelBlockMode: TLabel; LabelPaddingmode: TLabel; ComboBoxCipherMode: TComboBox; ComboBoxPaddingmode: TComboBox; LabelStr: TLabel; LabelIV: TLabel; LabelEnc: TLabel; LabelDec: TLabel; EditKey: TEdit; EditIV : TEdit; EditDec: TEdit; EditEnc: TEdit; EditStr: TEdit; LabelKey: TLabel; ButtonEncrypt: TButton; ButtonDecrypt: TButton; ComboBoxStr: TComboBox; ComboBoxKey: TComboBox; ComboBoxIV: TComboBox; ComboBoxEnc: TComboBox; ComboBoxDec: TComboBox; LabelStrCnt: TLabel; LabelKeyCnt: TLabel; LabelIVCnt : TLabel; LabelEncCnt: TLabel; LabelDecCnt: TLabel; EditSrc: TEdit; ButtonToHex: TButton; ButtonToBase64: TButton; EditDest: TEdit; RzEdit1: TEdit; Label1: TLabel; ButtonFromHex: TButton; ButtonFramBase64: TButton; Label2: TLabel; Label3: TLabel; procedure FormCreate(Sender: TObject); procedure EditChange(Sender: TObject); procedure ButtonClick(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure ButtonConvertClick(Sender: TObject); procedure ButtonFromClick(Sender: TObject); private type TProc = procedure(const S: String) of object; Tfunc = function(): String of object; TFromDict = TDictionary<String, TProc>; TToDict = TDictionary<String, TFunc>; TCountDict = TDictionary<TEdit, TLabel>; private SM4: TSM4; DIctCm: TDictionary<String, TCipherMode>; DIctPm: TDictionary<String, TPaddingMode>; DictFromStr, DictFromKey, DictFromIV, DictFromEnc: TFromDict; DictToEnc, DictToDec: TToDict; DictCount: TCountDict; procedure FillDicts; public { Public declarations } end; var MainForm: TMainForm; implementation {$R *.dfm} uses uBuffer; procedure TMainForm.FormCreate(Sender: TObject); begin ReportMemoryLeaksOnShutDown := True; SM4 := TSM4.Create; DIctCm := TDictionary<String, TCipherMode>.Create; DIctPm := TDictionary<String, TPaddingMode>.Create; DictFromStr := TFromDict.Create; DictFromKey := TFromDict.Create; DictFromIV := TFromDict.Create; DictFromEnc := TFromDict.Create; DictToEnc := TToDict.Create; DictToDec := TToDict.Create; DictCount := TCountDict.Create; FillDicts; EditChange(nil); end; procedure TMainForm.FormDestroy(Sender: TObject); begin DIctCm.Free; DIctPm.Free; DictFromStr.Free; DictFromKey.Free; DictFromIV.Free; DictFromEnc.Free; DictToEnc.Free; DictToDec.Free; DictCount.Free; SM4.Free; end; procedure TMainForm.FillDicts; var SrcBuffer, KeyBuffer, IVBuffer, DestBuffer: TBuffer; begin SrcBuffer := SM4.SrcBuffer; KeyBuffer := SM4.KeyBuffer; IVBuffer := SM4.IVBuffer; DestBuffer:= SM4.DestBuffer; with DIctCm do begin Add('ECB' , cmECB); Add('CBC' , cmCBC); Add('CFB' , cmCFB); Add('OFB' , cmOFB); Add('PCBC', cmPCBC); Add('CTR' , cmCTR); end; with DIctPm do begin Add('ZERO' , pmZERO); Add('PKCS5' , pmPKCS5); Add('PKCS7' , pmPKCS7); Add('ISO10126' , pmISO10126); Add('ANSIX923' , pmANSIX923); Add('OneAndZero', pmOneAndZero); end; with DictFromStr do begin Add('String', SrcBuffer.FromString); Add('Hex' , SrcBuffer.FromHexString); Add('Base64', SrcBuffer.FromBase64String); end; with DictFromKey do begin Add('String', KeyBuffer.FromString); Add('Hex' , KeyBuffer.FromHexString); Add('Base64', KeyBuffer.FromBase64String); end; with DictFromIV do begin Add('String', IVBuffer.FromString); Add('Hex' , IVBuffer.FromHexString); Add('Base64', IVBuffer.FromBase64String); end; with DictFromEnc do begin Add('Hex' , SrcBuffer.FromHexString); Add('Base64', SrcBuffer.FromBase64String); end; with DictToEnc do begin Add('Hex' , DestBuffer.ToHexString); Add('Base64', DestBuffer.ToBase64String); end; with DictToDec do begin Add('String', DestBuffer.ToString); Add('Hex' , DestBuffer.ToHexString); Add('Base64', DestBuffer.ToBase64String); end; with DictCount do begin Add(EditStr, LabelStrCnt); Add(EditKey, LabelKeyCnt); Add(EditIV , LabelIVCnt ); Add(EditEnc, LabelEncCnt); Add(EditDec, LabelDecCnt); end; end; procedure TMainForm.ButtonConvertClick(Sender: TObject); begin with TBuffer.Create do begin FromString(EditSrc.Text); if Sender = ButtonToHex then EditDest.Text := ToHexString else EditDest.Text := ToBase64String; Free; end; end; procedure TMainForm.ButtonFromClick(Sender: TObject); begin with TBuffer.Create do begin if Sender = ButtonFromHex then FromHexString(EditDest.Text) else FromBase64String(EditDest.Text); EditSrc.Text := ToString; Free; end; end; procedure TMainForm.ButtonClick(Sender: TObject); begin SM4.CipherMode := DIctCm.Items[ComboBoxCipherMode.Text]; SM4.PaddingMode := DIctPm.Items[ComboBoxPaddingMode.Text]; DictFromKey.Items[ComboBoxKey.Text](EditKey.Text); DictFromIV.Items[ComboBoxIV.Text](EditIV.Text); if Sender = ButtonEncrypt then begin DictFromStr.Items[ComboBoxStr.Text](EditStr.Text); SM4.Encrypt; EditEnc.Text := DictToEnc.Items[ComboBoxEnc.Text](); end else begin DictFromEnc.Items[ComboBoxEnc.Text](EditEnc.Text); SM4.Decrypt; EditDec.Text := DictToDec.Items[ComboBoxDec.Text](); end; end; procedure TMainForm.EditChange(Sender: TObject); var Edit: TEdit; begin if Sender <> nil then begin Edit := TEdit(Sender); DictCount.Items[Edit].Caption := Length(Edit.Text).ToString; end else begin for Edit in DictCount.Keys do begin DictCount.Items[Edit].Caption := Length(Edit.Text).ToString; end; end; end; end.
object MainForm: TMainForm Left = 0 Top = 0 Caption = 'SM4'#21152#23494#35299#23494#27979#35797 ClientHeight = 452 ClientWidth = 788 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate OnDestroy = FormDestroy DesignSize = ( 788 452) PixelsPerInch = 96 TextHeight = 13 object LabelBlockMode: TLabel Left = 5 Top = 108 Width = 48 Height = 13 Caption = #21152#23494#27169#24335 end object LabelPaddingmode: TLabel Left = 132 Top = 108 Width = 48 Height = 13 Caption = #22635#20805#27169#24335 end object LabelStr: TLabel Left = 28 Top = 149 Width = 24 Height = 13 Caption = #26126#25991 end object LabelIV: TLabel Left = 4 Top = 234 Width = 48 Height = 13 Caption = #21021#22987#21521#37327 end object LabelEnc: TLabel Left = 26 Top = 314 Width = 24 Height = 13 Caption = #23494#25991 end object LabelDec: TLabel Left = 26 Top = 402 Width = 24 Height = 13 Caption = #26126#25991 end object LabelKey: TLabel Left = 26 Top = 193 Width = 24 Height = 13 Caption = #23494#30721 end object LabelStrCnt: TLabel Left = 758 Top = 150 Width = 24 Height = 13 Anchors = [akTop, akRight] Caption = #23383#25968 end object LabelKeyCnt: TLabel Left = 758 Top = 192 Width = 24 Height = 13 Anchors = [akTop, akRight] Caption = #23383#25968 end object LabelIVCnt: TLabel Left = 758 Top = 234 Width = 24 Height = 13 Anchors = [akTop, akRight] Caption = #23383#25968 end object LabelEncCnt: TLabel Left = 758 Top = 314 Width = 24 Height = 13 Anchors = [akTop, akRight] Caption = #23383#25968 end object LabelDecCnt: TLabel Left = 758 Top = 400 Width = 24 Height = 13 Anchors = [akTop, akRight] Caption = #23383#25968 end object Label1: TLabel Left = 5 Top = 35 Width = 48 Height = 13 Caption = #23545#27604#32467#26524 end object Label2: TLabel Left = 512 Top = 1 Width = 28 Height = 13 Caption = 'String' end object Label3: TLabel Left = 494 Top = 64 Width = 89 Height = 13 Caption = 'Hex/Base64 [utf8]' end object ComboBoxCipherMode: TComboBox Left = 59 Top = 105 Width = 54 Height = 21 TabOrder = 0 Text = 'ECB' Items.Strings = ( 'ECB' 'CBC' 'PCBC' 'CFB' 'OFB' 'CTR') end object ComboBoxPaddingmode: TComboBox Left = 185 Top = 105 Width = 68 Height = 21 TabOrder = 1 Text = 'PKCS7' Items.Strings = ( 'PKCS5' 'PKCS7' 'ANSIX923' 'OneAndZero' 'ISO10126' 'ZERO' '') end object EditKey: TEdit Left = 119 Top = 188 Width = 633 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 2 Text = '1234567890123456' OnChange = EditChange end object EditIV: TEdit Left = 119 Top = 230 Width = 633 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 3 Text = 'abcdefghijklmnop' OnChange = EditChange end object EditDec: TEdit Left = 119 Top = 396 Width = 633 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 4 OnChange = EditChange end object EditEnc: TEdit Left = 119 Top = 310 Width = 633 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 5 OnChange = EditChange end object EditStr: TEdit Left = 119 Top = 146 Width = 633 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 6 Text = #20808#23398#30528#35753#33258#24049#20540#38065 OnChange = EditChange end object ButtonEncrypt: TButton Left = 329 Top = 268 Width = 137 Height = 24 Caption = #21152#23494 TabOrder = 7 OnClick = ButtonClick end object ButtonDecrypt: TButton Left = 329 Top = 351 Width = 137 Height = 24 Caption = #35299#23494 TabOrder = 8 OnClick = ButtonClick end object ComboBoxStr: TComboBox Left = 57 Top = 146 Width = 58 Height = 21 TabOrder = 9 Text = 'String' Items.Strings = ( 'String' 'Hex' 'Base64') end object ComboBoxKey: TComboBox Left = 57 Top = 188 Width = 58 Height = 21 TabOrder = 10 Text = 'String' Items.Strings = ( 'String' 'Hex' 'Base64') end object ComboBoxIV: TComboBox Left = 57 Top = 230 Width = 58 Height = 21 TabOrder = 11 Text = 'String' Items.Strings = ( 'String' 'Hex' 'Base64') end object ComboBoxEnc: TComboBox Left = 57 Top = 310 Width = 58 Height = 21 TabOrder = 12 Text = 'Hex' Items.Strings = ( 'Hex' 'Base64') end object ComboBoxDec: TComboBox Left = 57 Top = 396 Width = 58 Height = 21 TabOrder = 13 Text = 'String' Items.Strings = ( 'String' 'Hex' 'Base64') end object EditSrc: TEdit Left = 361 Top = 16 Width = 345 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 14 Text = #20808#23398#30528#35753#33258#24049#20540#38065 end object ButtonToHex: TButton Left = 293 Top = 41 Width = 62 Height = 22 Caption = 'ToHex' TabOrder = 15 OnClick = ButtonConvertClick end object ButtonToBase64: TButton Left = 713 Top = 41 Width = 65 Height = 22 Anchors = [akTop, akRight] Caption = 'ToBase64' TabOrder = 16 OnClick = ButtonConvertClick end object EditDest: TEdit Left = 361 Top = 41 Width = 345 Height = 21 Anchors = [akLeft, akTop, akRight] TabOrder = 17 end object RzEdit1: TEdit Left = 57 Top = 32 Width = 196 Height = 21 TabOrder = 18 Text = 'https://javalang.cn/crypto/sm4.html' end object ButtonFromHex: TButton Left = 294 Top = 16 Width = 61 Height = 22 Caption = 'FromHex' TabOrder = 19 OnClick = ButtonFromClick end object ButtonFramBase64: TButton Left = 713 Top = 15 Width = 65 Height = 22 Anchors = [akTop, akRight] Caption = 'FromBase64' TabOrder = 20 OnClick = ButtonFromClick end end
unit uSM4; interface uses {$IF CompilerVersion <= 22} Forms, Classes, Windows, SysUtils, NetEncoding, {$ELSE} Vcl.Forms, System.Classes, Winapi.Windows, System.SysUtils, System.NetEncoding, {$ENDIF} uConst, uBuffer; type TCipherMode = (cmECB, cmCBC, cmPCBC, cmCFB, cmOFB, cmCTR); TPaddingMode = (pmZERO, pmPKCS5, pmPKCS7, pmISO10126, pmANSIX923, pmOneAndZero); TSM4 = class(TObject) private type TWord = UInt32; TBlock = array[0..4 -1] of TWord; TRoundKey = array[0..32-1] of TWord; TCryptType = (ctEncrypt, ctDecrypt); TProc = procedure (var A: TBlock) of object; private RK: TRoundKey; MK, DataBlock, IVBlock: TBlock; BlockSize, BlockLen, RKLen: Integer; function SBoxMap(A: TWord): TWord; function ROTL(A: TWord; N: Byte): TWord; procedure CryptBlock(const CryptType: TCryptType; var A: TBlock); procedure ExpandKey; procedure ReverseEndian(var A: TBlock); procedure AppendPadding; procedure RemovePadding; procedure CheckKeyBufferAndIVBuffer; procedure XorBlock(var A: TBlock; const B: TBlock); overload; procedure XorBlock(var A: TBlock; const B, C: TBlock); overload; procedure IncBlock(Var A: TBlock); procedure Crypt(CryptType: TCryptType); public CipherMode : TCipherMode; PaddingMode: TPaddingMode; SrcBuffer, KeyBuffer, IVBuffer, DestBuffer: TBuffer; procedure Encrypt; procedure Decrypt; constructor Create(aCipherMode: TCipherMode = cmECB; aPaddingMode: TPaddingMode = pmPKCS7); destructor Destroy; override; end; implementation constructor TSM4.Create(aCipherMode: TCipherMode; aPaddingMode: TPaddingMode); begin inherited Create; CipherMode := aCipherMode; PaddingMode := aPaddingMode; SrcBuffer := TBuffer.Create; KeyBuffer := TBuffer.Create; IVBuffer := TBuffer.Create; DestBuffer := TBuffer.Create; BlockSize := SizeOf(TBlock); //16 BlockLen := SizeOf(TBlock) div Sizeof(UInt32); //4 RKLen := SizeOf(TRoundKey) div Sizeof(UInt32); //32 end; destructor TSM4.Destroy; begin SrcBuffer.Free; KeyBuffer.Free; IVBuffer.Free; DestBuffer.Free; inherited; end; procedure TSM4.Encrypt; begin AppendPadding; Crypt(ctEncrypt); end; procedure TSM4.Decrypt; begin Crypt(ctDecrypt); RemovePadding; end; procedure TSM4.Crypt(CryptType: TCryptType); var InBlock: TBlock; DataLen, OffSet: Integer; begin CheckKeyBufferAndIVBuffer; DataLen := SrcBuffer.Length; DestBuffer.Length := DataLen; KeyBuffer.ToBytes(MK, BlockSize); if CipherMode <> cmECB then begin IVBuffer.ToBytes(IVBlock, BlockSize); end; ExpandKey; OffSet := 0; while OffSet < DataLen do begin SrcBuffer.OffsetToBytes(OffSet, DataBlock, BlockSize); case CipherMode of cmECB: //Electronic Codebook (ECB) begin CryptBlock(CryptType, DataBlock); end; cmCBC: //Cipher Block Chaining (CBC) begin if CryptType = ctEncrypt then begin XorBlock(DataBlock, IVBlock); CryptBlock(CryptType, DataBlock); IVBlock := DataBlock; end else begin InBlock := DataBlock; CryptBlock(CryptType, DataBlock); XorBlock(DataBlock, IVBlock); IVBlock := InBlock; end; end; cmPCBC: //Propagating Cipher Block Chaining (PCBC) begin InBlock := DataBlock; if CryptType = ctEncrypt then begin XorBlock(DataBlock, IVBlock); CryptBlock(CryptType, DataBlock); end else begin CryptBlock(CryptType, DataBlock); XorBlock(DataBlock, IVBlock); end; XorBlock(IVBlock, DataBlock, InBlock); end; cmCFB: //Cipher Feedback (CFB) begin InBlock := DataBlock; CryptBlock(ctEncrypt, IVBlock); //不管是加密还是解密,这里都是用Encrypt对IV进行操作 XorBlock(DataBlock, IVBlock); if CryptType = ctEncrypt then IVBlock := DataBlock else IVBlock := InBlock; end; cmOFB: //Output Feedback (OFB) begin CryptBlock(ctEncrypt, IVBlock); //不管是加密还是解密,这里都是用Encrypt对IV进行操作 XorBlock(DataBlock, IVBlock); end; cmCTR: //Counter (CTR) begin InBlock := IVBlock; CryptBlock(ctEncrypt, InBlock); //不管是加密还是解密,这里都是用Encrypt对IV进行操作 XorBlock(DataBlock, InBlock); IncBlock(IVBlock); end; end; DestBuffer.OffsetFromBytes(OffSet, DataBlock, BlockSize); Inc(OffSet, BlockSize); end; end; procedure TSM4.AppendPadding; //添加填充 var I, M, N, Len, NewLen: Integer; begin Len := Length(SrcBuffer.Data); M := (Len mod BlockSize); if (M = 0) and (PaddingMode = pmZero) then N := 0 else N := BlockSize - M; NewLen := Len + N; SetLength(SrcBuffer.Data, NewLen); case PaddingMode of pmPKCS5, pmPKCS7: begin for I := Len to NewLen-1 do SrcBuffer.Data[I] := N; end; pmANSIX923: begin for I := Len to NewLen-1 do begin if I < NewLen-1 then SrcBuffer.Data[I] := 0 else SrcBuffer.Data[I] := N; end; end; pmISO10126: begin Randomize; for I := Len to NewLen-1 do begin if I < NewLen-1 then SrcBuffer.Data[I] := Random(255) else SrcBuffer.Data[I] := N; end; end; pmZERO: begin for I := Len to NewLen-1 do SrcBuffer.Data[I] := 0; end; pmOneAndZero: begin for I := Len to NewLen-1 do begin if I = Len then SrcBuffer.Data[I] := $80 else SrcBuffer.Data[I] := 0; end; end; end; end; procedure TSM4.RemovePadding; //移除填充 var I, M, Len: Integer; begin Len := Length(DestBuffer.Data); case PaddingMode of pmPKCS5, pmPKCS7, pmANSIX923, pmISO10126: begin M := DestBuffer.Data[Len-1]; SetLength(DestBuffer.Data, Len-M); end; pmZERO: begin for I := Len-1 downto 0 do begin if DestBuffer.Data[I] = 0 then Dec(Len) else Break; end; SetLength(DestBuffer.Data, Len); end; pmOneAndZero: begin for I := Len-1 downto 0 do begin if DestBuffer.Data[I] <> $80 then Dec(Len) else Break; end; SetLength(DestBuffer.Data, Len-1); end; end; end; procedure TSM4.CheckKeyBufferAndIVBuffer; //对Key和IV不足16Bytes的情况以0填足 var I, Len: Integer; begin Len := Length(KeyBuffer.Data); SetLength(KeyBuffer.Data, BlockSize); for I := Len to BlockSize - 1 do begin KeyBuffer.Data[I] := 0; end; if CipherMode <> cmECB then //ECB模式不需要初始矢量IV begin Len := Length(IVBuffer.Data); SetLength(IVBuffer.Data, BlockSize); for I := Len to BlockSize - 1 do begin IVBuffer.Data[I] := 0; end; end; end; procedure TSM4.ExpandKey; function Transform(A: TWord): TWord; //合成置换 begin A := SBoxMap(A); //非线性变换 Result := A xor ROTL(A, 13) xor ROTL(A, 23); //线性变换 end; var K: TBlock; I: Integer; M0, M1, M2, M3: TWord; begin ReverseEndian(MK); //32整数位大小端转换 for I := 0 to BlockLen-1 do begin K[I] := MK[I] xor FK[I]; end; for I := 0 to RKLen-1 do //32次迭代运算 begin M0 := (I ) mod 4; M1 := (I+1) mod 4; M2 := (I+2) mod 4; M3 := (I+3) mod 4; K[M0] := K[M0] xor Transform(K[M1] xor K[M2] xor K[M3] xor CK[I]); //迭代运算 RK[I] := K[M0]; end; end; procedure TSM4.CryptBlock(const CryptType: TCryptType; var A: TBlock); function TransForm(A: TWord): TWord; //合成置换 begin A := SBoxMap(A); //非线性变换 Result := A xor ROTL(A, 2) xor ROTL(A, 10) xor ROTL(A, 18) xor ROTL(A, 24); //线性变换 end; var T: TBlock; I, R: Integer; M0, M1, M2, M3: TWord; begin ReverseEndian(A); //32位整数大小端(Endian)转换 for I := 0 to RKLen-1 do //32次迭代运算 begin if CryptType = ctEncrypt then R := I else R := 31 - I; //解密时使用反序的RK M0 := (I ) mod 4; M1 := (I+1) mod 4; M2 := (I+2) mod 4; M3 := (I+3) mod 4; A[M0] := A[M0] xor TransForm(A[M1] xor A[M2] xor A[M3] xor RK[R]); //迭代运算 end; ReverseEndian(A); //32整数位大小端(Endian)转换 T := A; for I := 0 to 3 do //Block内部的4个32位整数的位置做反序变换 begin A[I] := T[3 - I]; end; end; function TSM4.SBoxMap(A: TWord): TWord; //S盒非线性变换(Byte to Byte的固定映射} var I: Integer; B: array[0..3] of Byte absolute A; R: array[0..3] of Byte absolute Result; begin for I := 0 to 3 do begin R[I] := SBox[B[I]]; end; end; procedure TSM4.ReverseEndian(var A: TBlock); //32位大小端(Endian)变换 var I: Integer; begin for I := 0 to BlockLen-1 do begin A[I] := ((A[I] and $FF000000) shr 24) or ((A[I] and $00FF0000) shr 8 ) or ((A[I] and $0000FF00) shl 8 ) or ((A[I] and $000000FF) shl 24); end; end; function TSM4.ROTL(A: TWord; N: Byte): TWord; //32位循环左移N位 begin Result := (A shl N) or (A shr (32-N)); end; procedure TSM4.XorBlock(var A: TBlock; const B: TBlock); //两个Block异或 var I: Integer; begin for I := 0 to BlockLen-1 do begin A[I] := A[I] xor B[I]; end; end; procedure TSM4.XorBlock(var A: TBlock; const B, C: TBlock); //两个Block异或 var I: Integer; begin for I := 0 to BlockLen-1 do begin A[I] := B[I] xor C[I]; end; end; procedure TSM4.IncBlock(var A: TBlock); //Block值加1 var I: Integer; begin for I := 0 to BlockLen-1 do begin if I > 0 then begin A[I-1] := 0; end; if (I = BlockLen-1) or (A[I] < $FFFFFFFF) then begin Inc(A[0]); Exit; end; end; end; end.
- unit uConst;
- interface
- const
- // S盒
- Sbox: array[0..255] of Byte = (
- $d6,$90,$e9,$fe,$cc,$e1,$3d,$b7,$16,$b6,$14,$c2,$28,$fb,$2c,$05,
- $2b,$67,$9a,$76,$2a,$be,$04,$c3,$aa,$44,$13,$26,$49,$86,$06,$99,
- $9c,$42,$50,$f4,$91,$ef,$98,$7a,$33,$54,$0b,$43,$ed,$cf,$ac,$62,
- $e4,$b3,$1c,$a9,$c9,$08,$e8,$95,$80,$df,$94,$fa,$75,$8f,$3f,$a6,
- $47,$07,$a7,$fc,$f3,$73,$17,$ba,$83,$59,$3c,$19,$e6,$85,$4f,$a8,
- $68,$6b,$81,$b2,$71,$64,$da,$8b,$f8,$eb,$0f,$4b,$70,$56,$9d,$35,
- $1e,$24,$0e,$5e,$63,$58,$d1,$a2,$25,$22,$7c,$3b,$01,$21,$78,$87,
- $d4,$00,$46,$57,$9f,$d3,$27,$52,$4c,$36,$02,$e7,$a0,$c4,$c8,$9e,
- $ea,$bf,$8a,$d2,$40,$c7,$38,$b5,$a3,$f7,$f2,$ce,$f9,$61,$15,$a1,
- $e0,$ae,$5d,$a4,$9b,$34,$1a,$55,$ad,$93,$32,$30,$f5,$8c,$b1,$e3,
- $1d,$f6,$e2,$2e,$82,$66,$ca,$60,$c0,$29,$23,$ab,$0d,$53,$4e,$6f,
- $d5,$db,$37,$45,$de,$fd,$8e,$2f,$03,$ff,$6a,$72,$6d,$6c,$5b,$51,
- $8d,$1b,$af,$92,$bb,$dd,$bc,$7f,$11,$d9,$5c,$41,$1f,$10,$5a,$d8,
- $0a,$c1,$31,$88,$a5,$cd,$7b,$bd,$2d,$74,$d0,$12,$b8,$e5,$b4,$b0,
- $89,$69,$97,$4a,$0c,$96,$77,$7e,$65,$b9,$f1,$09,$c5,$6e,$c6,$84,
- $18,$f0,$7d,$ec,$3a,$dc,$4d,$20,$79,$ee,$5f,$3e,$d7,$cb,$39,$48
- );
- // 密钥扩展算法的常数FK
- FK: array[0..3] of UInt32 = ($a3b1bac6, $56aa3350, $677d9197, $b27022dc);
- // 密钥扩展算法的固定参数CK
- CK: array[0..31] of UInt32 = (
- $00070e15, $1c232a31, $383f464d, $545b6269,
- $70777e85, $8c939aa1, $a8afb6bd, $c4cbd2d9,
- $e0e7eef5, $fc030a11, $181f262d, $343b4249,
- $50575e65, $6c737a81, $888f969d, $a4abb2b9,
- $c0c7ced5, $dce3eaf1, $f8ff060d, $141b2229,
- $30373e45, $4c535a61, $686f767d, $848b9299,
- $a0a7aeb5, $bcc3cad1, $d8dfe6ed, $f4fb0209,
- $10171e25, $2c333a41, $484f565d, $646b7279
- );
- implementation
- end.
- unit uBuffer;
- interface
- uses
- {$IF CompilerVersion <= 22}
- Forms, Classes, Windows, SysUtils, NetEncoding;
- {$ELSE}
- Vcl.Forms, System.Classes, Winapi.Windows, System.SysUtils, System.NetEncoding;
- {$ENDIF}
- type
- TBuffer = class
- private
- function GetDataLength: Integer; inline;
- procedure SetDataLength(Len: Integer); inline;
- function GetItem(Index: Integer): Byte; inline;
- procedure SetItem(Index: Integer; Value: Byte); inline;
- public
- Data: TBytes; //TBytes = array of Byte;
- procedure FromString(const Str: String); overload; //默认为utf8
- procedure FromString(const Str: String; Encoding: TEncoding); overload;
- procedure FromHexString(const Str: String);
- procedure FromDelimitedHexString(HexStr: String; Prefix: String = '$'; Delimitor: String = ',');
- procedure FromBase64String(const Str: String);
- procedure FromBytes(const InBytes: TBytes; ByteLen: Integer = -1); overload;
- procedure FromBytes(const InBytes: array of Byte; ByteLen: Integer = -1); overload;
- procedure FromBytes(const Ints: array of UInt32; ByteLen: Integer); overload;
- procedure OffsetFromBytes(Offset: Integer; const Ints: array of UInt32; ByteLen: Integer);
- procedure FromStream(const Stream: TStream; ByteLen: Integer = -1);
- procedure FromFile(const FileName: String);
- function ToString: String; reintroduce; overload; //默认为utf8
- function ToString(Encoding: TEncoding): String; reintroduce; overload;
- function ToHexString: String;
- function ToDelimitedHexString(Prefix: String = '$'; Delimitor: String = ', '): String;
- function ToBase64String: String;
- procedure ToBytes(var OutBytes: TBytes; ByteLen: Integer = -1); overload;
- procedure ToBytes(var OutBytes: array of Byte; ByteLen: Integer = -1); overload;
- procedure ToBytes(var Ints: array of UInt32; ByteLen: Integer = 1); overload;
- procedure OffsetToBytes(Offset: Integer; var Ints: array of UInt32; ByteLen: Integer);
- procedure ToStream(const Stream: TStream);
- procedure ToFile(const FileName: String; Warning: Boolean = True);
- property Length: Integer read GetDataLength write SetDataLength;
- property Bytes[Index: Integer]: Byte read GetItem write SetItem; default;
- end;
- resourcestring
- SInvalidBufSize = 'Invalid buffer size for ouput';
- implementation
- function TBuffer.GetDataLength: Integer;
- begin
- Result := System.Length(Data);
- end;
- procedure TBuffer.SetDataLength(Len: Integer);
- begin
- System.SetLength(Data, Len);
- end;
- function TBuffer.GetItem(Index: Integer): Byte;
- begin
- Result := Data[Index];
- end;
- procedure TBuffer.SetItem(Index: Integer; Value: Byte);
- begin
- Data[Index] := Value;
- end;
- procedure TBuffer.FromString(const Str: String);
- begin
- Data := TEncoding.UTF8.GetBytes(Str);
- end;
- procedure TBuffer.FromString(const Str: String; Encoding: TEncoding);
- begin
- Data := Encoding.GetBytes(Str);
- end;
- procedure TBuffer.FromHexString(const Str: String);
- var
- Len: Integer;
- begin
- Len := System.Length(Str) div 2;
- SetLength(Data, Len);
- HexToBin(PChar(Str), @Data[0], Len)
- end;
- procedure TBuffer.FromDelimitedHexString(HexStr: String; Prefix: String; Delimitor: String);
- var
- Len: Integer;
- begin
- HexStr := HexStr.Replace(Prefix , '');
- HexStr := HexStr.Replace(Delimitor , '');
- HexStr := HexStr.Replace(' ' , '');
- Len := System.Length(HexStr) div 2;
- SetLength(Data, Len);
- HexToBin(PChar(HexStr), @Data[0], Len)
- end;
- procedure TBuffer.FromBase64String(const Str: String);
- var
- Base64Encoding: TBase64Encoding;
- begin
- //Base64Encoding := TBase64Encoding.Create; //含换行符
- Base64Encoding := TBase64Encoding.Create(0); //不含换行符
- Data := Base64Encoding.DecodeStringToBytes(Str);
- Base64Encoding.Free;
- end;
- procedure TBuffer.FromBytes(const InBytes: array of Byte; ByteLen: Integer);
- begin
- if (ByteLen = -1) then ByteLen := System.Length(InBytes);
- SetLength(Data, ByteLen);
- Move(InBytes[0], Data[0], ByteLen);
- end;
- procedure TBuffer.FromBytes(const InBytes: TBytes; ByteLen: Integer);
- begin
- if (ByteLen = -1) then ByteLen := System.Length(InBytes);
- SetLength(Data, ByteLen);
- Move(InBytes[0], Data[0], ByteLen);
- end;
- procedure TBuffer.FromBytes(const Ints: array of UInt32; ByteLen: Integer);
- begin
- SetLength(Data, ByteLen);
- Move(Ints[0], Data[0], ByteLen);
- end;
- procedure TBuffer.OffsetFromBytes(Offset: Integer; const Ints: array of UInt32; ByteLen: Integer);
- begin
- Move(Ints[0], Data[Offset], ByteLen);
- end;
- procedure TBuffer.FromStream(const Stream: TStream; ByteLen: Integer);
- begin
- if (ByteLen = -1) then ByteLen := Stream.Size;
- SetLength(Data, ByteLen);
- Stream.Read(Data, ByteLen);
- end;
- procedure TBuffer.FromFile(const FileName: String);
- var
- Stream: TFileStream;
- begin
- Stream := TFileStream.Create(FileName, fmOpenRead);
- SetLength(Data, Stream.Size);
- Stream.Read(Data, Stream.Size);
- Stream.Free;
- end;
- function TBuffer.ToString: String;
- begin
- Result := TEncoding.UTF8.GetString(Data);
- end;
- function TBuffer.ToString(Encoding: TEncoding): String;
- begin
- Result := Encoding.GetString(Data);
- end;
- function TBuffer.ToHexString: String;
- var
- Len: Integer;
- begin
- Len := System.Length(Data);
- SetLength(Result, 2*Len);
- BinToHex(@Data[0], PChar(Result), Len);
- end;
- function TBuffer.ToDelimitedHexString(Prefix: String; Delimitor: String): String;
- var
- I, Len: Integer;
- begin
- Result := '';
- Len := System.Length(Data);
- for I := 0 to Len-1 do
- begin
- Result := Result + Prefix + IntToHex(Data[I], 2);
- if I < Len-1 then
- Result := Result + Delimitor;
- end;
- end;
- function TBuffer.ToBase64String: String;
- var
- Base64Encoding: TBase64Encoding;
- begin
- //Base64Encoding := TBase64Encoding.Create; //含换行符
- Base64Encoding := TBase64Encoding.Create(0); //不含换行符
- Result := Base64Encoding.EncodeBytesToString(Data);
- Base64Encoding.Free;
- end;
- procedure TBuffer.ToBytes(var OutBytes: array of Byte; ByteLen: Integer);
- begin
- if (ByteLen = -1) then ByteLen := System.Length(Data);
- if (ByteLen > System.Length(OutBytes)) then
- raise Exception.Create(SInvalidBufSize);
- Move(Data[0], OutBytes[0], ByteLen);
- end;
- procedure TBuffer.ToBytes(var OutBytes: TBytes; ByteLen: Integer);
- begin
- if ByteLen = -1 then ByteLen := System.Length(Data);
- SetLength(OutBytes, ByteLen);
- Move(Data[0], OutBytes[0], ByteLen);
- end;
- procedure TBuffer.ToBytes(var Ints: array of UInt32; ByteLen: Integer);
- begin
- if ByteLen = -1 then ByteLen := System.Length(Data);
- Move(Data[0], Ints[0], ByteLen);
- end;
- procedure TBuffer.OffsetToBytes(Offset: Integer; var Ints: array of UInt32; ByteLen: Integer);
- begin
- Move(Data[Offset], Ints[0], ByteLen);
- end;
- procedure TBuffer.ToStream(const Stream: TStream);
- begin
- Stream.Write(Data, System.Length(Data));
- end;
- procedure TBuffer.ToFile(const FileName: String; Warning: Boolean);
- var
- Stream: TFileStream;
- begin
- if Warning and FileExists(FileName) and
- (Application.MessageBox(PChar('File ' + FileName + ' Exists, Overwrite It?'),
- 'Warning: File Exists', MB_YESNO) = IDNO) then Exit;
- Stream := TFileStream.Create(FileName, fmCreate);
- Stream.Write(Data, System.Length(Data));
- Stream.Free;
- end;
- end.
联系客服