透过 Delphi 使用二进位金钥做 AES 加密.

时间:2021-07-30 02:55:39

从 1994 年开始,笔者就开始接触加密与网路安全的世界,从鲁立忠老师的指导当中获益良多,后来在*的元智大学就读研究所的时候,也以此为研究主题。

在当时,电子商务是显学,Visa跟 Master Card还特别为了网路交易制作了厚厚三大本的商务通讯协定,命名为SET (Secure Electronic Transaction,安全电子交易),从客户端、商店端、银行端定义了绵绵密密的交易规范。

然而,网际网路的世界跟 Visa Master Card所熟悉的专用网路世界差的远了,不是大狗们(Big dogs)说了算,很快的 SSL 128 被吹捧成『最安全的交易保护机制』,每年透过这『最安全的交易保护机制』成交的金额越攀越高。

破解网路而得逞的网路诈欺,始终维持在一个很低的比例,反而从商家端流出的诈欺资料年年创新高,SET也很快的成为一个历史名词。

但是,SET所本的一些加密基础,并没有就此被埋没。X.509电子凭证、RC4, RC5, DES, 3-DES, RSA, SHA-1, SHA256, SHA-2, 还有我们这次要介绍的AES,也不断的推陈出新,在世界上蓬勃发展。这些听了令人打呵欠的主题跟名词,在很多地方都会被用上,只是用了不同的面貌呈现给使用者而已。

像是在*的自然人凭证、健保卡里面,都有个人电子凭证(X.509),每年五月我们在*都可以用这两种凭证进行网路报税。

或是像在*的电子发票,当中就需要用到 AES 加密,依据『纸本电子发票二维条码内容规范』第五页所述:

在纸本电子发票左方的二维条码里面,就需要用到 AES 对发票字轨10码及随机码4码以字串方式合并后使用AES加密,并采用Base64编码转换。

但是,在Delphi里面好像没有可以直接使用AES加密的单元可以使用。笔者在硕士论文的程式撰写时,使用的是OpenSSL 0.4的函式库,当时还叫做SSLeay呢。但是,这作法只能在Windows 平台上面顺顺的用,有没有什么方法可以让我们在不同的作业系统下都能顺利使用 AES 呢?

经过约莫两三个小时上穷碧落下黄泉的搜寻,找到了一个在 SourceForge 上面的加密范例程式,更棒的是,它是用 Delphi + FireMonkey 写的,不使用 DLL,而是使用纯粹的Pascal 写的 (感谢 Eldos 的 OpenSource, 但直接到 Eldos 网站的连结目前已经找不到了)。

换句话说,这是一个跨平台都可以正常运作的 Delphi 程式,不用依靠载入的 DLL 或 Lib,用这个范例来制作电子发票的验证加密字串,就能够很方便的达成了。

Source Forge 的范例程式可以从这个连结下载,下载之后,请看到里面的范例专案『FlyUtilsAESCBC.dproj』,这个范例程式中,,支援用字串作为AES加密金钥(Key)对文字进行加解密,执行起来的画面也很清楚,笔者做了一点点修改,修改后的执行画面如下图所示:

透过 Delphi 使用二进位金钥做 AES 加密.

 

透过 Delphi 使用二进位金钥做 AES 加密.

左图是未执行加密作业前的画面,右图则是执行了加密作业之后的画面。原始的范例程式中,只支援完整的字串作为 AES 金钥,但我们常会用到二进位资讯来做金钥,这种情形下,金钥通常也会经过Base64编码过。

所以笔者稍微改写了一个function,新增了一个按钮,就是画面最底下的『AES加密with Byte Key』这个按钮的event handler。

如果点选按钮是 AES加密,则Key里面的字串不会被做任何处理,直接会被当成AES金钥,点选的如果是最底下的『AES加密with Byte Key』,则Key里面的字串会先被做Base64 解码,变成二进位资讯,AES金钥就是这些二进位资讯了。

procedure TFormMain.Button1Click(Sender: TObject); var KeyBit: TKeyBit; APaddingMode: TPaddingMode; begin KeyBit := TKeyBit.kb256; APaddingMode := TPaddingMode.pmZeroPadding; Memo2.text := AESEncryptStrToBase64_Base64Key(Memo1.Text, Edit1.text, TEncoding.UTF8, KeyBit, ‘‘, APaddingMode, CheckBoxCBC.IsChecked, rlCRLF, rlCRLF, Process); end;

这儿的 AESEncryptStrToBase64_Base64Key 是笔者照着原本 Eldos 的程式做了一点小手脚,方便大家把电子发票平台取得的金钥直接贴上来就能用:

function AESEncryptStrToBase64_Base64Key(Value, Key: string; StrEncoding: TEncoding = nil; KeyBit: TKeyBit = kb128; InitVectorStr: string = ‘‘; APaddingMode: TPaddingMode = TPaddingMode.pmPKCS5or7RandomPadding; CBCMode: Boolean = True; ValueCRLFMode: TCRLFMode = rlCRLF; KeyCRLFMode: TCRLFMode = rlCRLF; OnProcessProc: TOnProcessProc = nil; ProcessProc: TProcessProc = nil): string; var tStrm : TBytesStream; keyBytes: TBytes; IVBytes: TBytes; IdDecoderMIME1 : TIdDecoderMIME; begin tStrm := TBytesStream.create; IdDecoderMIME1 := TIdDecoderMIME.Create(nil); try IdDecoderMIME1.DecodeBegin(tStrm); IdDecoderMIME1.Decode(Key); IdDecoderMIME1.DecodeEnd; keyBytes := tStrm.Bytes; finally tStrm.Free; end; tStrm := TBytesStream.create; try IdDecoderMIME1.DecodeBegin(tStrm); IdDecoderMIME1.Decode(InitVectorStr); IdDecoderMIME1.DecodeEnd; IVBytes := tStrm.Bytes; finally tStrm.Free; end; IdDecoderMIME1.Free; Result := EncodeBase64Bytes(AESEncryptStr_BytesKey(Value, keyBytes, IVBytes, TEncoding.UTF8, KeyBit, APaddingMode, CBCMode, ValueCRLFMode, KeyCRLFMode, OnProcessProc, ProcessProc)); end;