Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi FMX dcpcrypt在macOS 64位上的错误结果_Delphi_Firemonkey - Fatal编程技术网

Delphi FMX dcpcrypt在macOS 64位上的错误结果

Delphi FMX dcpcrypt在macOS 64位上的错误结果,delphi,firemonkey,Delphi,Firemonkey,我使用的是Delphi10.3.2 我试图将DCPCrypt单元与firemonkey框架一起用于加密字符串。 它在Win32、Win64和macOS 32目标上100%工作,结果总是一样的。但当我为macOS 64编译时,结果是不同的 这是使用的代码: function EncodeAES(code:ansistring; key:ansistring):string; var s,u:ansistring; enc: TEncoding; k,iv, Data, Crypt:

我使用的是Delphi10.3.2 我试图将DCPCrypt单元与firemonkey框架一起用于加密字符串。 它在Win32、Win64和macOS 32目标上100%工作,结果总是一样的。但当我为macOS 64编译时,结果是不同的

这是使用的代码:

function EncodeAES(code:ansistring; key:ansistring):string;
var
    s,u:ansistring;
  enc: TEncoding;
  k,iv, Data, Crypt: TBytes;
  Cipher: TDCP_rijndael;
begin
    u:='';
    enc:=TEncoding.ANSI;
    Data := enc.GetBytes(code); // VMpuXJGbUNOv
    k:=enc.GetBytes(key);   // kj3214ed)k32nre2
    iv:=enc.GetBytes(u);
    Cipher:=TDCP_rijndael.Create(nil);
    Cipher.Init(K[0], 128, @iv[0]);
    Crypt:=Copy(Data, 0, Length(Data));
    BytePadding(Crypt, Cipher.BlockSize, pmPKCS7);
    Cipher.EncryptECB(Crypt[0], Crypt[0]);
    Cipher.Free;
    s:=tencoding.ANSI.GetString(crypt);
    result:=StringToHex(s);
end;
这是BytePadding函数:

procedure BytePadding(var Data: TBytes; BlockSize: integer; PaddingMode: TPaddingMode);
var
    I, DataBlocks, DataLength, PaddingStart, PaddingCount: integer;
begin
    BlockSize := BlockSize div 8;
    if PaddingMode in [pmZeroPadding, pmRandomPadding] then
        if Length(Data) mod BlockSize = 0 then Exit;
    DataBlocks := (Length(Data) div BlockSize) + 1;
    DataLength := DataBlocks * BlockSize;
    PaddingCount := DataLength - Length(Data);
    if PaddingMode in [pmANSIX923, pmISO10126, pmPKCS7] then
        if PaddingCount > $FF then Exit;
    PaddingStart := Length(Data);
    SetLength(Data, DataLength);
    case PaddingMode of
        pmZeroPadding, pmANSIX923, pmISO7816: // fill with $00 bytes
            FillChar(Data[PaddingStart], PaddingCount, 0);
        pmPKCS7: // fill with PaddingCount bytes
            FillChar(Data[PaddingStart], PaddingCount, PaddingCount);
        pmRandomPadding, pmISO10126: // fill with random bytes
            for I := PaddingStart to DataLength-1 do Data[I] := Random($FF);
    end;
    case PaddingMode of
        pmANSIX923, pmISO10126:
            Data[DataLength-1] := PaddingCount; // set end-marker with number of bytes added
        pmISO7816:
            Data[PaddingStart] := $80; // set fixed end-markder $80
    end;
end;
我调用函数如下:

procedure TForm1.BtnClick(Sender: TObject);
var
    s:string;
begin
    s:=EncodeAES('VMpuXJGbUNOv','kj3214ed)k32nre2');
end;
Win32/Win64/macOS 32的结果正确: E32A9DE47CC60BDB70CA27885128D17A

macOS 64的结果错误: CF6221555545E485AC3A083E8A0478493


我做错了什么?

加密操作的是二进制数据,而不是文本数据。在处理文本时,必须在加密之前将字符编码为字节,然后在解密之后将字节解码为字符。这意味着在加密之前和解密之后使用相同的字符编码。您正在尝试进行这种编码,但没有考虑到TEncoding.ANSI不能跨操作系统平台移植,甚至不能跨使用同一操作系统平台的不同机器移植。为了更好的可移植性,您需要使用一致的编码,例如TEncoding.UTF8

