從 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)對文字進行加解密,執行起來的畫面也很清楚,筆者做了一點點修改,修改後的執行畫面如下圖所示:
左圖是未執行加密作業前的畫面,右圖則是執行了加密作業之後的畫面。原始的範例程式中,只支援完整的字串作為 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 進行處理的。
寫到這裡,說明的差不多了,範例程式專案我也準備好了,有興趣的讀者請自行取用吧。範例在此。