Delphi是一种通过使用Object Pascal快速开发本机Windows,macOS,Linux,iOS和Android应用程序的语言。该名称是指Delphi语言及其库,编译器和IDE,用于帮助编辑和调试Delphi项目。
我正在使用delphi,当我执行openpicturedialog时,我想要一个目录中所有文件的列表。 即,当执行打开对话框时并且 我从中选择一个文件,我想要 列表...
我的IDE是Delphi 10.3。 我有一个 Firebird 2.5 表,附件字段类型是 Binary Blob。我可以打开此存储的文件(图像、word、excel、pdf、txt...)而不保存到磁盘吗? 如果这不是
Delphi (FMX):Windows 中的 DCPCrypt2 在 Android/IOS 中产生不同的结果
我正在尝试编写一个函数,该函数在 Delphi (RAD Studio 10.2) 中返回与 PHP 中的以下代码相同的结果: 我正在尝试编写一个在 Delphi (RAD Studio 10.2) 中返回与 PHP 中的以下代码相同的结果的函数: <?php $method = 'AES-256-CTR'; $data = 'Hello, world!'; $key = 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuini'; $vector = 'bf49ea9d61104d8c'; $crypt = openssl_encrypt($data, $method, $key, 0, $vector); echo $crypt; ?> 我在 Pascal 中提出了这个函数(使用 David Barton 编写的 DCPcrypt v2.1 库): procedure TMainForm.Encrypt1ButtonClick(Sender: TObject); var Cipher: TDCP_rijndael; Key, Vector: RawByteString; Data, Crypt: RawByteString; begin Data := 'Hello, world!'; SetLength(Crypt, Length(Data)); Key := 'bRuD5WYw5wd0rdHR9yLlM6wt2vteuini'; Vector := 'bf49ea9d61104d8c'; Cipher := TDCP_rijndael.Create(nil); try Cipher.Init(Key[1], 256, @Vector[1]); Cipher.EncryptCTR(Data[1], Crypt[1], Length(Data)); finally Cipher.Free; end; EncryptEdit.Text := DCPBase64.Base64EncodeStr(Crypt); end; 这确实有效(在 Windows 中)。 PHP 和 Pascal 都返回:pEP16OOxov9QDfraIg== 但是,如果我为 Android 编译相同的代码并在平板电脑上运行它,我会得到非常不同的结果。这是为什么? 我确实阅读了有关转换 fmx 代码的文档,特别是处理字符串处理的内容,但我仍然不明白为什么。即使 RawByteString 是基于 0 而不是基于 1,我仍然会得到差异(尝试使用 [0] 而不是 [1])。 RawByteString 没有附加代码页,对吧?所以这个问题不可能是由某些字符串转换引起的(我认为)。那么这是怎么回事? 经过3天的努力,我终于成功了。关键是完全消除字符串的使用,并且仅使用 DCPCrypt 中基于 TByte 的例程。 下面的代码是一个测试程序,用于测试 DCPCrypt 支持的所有不同链接模式。我还添加了一个函数来实现我在这里找到的四种填充模式(与 CBC 和 ECB 一起使用): https://en.wikipedia.org/wiki/Padding_(密码学) 以及零填充和随机填充。 我选择不使用 DCPCrypt 自己的 Base64 函数,因为它们与 FMX 不兼容。相反,我使用 System.NetEncoding 单元中的对应项。 拜托,我认为自己只是一个普通的程序员,所以我希望你们当中真正的 Delphi 奇才能够找到很多可以批评的地方。但没关系。如果给出良好的反馈,我将调整代码。 现在,代码可以运行并生成与 PHP 的 openssl 函数兼容的结果(使用 CTR 模式进行测试)。我只是在这里发布此内容,希望它对寻找与我相同的解决方案的人有用。 unit MainUnit; interface uses System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants, System.NetEncoding, FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, FMX.StdCtrls, FMX.Layouts, FMX.ScrollBox, FMX.Memo, FMX.Edit, FMX.Controls.Presentation, DCPcrypt2, DCPsha256, DCPblockciphers, DCPrijndael; type TChainingMode = (cmCBC, cmCFB8bit, cmCFBblock, cmOFB, cmCTR, cmECB); TPaddingMode = (pmZeroPadding, pmANSIX923, pmISO10126, pmISO7816, pmPKCS7, pmRandomPadding); type TMainForm = class(TForm) ScrollBox: TScrollBox; KeySizeLabel: TLabel; ChainingLabel: TLabel; EncodingLabel: TLabel; PaddingLabel: TLabel; KeyLabel: TLabel; InitVectorLabel: TLabel; DataLabel: TLabel; DecryptedLabel: TLabel; CipherLabel: TLabel; EncryptedLabel: TLabel; rbRijndael: TRadioButton; rb128bit: TRadioButton; rb256bit: TRadioButton; rbANSI: TRadioButton; rbUTF8: TRadioButton; rbUnicode: TRadioButton; rbCBC: TRadioButton; rbOFB: TRadioButton; rbCTR: TRadioButton; rbECB: TRadioButton; rbCFB8bit: TRadioButton; rbCFBblock: TRadioButton; rbZeroPadding: TRadioButton; rbANSIX923: TRadioButton; rbISO10126: TRadioButton; rbISO7816: TRadioButton; rbPKCS7: TRadioButton; rbRandomPadding: TRadioButton; KeyEdit: TEdit; InitVectorEdit: TEdit; DataMemo: TMemo; EncryptedMemo: TMemo; DecryptedMemo: TMemo; EncryptButton: TButton; DecryptButton: TButton; procedure FormCreate(Sender: TObject); procedure EncryptButtonClick(Sender: TObject); procedure DecryptButtonClick(Sender: TObject); public procedure GetOptions(var Key: TBytes; var KeySize: integer; var InitVector: TBytes; var Encoding: TEncoding; var ChainingMode: TChainingMode; var PaddingMode: TPaddingMode); end; var MainForm: TMainForm; implementation {$R *.fmx} {$R *.LgXhdpiPh.fmx ANDROID} function BytesToHex(B: TBytes): string; var I: integer; begin Result := ''; for I := Low(B) to High(B) do Result := Result + IntToHex(B[I]) + ' '; end; procedure BytePadding(var Data: TBytes; BlockSize: integer; PaddingMode: TPaddingMode); // Supports: ANSI X.923, ISO 10126, ISO 7816, PKCS7, zero padding and random padding var I, DataBlocks, DataLength, PaddingStart, PaddingCount: integer; begin BlockSize := BlockSize div 8; // convert bits to bytes // Zero and Random padding do not use end-markers, so if Length(Data) is a multiple of BlockSize, no padding is needed 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); // ANSIX923, ISO10126 and PKCS7 store the padding length in a 1 byte end-marker, so any padding length > $FF is not supported 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 EncryptAES(const Data: TBytes; var Crypt: TBytes; const Key: TBytes; KeySize: integer; const InitVector: TBytes; ChainingMode: TChainingMode; PaddingMode: TPaddingMode); overload; var Cipher: TDCP_rijndael; begin Cipher := TDCP_rijndael.Create(nil); try Cipher.Init(Key[0], KeySize, @InitVector[0]); // Copy Data => Crypt Crypt := Copy(Data, 0, Length(Data)); // Padd Crypt to required length (for Block based algorithms) if ChainingMode in [cmCBC, cmECB] then BytePadding(Crypt, Cipher.BlockSize, PaddingMode); // Encrypt Crypt using the algorithm specified in ChainingMode case ChainingMode of cmCBC: Cipher.EncryptCBC(Crypt[0], Crypt[0], Length(Crypt)); cmCFB8bit: Cipher.EncryptCFB8bit(Crypt[0], Crypt[0], Length(Crypt)); cmCFBblock: Cipher.EncryptCFBblock(Crypt[0], Crypt[0], Length(Crypt)); cmOFB: Cipher.EncryptOFB(Crypt[0], Crypt[0], Length(Crypt)); cmCTR: Cipher.EncryptCTR(Crypt[0], Crypt[0], Length(Crypt)); cmECB: Cipher.EncryptECB(Crypt[0], Crypt[0]); end; finally Cipher.Free; end; end; procedure DecryptAES(const Crypt: TBytes; var Data: TBytes; const Key: TBytes; KeySize: integer; const InitVector: TBytes; ChainingMode: TChainingMode; PaddingMode: TPaddingMode); overload; var Cipher: TDCP_rijndael; I: integer; begin Cipher := TDCP_rijndael.Create(nil); try Cipher.Init(Key[0], KeySize, @InitVector[0]); // Copy Crypt => Data Data := Copy(Crypt, 0, Length(Crypt)); // Decrypt Data using the algorithm specified in ChainingMode case ChainingMode of cmCBC: Cipher.DecryptCBC(Data[0], Data[0], Length(Data)); cmCFB8bit: Cipher.DecryptCFB8bit(Data[0], Data[0], Length(Data)); cmCFBblock: Cipher.DecryptCFBblock(Data[0], Data[0], Length(Data)); cmOFB: Cipher.DecryptOFB(Data[0], Data[0], Length(Data)); cmCTR: Cipher.DecryptCTR(Data[0], Data[0], Length(Data)); cmECB: Cipher.DecryptECB(Data[0], Data[0]); end; // Correct the length of Data, based on the used PaddingMode (only for Block based algorithms) if ChainingMode in [cmCBC, cmECB] then case PaddingMode of pmANSIX923, pmISO10126, pmPKCS7: // these modes store the original Padding count in the last byte SetLength(Data, Length(Data) - Data[Length(Data)-1]); pmISO7816: // this mode uses a fixed end-marker. Find it and correct length accordingly. for I := Length(Data)-1 downto 0 do if Data[I] = $80 then begin SetLength(Data, I); Break; end; end; finally Cipher.Free; end; end; procedure TMainForm.FormCreate(Sender: TObject); begin EncryptedMemo.Lines.Clear; DecryptedMemo.Lines.Clear; end; procedure TMainForm.GetOptions(var Key: TBytes; var KeySize: integer; var InitVector: TBytes; var Encoding: TEncoding; var ChainingMode: TChainingMode; var PaddingMode: TPaddingMode); begin KeySize := 256; Encoding := TEncoding.ANSI; ChainingMode := cmCBC; PaddingMode := pmPKCS7; if rb128bit.IsChecked then KeySize := 128; if rb256bit.IsChecked then KeySize := 256; if rbCBC.IsChecked then ChainingMode := cmCBC; if rbCFB8bit.IsChecked then ChainingMode := cmCFB8bit; if rbCFBblock.IsChecked then ChainingMode := cmCFBblock; if rbOFB.IsChecked then ChainingMode := cmOFB; if rbCTR.IsChecked then ChainingMode := cmCTR; if rbECB.IsChecked then ChainingMode := cmECB; if rbZeroPadding.IsChecked then PaddingMode := pmZeroPadding; if rbANSIX923.IsChecked then PaddingMode := pmANSIX923; if rbISO10126.IsChecked then PaddingMode := pmISO10126; if rbISO7816.IsChecked then PaddingMode := pmISO7816; if rbPKCS7.IsChecked then PaddingMode := pmPKCS7; if rbRandomPadding.IsChecked then PaddingMode := pmRandomPadding; if rbANSI.IsChecked then Encoding := TEncoding.ANSI; if rbUTF8.IsChecked then Encoding := TEncoding.UTF8; if rbUnicode.IsChecked then Encoding := TEncoding.Unicode; Key := Encoding.GetBytes(KeyEdit.Text); InitVector := Encoding.GetBytes(InitVectorEdit.Text); end; procedure TMainForm.EncryptButtonClick(Sender: TObject); var Keysize: integer; Encoding: TEncoding; ChainingMode: TChainingMode; PaddingMode: TPaddingMode; Key, InitVector, Data, Crypt: TBytes; begin GetOptions(Key, KeySize, InitVector, Encoding, ChainingMode, PaddingMode); Data := Encoding.GetBytes(DataMemo.Text); EncryptAES(Data, Crypt, Key, KeySize, InitVector, ChainingMode, PaddingMode); EncryptedMemo.Text := TNetEncoding.Base64.EncodeBytesToString(Crypt); end; procedure TMainForm.DecryptButtonClick(Sender: TObject); var Keysize: integer; Encoding: TEncoding; ChainingMode: TChainingMode; PaddingMode: TPaddingMode; Key, InitVector, Data, Crypt: TBytes; begin GetOptions(Key, KeySize, InitVector, Encoding, ChainingMode, PaddingMode); Crypt := TNetEncoding.Base64.DecodeStringToBytes(EncryptedMemo.Text); DecryptAES(Crypt, Data, Key, KeySize, InitVector, ChainingMode, PaddingMode); DecryptedMemo.Text := Encoding.GetString(Data); end; end. Android 字符串从位置 0 开始。您可以使用 low(Data) 返回字符串的第一个字符,库内部也使用从位置 1 开始的字符串,这不会在 android 或 ios 中运行。对于多平台,我们不应该使用 for i:=1 to length(string) 而应该使用 for l in string 我认为LockBox3应该可以解决你的问题。 我在这里面临着同样的问题,并且想运行您测试应用程序。能提供一下fmx表格的源码吗? 非常感谢!
如何使用 Delphi 将各种文档类型添加到 Firebird BLOB 字段
背景:我们的产品包括一个文档管理系统,允许用户保存和检索各种文档类型(.PDF、.DOC、.JPG、.PNG、.TIF 等)。目前
使用 mongo-delphi-driver 获取具有特定 _id 的文档
我必须在mongodb上执行查询,我想仅选择具有特定_id(类型ObjectId)的文档。 我使用“严格模式”语法,特别是运算符 $oid 将 _id 与
我想使用 doxygen + pas2dox 记录我的源代码。当我设置好所有内容(包括过滤器和提取选项(提取所有内容))时,doxygen 运行良好。但是生成的文档...
如何使用 Delphi 10(西雅图)在 Excel 中合并 2 个单元格
互联网上曾经有很多Delphi参考资料。我尝试用谷歌搜索,我从黛博拉·佩特 (Deborah Pate) 那里获得的 com 编程的首选现在给了我一个 404 页面未找到!不好了! 无论如何,我正在使用...
如何在 Delphi 中将带有图像的 RichText (RTF) 文档转换为 HTML?
我一直在尝试找到一个免费的(最好是开源的)组件或库,它可以将嵌入图像的 RTF 文件转换为 HTML 文件和图像文件或更好的 HTML 和图像
当最大化表单时(即使在 IDE 设计器中),Delphi 表单会出现不正确的行为,为什么?
这是完整 Delphi 应用程序的精简版本。 即使在Delphi7 IDE设计器中,当双击窗体的标题时,窗体也会错误地最大化,这意味着左上角
Google Oauth2 出现 invalid_grant 错误问题
大家加油, 我们一直在深入阅读关于从 google 交换 access_token 的 google 文档,以便我们的(delphi)桌面应用程序从服务器端与 google 进行 SSO。这是 p...
我用 pascal 编写了一个程序,使用 sam api 启用/禁用“密码必须满足复杂性要求”。每个函数都会返回 STATUS_SUCCESS,除了 SamSetInformationD...
编写一段代码,将一个数字分为几个不同的区间,并对每个区间进行特殊计算
我想编写一段代码,将一个数字分为几个不同的区间,并对每个区间进行特殊计算,如下所示。 最后,显示所有获得的数字的总和。我...
如何使用 TIdMessage 处理将内联图像分隔到不同边界的 MIME 格式?
我的 MIME 格式如下: 内容类型:多部分/替代;边界=“qawqKLHOZYgscUPhZKw5hacv=_UlERjiEj” MIME 版本:1.0 日期:2024 年 3 月 25 日星期一 10:17:34 +0800 这是一个多...
假设我的字符串是: “狐狸跳过了圆木。” 那么它应该变成: “狐狸跳过了圆木。” 实现这一目标最简单的(1-3行)是什么,
我需要将用 Delphi 编程语言编写的程序转换为 C#,但我遇到了问题。 我无法找出正确的转换。任何帮助都会很棒。 我有注意...
我正在将低级 C 库转换为 Delphi 编程语言。 我发现很多演员。我觉得这在C世界很正常。我认为我可以安全地将它们扔掉。仅此处整数为 32 位。
我有一个用 Delphi 编程语言编写的古老但非常复杂的算法,我想将其用作 Java 项目的服务。 我的计划是建立一个可以为算法提供服务的网站
Delphi 在 Visual Studio IDE 上可用吗?
我已经决定(无论是好还是坏),开始学习 Delphi 编程语言。但是,它在 Visual Studio 中可用吗?或者有适合它的IDE吗?我用谷歌搜索了 Delphi,但是 cam...
我想尝试制作一些用于个人/学习目的的简单游戏。我所说的简单游戏是指平台游戏、迷宫游戏、街机游戏等游戏。我也想有一天创建一个
我有一个 TWebScrollBox,里面有很多元素,但我不喜欢其中默认滚动条的颜色。 这是我在 TWebScrollBox 上的滚动条: 你可以看到滚动条由两个