此外,TEncoding仅在Unicoding下运行,因此使用TEncoding.GetBytes和TEncoding.GetString与AnsiString将使用RTL的ANSI定义(而不是您的定义)在ANSI和Unicode之间执行隐式转换,如果字符串中包含任何非ASCII字符,则生成您可能不期望的字节

您的EncodeAES函数最好使用UnicodeString进行所有字符串处理,并且忘记AnsiString甚至存在。尽管像Linux这样的平台主要是UTF-8系统,但Delphi的默认Unicodestring在所有平台上都使用UTF-16。如果要对ANSI字符串进行编码,如果调用代码要使用UTF8String、AnsiStringN等,请使用RawByteString避免任何隐式转换。按原样加密8位字符,而不使用TEncoding。仅在销毁数据时使用TEncoding

最后,EncodeAES函数不应该将加密的字节解码为Unicode,而只是将其转换为十六进制字符串。您应该按原样对加密的字节进行十六进制编码

请尝试以下方法:

函数编码常量数据:t字节;常量键:字符串:字符串;超载; 常数 十六进制:字符为'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'的数组[0..15]; 变量 enc:TEncoding; iv,k,隐窝:T细胞; 密码:TDCP_rijndael; B:字节; I:整数; 开始 enc:=TEncoding.UTF8; iv:=enc.GetBytes; k:=enc.GetBytesKey; 密码:=TDCP_rijndael.Createnil; 尝试 Cipher.Initk[0],128,@iv[0]; Crypt:=CopyData,0,LengthData; BytePaddingCrypt,Cipher.BlockSize,pmPKCS7; Cipher.EncryptECBCrypt[0],Crypt[0]; 最后 密码。免费; 终止 SetLengthResult,LengthCrypt*2; I:=低结果; 在地穴里做B 开始 结果[I]:=Hex[B shr 4和$F]; 结果[I+1]:=Hex[B和$F]; IncI,2; 终止 终止 函数EncodeAESconst S,键:string:string;超载; 开始 结果:=EncodeAESTEncoding.UTF8.GetBytesS,键; 终止 函数编码常数S:RawByteString;常量键:字符串:字符串;超载; 开始 结果:=编码字节数,键; 终止
加密操作的是二进制数据,而不是文本数据。在处理文本时,必须在加密之前将字符编码为字节,然后在解密之后将字节解码为字符。这意味着在加密之前和解密之后使用相同的字符编码。您正在尝试进行这种编码,但没有考虑到TEncoding.ANSI不能跨操作系统平台移植,甚至不能跨使用同一操作系统平台的不同机器移植。为了更好的可移植性,您需要使用一致的编码,例如TEncoding.UTF8

此外,TEncoding仅在Unicoding下运行,因此使用TEncoding.GetBytes和TEncoding.GetString与AnsiString将使用RTL的ANSI定义(而不是您的定义)在ANSI和Unicode之间执行隐式转换,如果字符串中包含任何非ASCII字符,则生成您可能不期望的字节

您的EncodeAES函数最好使用UnicodeString进行所有字符串处理,并且忘记AnsiString甚至存在。尽管像Linux这样的平台主要是UTF-8系统,但Delphi的默认Unicodestring在所有平台上都使用UTF-16。如果要对ANSI字符串进行编码,如果调用代码要使用UTF8String、AnsiStringN等,请使用RawByteString避免任何隐式转换。按原样加密8位字符,而不使用TEncoding。仅在销毁数据时使用TEncoding

最后,EncodeAES函数不应该将加密的字节解码为Unicode,而只是将其转换为十六进制字符串。您应该按原样对加密的字节进行十六进制编码

请尝试以下方法:

