从 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 进行处理的。

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

透过 Delphi 使用二进位金钥做 AES 加密.的更多相关文章

  1. 使用php扩展mcrypt实现AES加密

    AES(Advanced Encryption Standard,高级加密标准)是美国联邦政府采用的一种区块加密标准.这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用.Rijndael是 ...

  2. 【5】JMicro其于RSA及AES加密实现安全服务调用

    JMicro是基于Java实现的微服务平台,最近花了两个周未实现服务间安全调用支持. JMicro服务调用分两个部份,分别为内部服务间相互调用和外部客户端通过API网关调用JMicro集群内部服务,前 ...

  3. [Java 实现AES加密解密]

    今天同学请教我这个问题,被坑了次…… 实现的功能是2个Java类:一个读取源文件生成加密文件,另一个类读取加密文件来解密. 整个过程其实很简单,java有AES的工具包,设好秘钥,设好输入内容,就得到 ...

  4. ruby AES加密解密

    最近和京东合作做一个项目,在接口对接传递参数时,参数需要通过AES加密解密. 本来想到用gem 'aescrypt'处理,但是aescrypt的编码方式用的base64,而京东那边用的是16进制.所以 ...

  5. 【Python】 基于秘钥的对称加密

    [Crypto] 关于用python进行信息的加密,类似的解决方案有很多比如用base64编码进行encode,再或者是hashlib来进行hash.但是还缺少一种明明场景很简单的解决方案,就是把利用 ...

  6. java与C#、.NET AES加密、解密 解决方案

      1.情景展示 Java提供的密钥,C#无法解密. 2.原因分析 在Java中,AES的实际密钥需要用到KeyGenerator 和 SecureRandom,但是C#和.NET 里面没有这2个类, ...

  7. 你真的了解字典(Dictionary)吗? C# Memory Cache 踩坑记录 .net 泛型 结构化CSS设计思维 WinForm POST上传与后台接收 高效实用的.NET开源项目 .net 笔试面试总结(3) .net 笔试面试总结(2) 依赖注入 C# RSA 加密 C#与Java AES 加密解密

    你真的了解字典(Dictionary)吗?   从一道亲身经历的面试题说起 半年前,我参加我现在所在公司的面试,面试官给了一道题,说有一个Y形的链表,知道起始节点,找出交叉节点.为了便于描述,我把上面 ...

  8. 使用Python进行AES加密和解密

    摘录于:http://blog.csdn.net/nurke/article/details/77267081 另外参考:http://www.cnblogs.com/kaituorensheng/p ...

  9. AES加密、解密工具类

    AES加密.解密工具类代码如下: package com.util; import java.io.IOException; import java.io.UnsupportedEncodingExc ...

随机推荐

  1. 【C++】指针与引用的区别

    本文主要总结在C++中指针与引用的区别. 从定义与性质来看指针与引用有如下区别: 指针表示的是一块变量的地址 引用表示一个变量的别名. 因此指针变量需要占用空间(一个指针变量在32位系统下占用4字节, ...

  2. as3中去掉字符串两边的空格,换行符

     as3 去掉字符串两边的空格,换行符,方法一  ActionScript Code  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20   pub ...

  3. 老李分享:Web Services 特性 1

    老李分享:Web Services 特性   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq:9 ...

  4. hdu 2516 取石子游戏 (斐波那契博弈)

    题意:1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍. 取完者胜,先取者负输出"Second win",先取者胜 ...

  5. Android Google AdMob 广告接入示例

    Android Google AdMob 广告接入示例 [TOC] 首先请大家放心,虽然 Google搜索等服务被qiang了,但是 广告服务国内还是可以用的,真是普天同庆啊~~~噗! 其实这篇文章也 ...

  6. 伸展树(Splay树)的简要操作

    伸展树(splay树),是二叉排序树的一种.[两个月之前写过,今天突然想写个博客...] 伸展树和一般的二叉排序树不同的是,在每次执行完插入.查询.删除等操作后,都会自动平衡这棵树.(说是自动,也就是 ...

  7. 移植 DeepinQQ 到 Fedora 中

    本着自由/开源软件的分享精神创作此文,如有任何权力侵害请联系我,我将积极配合. 移植 DeepinQQ 到 Fedora 中 --也不知道是用移植还是迁移更合适 写在前面 首先,在这里要感谢武汉深之度 ...

  8. mac下CSV文件用FileReader、FileWriter读写乱码

      先说下windows的excel文件搬到mac下打开为什么会显示乱码.    在win下,excel采用GBK编码,1个汉字是存为2个字节,而mac下各种软件广泛默认使用UTF-8编码方式,如在e ...

  9. Bug 笔记

    1.页面返回 400 Bag request: 原因:使用Spring  MVC  controller的时候,查询数据库:当数据库的数据类型是int型时,Spring MVC在查询的数据匹配给实体类 ...

  10. angular apply

    <div ng-controller="firstController"> {{date}} </div> <script> var first ...