delphi加密C#解密(AES-256)
因为公司内部业务需要,用delphi加密的内容(流和字符串)要用C#解密,因为不懂delphi,我这里只是问同事要了代码,贴上
delphi加密:
共两个文件(AES.pas 和 ElAES.pas),ElAES这个文件应该是类似C#的第三方库,代码我就不贴了
AES.pas :
(**************************************************************) (* *) (* AES Delphi 加密算法 *) (* *) (* *) (* *) (**************************************************************) unit AES; interface //{$DEFINE VER210} //{$IFDEF VER210} // {$WARN IMPLICIT_STRING_CAST OFF} //关闭警告 // {$WARN IMPLICIT_STRING_CAST_LOSS OFF} //{$ENDIF} uses SysUtils, Classes, Math, ElAES; const SDestStreamNotCreated = 'Dest stream not created.'; SEncryptStreamError = 'Encrypt stream error.'; SDecryptStreamError = 'Decrypt stream error.'; type TKeyBit = (kb128, kb192, kb256); function StrToHex(Const str: AnsiString): AnsiString; function HexToStr(const Value: AnsiString): AnsiString; function EncryptString(Value: AnsiString; Key: AnsiString; KeyBit: TKeyBit = kb128): AnsiString; function DecryptString(Value: AnsiString; Key: AnsiString; KeyBit: TKeyBit = kb128): AnsiString; function EncryptStream(Src: TStream; Key: AnsiString; var Dest: TStream; KeyBit: TKeyBit = kb128): Boolean; function DecryptStream(Src: TStream; Key: AnsiString; var Dest: TStream; KeyBit: TKeyBit = kb128): Boolean; procedure EncryptFile(SourceFile, DestFile: String; Key: AnsiString; KeyBit: TKeyBit = kb128); procedure DecryptFile(SourceFile, DestFile: String; Key: AnsiString; KeyBit: TKeyBit = kb128); implementation function StrToHex(Const str: Ansistring): Ansistring; asm push ebx push esi push edi test eax,eax jz @@Exit mov esi,edx //保存edx值,用来产生新字符串的地址 mov edi,eax //保存原字符串 mov edx,[eax-4] //获得字符串长度 test edx,edx //检查长度 je @@Exit {Length(S) = 0} mov ecx,edx //保存长度 Push ecx shl edx,1 mov eax,esi {$IFDEF VER210} movzx ecx, word ptr [edi-12] {需要设置CodePage} {$ENDIF} call System.@LStrSetLength //设置新串长度 mov eax,esi //新字符串地址 Call UniqueString //产生一个唯一的新字符串,串位置在eax中 Pop ecx @@SetHex: xor edx,edx //清空edx mov dl, [edi] //Str字符串字符 mov ebx,edx //保存当前的字符 shr edx,4 //右移4字节,得到高8位 mov dl,byte ptr[edx+@@HexChar] //转换成字符 mov [eax],dl //将字符串输入到新建串中存放 and ebx,$0F //获得低8位 mov dl,byte ptr[ebx+@@HexChar] //转换成字符 inc eax //移动一个字节,存放低位 mov [eax],dl inc edi inc eax loop @@SetHex @@Exit: pop edi pop esi pop ebx ret @@HexChar: db '0123456789ABCDEF' end; function HexToStr(const Value: AnsiString): AnsiString; asm push ebx push edi push esi test eax,eax //为空串 jz @@Exit mov edi,eax mov esi,edx mov edx,[eax-4] test edx,edx je @@Exit mov ecx,edx push ecx shr edx,1 mov eax,esi //开始构造字符串 {$IFDEF VER210} movzx ecx, word ptr [edi-12] {需要设置CodePage} {$ENDIF} call System.@LStrSetLength //设置新串长度 mov eax,esi //新字符串地址 Call UniqueString //产生一个唯一的新字符串,串位置在eax中 Pop ecx xor ebx,ebx xor esi,esi @@CharFromHex: xor edx,edx mov dl, [edi] //Str字符串字符 cmp dl, '0' //查看是否在0到f之间的字符 JB @@Exit //小于0,退出 cmp dl,'9' //小于=9 ja @@DoChar//CompOkNum sub dl,'0' jmp @@DoConvert @@DoChar: //先转成大写字符 and dl,$DF cmp dl,'F' ja @@Exit //大于F退出 add dl,10 sub dl,'A' @@DoConvert: //转化 inc ebx cmp ebx,2 je @@Num1 xor esi,esi shl edx,4 mov esi,edx jmp @@Num2 @@Num1: add esi,edx mov edx,esi mov [eax],dl xor ebx,ebx inc eax @@Num2: dec ecx inc edi test ecx,ecx jnz @@CharFromHex @@Exit: pop esi pop edi pop ebx end; { -- 字符串加密函数 默认按照 128 位密匙加密 -- } function EncryptString(Value: AnsiString; Key: AnsiString; KeyBit: TKeyBit = kb128): AnsiString; var {$IFDEF VER210} SS,DS: TMemoryStream; {$ELSE} SS, DS: TStringStream; {$ENDIF} Size: Int64; AESKey128: TAESKey128; AESKey192: TAESKey192; AESKey256: TAESKey256; st: AnsiString; begin Result := ''; {$IFDEF VER210} ss := TMemoryStream.Create; SS.WriteBuffer(PAnsiChar(Value)^,Length(Value)); DS := TMemoryStream.Create; {$ELSE} SS := TStringStream.Create(Value); DS := TStringStream.Create(''); {$ENDIF} try Size := SS.Size; // DS.WriteBuffer(Size, SizeOf(Size)); { -- 128 位密匙最大长度为 16 个字符 -- } if KeyBit = kb128 then begin FillChar(AESKey128, SizeOf(AESKey128), 0 ); Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); EncryptAESStreamECB(SS, 0, AESKey128, DS); end; { -- 192 位密匙最大长度为 24 个字符 -- } if KeyBit = kb192 then begin FillChar(AESKey192, SizeOf(AESKey192), 0 ); Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); EncryptAESStreamECB(SS, 0, AESKey192, DS); end; { -- 256 位密匙最大长度为 32 个字符 -- } if KeyBit = kb256 then begin FillChar(AESKey256, SizeOf(AESKey256), 0 ); Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); EncryptAESStreamECB(SS, 0, AESKey256, DS); end; {$IFDEF VER210} SetLength(st,Ds.Size); DS.Position := 0; DS.ReadBuffer(PAnsiChar(st)^,DS.Size); Result := StrToHex(st); {$ELSE} Result := StrToHex(DS.DataString); {$ENDIF} finally SS.Free; DS.Free; end; end; { -- 字符串解密函数 默认按照 128 位密匙解密 -- } function DecryptString(Value: AnsiString; Key: AnsiString; KeyBit: TKeyBit = kb128): AnsiString; var SS, DS: TStringStream; Size: Int64; AESKey128: TAESKey128; AESKey192: TAESKey192; AESKey256: TAESKey256; begin Result := ''; SS := TStringStream.Create(HexToStr(Value)); DS := TStringStream.Create(''); try Size := SS.Size; // SS.ReadBuffer(Size, SizeOf(Size)); { -- 128 位密匙最大长度为 16 个字符 -- } if KeyBit = kb128 then begin FillChar(AESKey128, SizeOf(AESKey128), 0 ); Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); DecryptAESStreamECB(SS, SS.Size - SS.Position, AESKey128, DS); end; { -- 192 位密匙最大长度为 24 个字符 -- } if KeyBit = kb192 then begin FillChar(AESKey192, SizeOf(AESKey192), 0 ); Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); DecryptAESStreamECB(SS, SS.Size - SS.Position, AESKey192, DS); end; { -- 256 位密匙最大长度为 32 个字符 -- } if KeyBit = kb256 then begin FillChar(AESKey256, SizeOf(AESKey256), 0 ); Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); DecryptAESStreamECB(SS, SS.Size - SS.Position, AESKey256, DS); end; Result := DS.DataString; finally SS.Free; DS.Free; end; end; { 流加密函数, default keybit: 128bit } function EncryptStream(Src: TStream; Key: AnsiString; var Dest: TStream; KeyBit: TKeyBit = kb128): Boolean; var Count: Int64; AESKey128: TAESKey128; AESKey192: TAESKey192; AESKey256: TAESKey256; begin if Dest = nil then begin raise Exception.Create(SDestStreamNotCreated); Result:= False; Exit; end; try Src.Position:= 0; // Count:= Src.Size; // Dest.Write(Count, SizeOf(Count)); { -- 128 位密匙最大长度为 16 个字符 -- } if KeyBit = kb128 then begin FillChar(AESKey128, SizeOf(AESKey128), 0 ); Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); EncryptAESStreamECB(Src, 0, AESKey128, Dest); end; { -- 192 位密匙最大长度为 24 个字符 -- } if KeyBit = kb192 then begin FillChar(AESKey192, SizeOf(AESKey192), 0 ); Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); EncryptAESStreamECB(Src, 0, AESKey192, Dest); end; { -- 256 位密匙最大长度为 32 个字符 -- } if KeyBit = kb256 then begin FillChar(AESKey256, SizeOf(AESKey256), 0 ); Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); EncryptAESStreamECB(Src, 0, AESKey256, Dest); end; Result := True; except raise Exception.Create(SEncryptStreamError); Result:= False; end; end; { 流解密函数, default keybit: 128bit } function DecryptStream(Src: TStream; Key: AnsiString; var Dest: TStream; KeyBit: TKeyBit = kb128): Boolean; var Count, OutPos: Int64; AESKey128: TAESKey128; AESKey192: TAESKey192; AESKey256: TAESKey256; begin if Dest = nil then begin raise Exception.Create(SDestStreamNotCreated); Result:= False; Exit; end; try Src.Position:= 0; OutPos:= Dest.Position; // Src.ReadBuffer(Count, SizeOf(Count)); Count := Src.Size; { -- 128 位密匙最大长度为 16 个字符 -- } if KeyBit = kb128 then begin FillChar(AESKey128, SizeOf(AESKey128), 0 ); Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); DecryptAESStreamECB(Src, Src.Size - Src.Position, AESKey128, Dest); end; { -- 192 位密匙最大长度为 24 个字符 -- } if KeyBit = kb192 then begin FillChar(AESKey192, SizeOf(AESKey192), 0 ); Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); DecryptAESStreamECB(Src, Src.Size - Src.Position, AESKey192, Dest); end; { -- 256 位密匙最大长度为 32 个字符 -- } if KeyBit = kb256 then begin FillChar(AESKey256, SizeOf(AESKey256), 0 ); Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); DecryptAESStreamECB(Src, Src.Size - Src.Position, AESKey256, Dest); end; // Dest.Size := OutPos + Count; Dest.Position := OutPos; Result := True; except raise Exception.Create(SDecryptStreamError); Result:= False; end; end; { -- 文件加密函数 默认按照 128 位密匙解密 -- } procedure EncryptFile(SourceFile, DestFile: String; Key: AnsiString; KeyBit: TKeyBit = kb128); var SFS, DFS: TFileStream; Size: Int64; AESKey128: TAESKey128; AESKey192: TAESKey192; AESKey256: TAESKey256; begin SFS := TFileStream.Create(SourceFile, fmOpenRead); try DFS := TFileStream.Create(DestFile, fmCreate); try // Size := SFS.Size; // DFS.WriteBuffer(Size, SizeOf(Size)); { -- 128 位密匙最大长度为 16 个字符 -- } if KeyBit = kb128 then begin FillChar(AESKey128, SizeOf(AESKey128), 0 ); Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); EncryptAESStreamECB(SFS, 0, AESKey128, DFS); end; { -- 192 位密匙最大长度为 24 个字符 -- } if KeyBit = kb192 then begin FillChar(AESKey192, SizeOf(AESKey192), 0 ); Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); EncryptAESStreamECB(SFS, 0, AESKey192, DFS); end; { -- 256 位密匙最大长度为 32 个字符 -- } if KeyBit = kb256 then begin FillChar(AESKey256, SizeOf(AESKey256), 0 ); Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); EncryptAESStreamECB(SFS, 0, AESKey256, DFS); end; finally DFS.Free; end; finally SFS.Free; end; end; { -- 文件解密函数 默认按照 128 位密匙解密 -- } procedure DecryptFile(SourceFile, DestFile: String; Key: AnsiString; KeyBit: TKeyBit = kb128); var SFS, DFS: TFileStream; Size: Int64; AESKey128: TAESKey128; AESKey192: TAESKey192; AESKey256: TAESKey256; begin SFS := TFileStream.Create(SourceFile, fmOpenRead); try Size := SFS.Size; // SFS.ReadBuffer(Size, SizeOf(Size)); DFS := TFileStream.Create(DestFile, fmCreate); try { -- 128 位密匙最大长度为 16 个字符 -- } if KeyBit = kb128 then begin FillChar(AESKey128, SizeOf(AESKey128), 0 ); Move(PAnsiChar(Key)^, AESKey128, Min(SizeOf(AESKey128), Length(Key))); DecryptAESStreamECB(SFS, SFS.Size - SFS.Position, AESKey128, DFS); end; { -- 192 位密匙最大长度为 24 个字符 -- } if KeyBit = kb192 then begin FillChar(AESKey192, SizeOf(AESKey192), 0 ); Move(PAnsiChar(Key)^, AESKey192, Min(SizeOf(AESKey192), Length(Key))); DecryptAESStreamECB(SFS, SFS.Size - SFS.Position, AESKey192, DFS); end; { -- 256 位密匙最大长度为 32 个字符 -- } if KeyBit = kb256 then begin FillChar(AESKey256, SizeOf(AESKey256), 0 ); Move(PAnsiChar(Key)^, AESKey256, Min(SizeOf(AESKey256), Length(Key))); DecryptAESStreamECB(SFS, SFS.Size - SFS.Position, AESKey256, DFS); end; DFS.Size := Size; finally DFS.Free; end; finally SFS.Free; end; end; end.
C#解密:
/// <summary> /// 解密delphi加密字符串和流 /// </summary> public class AesDelphi { public static byte[] HexStringToBytes(string hex) { if (hex.Length % 2 != 0) throw new ArgumentException("Hex string must have an even length"); byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < hex.Length; i += 2) { bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); } return bytes; } /// <summary> /// 解密字符串 /// </summary> /// <param name="encryptedText"></param> /// <param name="key"></param> /// <returns></returns> public static string DecryptString(string encryptedText, string key) { /* ECB模式,不会使用到IV,只有CBC模式才会使用IV设置成null就行,设置成空数组也行 Aes的iv不能设置null,可以设置到aes.CreateDecryptor(aes.Key, null)) aesAlg.KeySize = 256;千万不要设置,如果想设置要放到设置Key的前面,设置Key的时候会重置KeySize 只要保证key的大小即可,需要判定一下 if (Key == null || Key.Length != 32) throw new ArgumentNullException(nameof(Key)); aesAlg.BlockSize = 128; 默认的不需要设置,和Delphi一致 */ byte[] array = HexStringToBytes(encryptedText); // Convert.FromBase64String(encryptedText); using (Aes aes = Aes.Create()) { aes.Key = Encoding.UTF8.GetBytes(key); aes.Mode = CipherMode.ECB; // 确保和Delphi端的模式相匹配 aes.Padding = PaddingMode.PKCS7; // 确保和Delphi端的填充模式相匹配 using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, null)) { using (MemoryStream ms = new MemoryStream()) { using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Write)) { cs.Write(array, 0, array.Length); cs.FlushFinalBlock(); byte[] decryptedBytes = ms.ToArray(); return Encoding.UTF8.GetString(decryptedBytes).TrimEnd('\0'); } } } } } /// <summary> /// 解密文件流 /// </summary> /// <param name="encryptedData"></param> /// <param name="key"></param> /// <returns></returns> public static byte[] DecryptByte(byte[] encryptedData, string key) { /* ECB模式,不会使用到IV,只有CBC模式才会使用IV设置成null就行,设置成空数组也行 Aes的iv不能设置null,可以设置到aes.CreateDecryptor(aes.Key, null)) aesAlg.KeySize = 256;千万不要设置,如果想设置要放到设置Key的前面,设置Key的时候会重置KeySize 只要保证key的大小即可,需要判定一下 if (Key == null || Key.Length != 32) throw new ArgumentNullException(nameof(Key)); aesAlg.BlockSize = 128; 默认的不需要设置,和Delphi一致 */ //string encryptedText = Encoding.UTF8.GetString(encryptedData); //byte[] array = HexStringToBytes(encryptedText); // Convert.FromBase64String(encryptedText); using (Aes aes = Aes.Create()) { aes.Key = Encoding.UTF8.GetBytes(key); aes.Mode = CipherMode.ECB; // 确保和Delphi端的模式相匹配 aes.Padding = PaddingMode.PKCS7; // 确保和Delphi端的填充模式相匹配 byte[] decryptBytes = new byte[encryptedData.Length]; using (ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, null)) { using (MemoryStream ms = new MemoryStream(encryptedData)) { using (CryptoStream cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read)) { cs.Read(decryptBytes, 0, decryptBytes.Length); return decryptBytes; } } } } } }