函数编码常量数据:t字节;常量键:字符串:字符串;超载; 常数 十六进制:字符为'0','1','2'的数组[0..15] ‘3’、‘4’、‘5’、‘6’、‘7’、‘8’、‘9’、‘A’、‘B’、‘C’、‘D’、‘E’、‘F’; 变量 enc:TEncoding; iv,k,隐窝:T细胞; 密码:TDCP_rijndael; B:字节; I:整数; 开始 enc:=TEncoding.UTF8; iv:=enc.GetBytes; k:=enc.GetBytesKey; 密码:=TDCP_rijndael.Createnil; 尝试 Cipher.Initk[0],128,@iv[0]; Crypt:=CopyData,0,LengthData; BytePaddingCrypt,Cipher.BlockSize,pmPKCS7; Cipher.EncryptECBCrypt[0],Crypt[0]; 最后 密码。免费; 终止 SetLengthResult,LengthCrypt*2; I:=低结果; 在地穴里做B 开始 结果[I]:=Hex[B shr 4和$F]; 结果[I+1]:=Hex[B和$F]; IncI,2; 终止 终止 函数EncodeAESconst S,键:string:string;超载; 开始 结果:=EncodeAESTEncoding.UTF8.GetBytesS,键; 终止 函数编码常数S:RawByteString;常量键:字符串:字符串;超载; 开始 结果:=编码字节数,键; 终止
啊!!!!不会了。如此多的问题将二进制和文本视为可互换的。请让它停下来!不过,说真的,加密算法是在二进制上运行的。您的加密函数需要使用字节数组作为输入和输出。我假设当数据、crypt、iv和k变量声明为TBytes时,它们是字节数组。@Softtouch是的,但您负责跨机器/平台正确、一致地填充有效字节,您的EncodeAES代码根本没有这样做。DCPCrypt2.pas中的DCPCrypt2定义不正确。dword=longword应该是:dword=Cardinal。长字是64位Posix上的8个字节systems@DaveNottage我会选择UInt32而不是CardinalArgh!!!!不会了。如此多的问题将二进制和文本视为可互换的。请让它停下来!不过,说真的,加密算法是在二进制上运行的。您的加密函数需要使用字节数组作为输入和输出。我假设当数据、crypt、iv和k变量声明为TBytes时,它们是字节数组。@Softtouch是的,但您负责跨机器/平台正确、一致地填充有效字节,您的EncodeAES代码根本没有这样做。DCPCrypt2.pas中的DCPCrypt2定义不正确。dword=longword应该是:dword=Cardinal。长字是64位Posix上的8个字节systems@DaveNottage我会选择UInt32,而不是现在完全理解这一点。不幸的是,当要加密的字符串长度超过15个字符时,dcpcrypt组件中肯定仍有某些内容导致它失败。我使用的是正常的TMS加密包,它工作正常,但到目前为止,它们没有更新到macOS 64,我的项目无法编译,所以我正在寻找另一种解决方案。我用密钥1111111111111 15x1加密1111111111111115X1。在线工具、我自己的加密代码和其他Win32组件返回的结果都一样:FD97A42377D8235121E41640B935BDDD现在我再添加一个1,所以它是16x1。在线工具和其他Win32组件返回的结果都是一样的:AD0110483D0559D12E8CB97203E6C908F30C69C4F945E654EBD4B388B1C8F790但我自己的代码基于DCPCrypt返回:AD0110483D0559D12E8CB97203E6C90810101010101010101010101010101010我使用了上面Remy的示例代码。我做错了什么?我不明白…现在完全明白了。不幸的是,当要加密的字符串长度超过15个字符时,dcpcrypt组件中肯定仍有某些内容导致它失败。我使用的是正常的TMS加密包,它工作正常,但到目前为止,它们没有更新到macOS 64,我的项目无法编译,所以我正在寻找另一种解决方案。我用密钥1111111111111 15x1加密1111111111111115X1。在线工具、我自己的加密代码和其他Win32组件返回的结果都一样:FD97A42377D8235121E41640B935BDDD现在我再添加一个1,所以它是16x1。在线工具和其他Win32组件返回的结果都是一样的:AD0110483D0559D12E8CB97203E6C908F30C69C4F945E654EBD4B388B1C8F790但我自己的代码基于DCPCrypt返回:AD0110483D0559D12E8CB97203E6C90810101010101010101010101010101010我使用了上面Remy的示例代码。我做错了什么?我不明白。。。