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

时间:2023-03-09 01:31:33
透过 Delphi 使用二进位金钥做 AES 加密.

从 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 加密,依据『纸本电子发票二维条码内容规范』第五页所述:

透过 Delphi 使用二进位金钥做 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;

单独使用这个 function 的话,ProcessProc 参数可以给 nil, 这是用来让大家看到有进度列可以显示处理进度用的,通常这些处理是在背景进行,没有介面的时候直接给个 nil, 就可以不用管进度条了。

大家可以看到,上面的程式码里面,笔者使用了Indy的 Base64解码元件『IdDecoderMIME』,因为一来它是原本 Delphi 安装就内建的,使用上比较方便,二来笔者也熟悉这套元件,所以不另外找其他元件了。

AES 里面除了 Key 之外,还可以指定 IV (initialization vector), 如果使用上需要使用二进位的 IV, 您可以把二进位的 IV 先做好 Base64 编码,这个 function 也会将它先做 Base64 解码之后,作为 IV 进行处理的。

写到这里,说明的差不多了,范例程式专案我也准备好了,有兴趣的读者请自行取用吧。范例在此