DUKPT(derived unique key per Transaction)

转自 http://blog.csdn.net/jackyvictory/article/details/44156889

DUKPT(Derived Unique Key Per Transaction)是被ANSI定义的一套密钥管理体系和算法,用于解决金融支付领域的信息安全传输中的密钥管理问题,应用于对称密钥加密MAC,PIN等数据安全方面。保证每一次交易流程使用唯一的密钥,采用一种不可逆的密钥转换算法,使得无法从当前交易数据信息破解上一次交易密钥。要求收单行与终端必须同步支持该项密钥管理技术。由交易发起端点(S-TRSM,如pos,ATM)与交易接收端点(R-TRSM,如收单行)两部分组成。注:TRSM(Tamper-Resistant Security Module)是一个具备阻止攻击能力的安全模块。TRSM具有抵御攻击能力。

以下内容引用自ANSI X9.24规范文档(Retail Financial Services Symmetric Key Management)

This standard establishes requirements and guidelines for the secure management and application-level 
interoperability of keying operations. Such keys could be used for authenticating messages (see Reference 5), for 
encrypting Personal Identification Numbers (PIN) (see Reference 4), for encrypting other data, and for encrypting 
other keys.

DUKPT应用场景举例

Jacky到Wal-Mart购买了一双鞋,结帐时使用VISA信用卡刷卡,刷卡后POS需要与后台系统进行数据交互,将此交易的信息告知发卡行,交易信息的传递路径大概描述如下:

DUKPT应用场景举例

从信息传递的安全性上考虑: 
1. 上图的交易信息传递过程中,会涉及到一些敏感信息的传输,例如可能有卡片有效期、CVV2、密码等,如何保证这些信息的安全性? 
2. 每个结点如何校验接收到的数据是来自可信的相邻结点?即,如何校验数据的完整性,防止被恶意篡改

于是,聪明的孩子就想到了使用DES/T-DES算法,针对敏感数据进行加密,解决了第一个问题;使用基于DES/T-DES的MAC算法,解决了报文校验问题。(为神马是T-DES和MAC?这不重要,我们要解释的是DUKPT!)

那么问题来了,既然使用了DES/T-DES这类的对称加密算法,就一定会涉及到对称密钥的交互问题。只有保证了密钥的安全性,对称加密才有意义。

于是,DUKPT应运而生。

DUKPT流程简析

说了半天,DUKPT到底干了些神马?别急,马上为你娓娓道来。

为了说明DUKPT流程,先介绍几个基本概念:

  • BDK(Base Derivation Key):DUKPT密钥体系的根密钥,一般是一个双倍长或三倍长的T-DES密钥。一定要保证它的安全性哦!

  • KSN(Key Serial Number):一串80bit的(20 hexadecimal digits)序号,由59bit的IKSN(Initial Key Serial Number)和21bit的EC(Encryption Counter)组成。所谓的“Unique Key Per Transaction”,全靠它啦!

  • PEK(PIN Encryption Key):顾名思义,加密PIN(卡片密码)的密钥咯!一般是双倍长的T-DES密钥。

依旧引用上图,我们单看POS和Acquirer Host这两个结点之间(其它结点之间的处理,基本类似):

  1. Acquirer在布放POS到Wal-Mart时,已经提前给这台POS的安全芯片中,灌输了BDK【BDK的灌输过程,是有Acquirer的安全部门保证的哦】,并: 
    1> 生成了EC=0的Initial PEK:Initial PEK = PEK_Derive(BDK, KSN with EC=0) 
    2> 销毁了终端中的BDK(保证BDK的安全性)
  2. 当然,BDK在Acquirer Host中肯的是有保存的(不然他收到交易后怎么解密!)。别担心,一般来说Acquirer Host都是使用硬件加密机(HSM)保存密钥的,基本不会存在密钥泄漏的风险。
  3. 重头戏来啦:Jacky在POS上进行刷卡交易,此时POS做了哪些事情呢? 
    1> Current KSN = IKSN and EC++【即,Current KSN中的EC = 1】 
    2> Current PEK = PEK_Derive(Initial PEK, Current KSN) 
    3> Encrypted PIN = T-DES(Opr=Encrypt, Current PEK, Clear PIN)
  4. 至此,Encrypted PIN已经得出来啦!POS开开心心的把Encrypted PIN放到交易报文里面,送给Acquirer Host咯。
  5. 等等!POS只送出一个Encrypted PIN,真的够了吗?

    想一下,Acquirer Host收到交易报文之后,需要解密Encrypted PIN的哦!怎么解密?Clear PIN = T-DES(Opr=Decrypt, Current PEK, Encrypted PIN) 
    【淡定,这个步骤是在HSM里面做的,只有HSM知道clear PIN,Acquirer Host的软件是不知道的哦】。

    问题又来了,Acquirer Host大叫:我怎么知道Current PEK是神马?我只知道BDK啊! 
    Acquirer Host真是个笨蛋!人家POS都知道怎么算Current PEK,你咋不知道?同样的步骤算一下呗: 
    1> Initial PEK = PEK_Derive(BDK, KSN with EC=0) 
    2> Current PEK = PEK_Derive(Initial PEK, Current KSN)

    Acquirer Host再次大叫:我说了我只知道BDK啊!看看上面两个步骤的参数,我还需要Current KSN,才能算出Current PEK呢!

  6. 好吧,POS不得不承认自己的错误:不好意思刚刚只在交易报文里面塞进了Encrypted PIN,忘了把Current EC塞进去啦!

    于是,POS不得不屁颠屁颠的把Encrypted PINCurrent KSN都塞进交易报文,送给Acquirer Host 
    于是,Acquirer Host收到报文后,开开心心的解密成功,可以进行后续交易处理啦。

于是,我们总结一下上述流程:

  1. 初始化:Acquirer Host和POS交互相同的BDK,且POS中销毁BDK,仅保存由BDK分散出来的Initial PEK
  2. 发生交易时,POS的处理:再重复一遍,不就是上面的这些步骤么 
    1> Current KSN = IKSN and EC++ 
    2> Current PEK = PEK_Derive(Initial PEK, Current KSN) 
    3> Encrypted PIN = T-DES(Opr=Encrypt, Current PEK, Clear PIN) 
    4> 把Current KSNEncrypted PIN放到交易报文里面,发送给Acquirer Host
  3. 收到交易时,Acquirer Host的处理: 
    1> Initial PEK = PEK_Derive(BDK, KSN with EC=0) 
    2> Current PEK = PEK_Derive(Initial PEK, Current KSN) 
    3> Clear PIN = T-DES(Opr=Decrypt, Current PEK, Encrypted PIN) 
    4> 后续交易处理

呼…说这么多,刚解释完DUKPT的第一轮计算方式… 
想想如果是你来设计这个算法,接下来该怎么处理EC=2、EC=3…EC=n的情况呢?

我们回头看一下上文中提到的”发生交易时,POS的处理“: 
1> Current KSN = IKSN and EC++ 
2> Current PEK = PEK_Derive(Initial PEK, Current KSN) 
3> Encrypted PIN = T-DES(Opr=Encrypt, Current PEK, Clear PIN) 
4> 把Current KSN和Encrypted PIN放到交易报文里面,发送给Acquirer Host

其实这里我有些偷懒了(表打我哦…),想一下,在这个追求用户体验的年代,刷卡交易的速度一定是评估刷卡体验的重要指标。

那么,为了提高速度,怎么简化一下上述流程呢?抛开算法层面的优化,很自然的一个想法:把能提起做的事情,先提前做起来!

哪些步骤可以提前做?看看上述流程中每个步骤的入参,好像只有Clear PIN是持卡人在交易发生时输入的,其它参数不都是POS内部的数据么!

这是个好消息!这样的话,我们可以在初始化POS(想想上文提到的“初始化”流程)时,就把EC=2、EC=3…EC=n时的每个EC对应的(Current Key)i 计算出来,提前保存到POS中,交易发生时,只需要EC++并取出相应的(Current Key)i ,就万事大吉啦!

呃,好像有哪里不对的样子……哦哦哦,EC=2、EC=3…EC=n,这个n到底是多少啊?要是有个几十上百万,POS中哪有那么大的空间给你存(Current Key)i呢!要知道,POS的硬件就那么一块小板子,每一个字节都是很宝贵的哦!

该死的,又是时间和空间互换的问题,那就找个平衡点咯!于是乎,ANSI果断的找到了这个平衡点:POS中预先存储的Current Key(插一句,这些Key都是后续交易中,EC++之后才用到的Key,是不是应该叫做Future Key啊?)数量,是21个! 
【为啥是21?我咋知道!或许是这个数字比较吉利?不过想想EC的长度也是21个bit,好像发现了点儿神马哦…】

于是,POS中出现了21个寄存器,叫做Future Key Register,在POS初始化时,它们被依次填充了EC=1 … EC=21Future Key

于是,我们更新一下POS初始化的流程: 
1> Acquirer给POS灌输BDK 
2> Initial PEK = PEK_Derive(BDK, KSN with EC=0) 
3> 
(Future Key)1 = PEK_Derive(Initial PEK, KSN with EC=1) -> (Future Key Register)1 
(Future Key)2 = PEK_Derive(Initial PEK, KSN with EC=2) -> (Future Key Register)2 
…… 
(Future Key)21 = PEK_Derive(Initial PEK, KSN with EC=21) -> (Future Key Register)21 
4> 为了保证密钥安全性,别忘了销毁BDKInitial PEK

ok啦,POS曰:万事大吉,坐等刷卡!

那么,21个Future Key用完了咋办?当然后面接着生成啦。这里就有2个新问题了:

  1. 比较明显的问题:什么时机去生成和更新EC=22、EC=23…的Future Key?

    既然POS中只有21个寄存器,那当然得物尽其用啦!反正EC又不会重复使用(EC++操作是有上限的哦,后面会提到),EC=1的Future Key用过一次之后,就木有用啦!

    那就在POS的第一笔交易处理完成后,把(Future Key Register)1中保存的Key,更新成(Future Key)22吧!这样既不影响交易处理效率,又可以充分利用空间,多好啊!

  2. 比较隐晦的问题:(Future Key)22是怎么生成的呢?

    最直接的想法,跟(Future Key)1采用同样的方式呗: 
    (Future Key)22 = PEK_Derive(Initial PEK, KSN with EC=22) -> (Future Key Register)1

    Stop!POS曰:我去哪儿找Initial PEK啊?之前初始化的第4步里面,已经把这玩意儿销毁了哎!

    呃,有点儿麻烦了,是之前不应该销毁Initial PEK吗?可是如果不销毁,后续所有的Key,都由Initial PEK分散得到的话,那这个Initial PEK可是个相当重要、相当机密的东东啦!

    嘿,换个思路如何?我现在是要生成(Future Key)22,而它要占用的地盘儿(寄存器),正是(Future Key Register)1,那我干脆就用(Future Key)1来分散得到(Future Key)22吧!

    于是: (Future Key)22 = PEK_Derive( (Future Key)1 , KSN with EC=22) -> (Future Key Register)1

ok,总算是把(Future Key)22搞定了,接下来就好说啦,以此类推呗: 
(Future Key)23 = PEK_Derive( (Future Key)2 , KSN with EC=23) -> (Future Key Register)2 
(Future Key)24 = PEK_Derive( (Future Key)3 , KSN with EC=24) -> (Future Key Register)3 
…… 
(Future Key)42 = PEK_Derive( (Future Key)21 , KSN with EC=42) -> (Future Key Register)21

哦,又是21,好巧哦,又是一个轮回啊!接下来咋办? 
(Future Key)43 = PEK_Derive( (Future Key)? , KSN with EC=43) -> (Future Key Register)?

好办啊!跟(Future Key)22一样处理呗: 
(Future Key)43 = PEK_Derive( (Future Key)22 , KSN with EC=43) -> (Future Key Register)1 
……

其实前文已经将DUKPT算法解释的差不多了,需要进一步说明的,就是Future Key的计算了。其实之前已经推理了一大堆了,我就直接把结果贴出来吧:

EC共有21个bit,每个bit可能的取值为“0”“1”,那么如此多的EC,可以形成一棵树状结构: 
这里写图片描述

说明一下,这棵树的组成是这样的:

  • 层次:树的每一层,EC中包含的bit为“1”的数量是固定的;即 
    • 0层的EC中,包含0个bit的“1”
    • 1层的EC中,包含1个bit的“1”
    • 2层的EC中,包含2个bit的“1”
  • 子结点:每个结点的子结点,均保留本结点的EC中所有为“1”的bit,并将最右侧的“1”后面的“0”,依次替换为“1”;例如 
    • EC=(1000)2的结点,有(1100)2(1010)2(1001)2这3个子节点
    • EC=(1100)2的结点,有(1110)2(1101)2这2个子结点
  • 深度:为保证算法效率,DUKPT规定,上面那棵树的最大深度为10,即 
    • 有效的EC中,包含“1”的bit个数 <= 10
    • 计算过程中遇到无效的EC,直接跳过
    • 这样的话,有效的EC个数为100多万个(
  • Future Key:与EC是对应的 
    • 每个EC,对应一个Future Key
    • 子结点EC的Future Key,是被父结点EC的Future Key加密的
    • 即,上面的那棵树,就是一棵Future Key计算体系的树

好啦,DUKPT基本上就是这样了

哦对了,再补充一句: 
上述流程只讲解到了Future Key,但实际用于数据(如PIN、MAC等)加密的,其实不是直接拿Future Key来用的,而是Future Key xor 分散向量得到的工作密钥

  • PIN密钥的分散向量:00000000000000FF00000000000000FF
  • MAC密钥的分散向量:000000000000FF00000000000000FF00 
    【其它的分散向量好像还有,但没有在ANSI x9.24规范(2004版)中提及】

o啦,大功告成,默默匿了~~~ :)

话说看到评论才发现,全文对于PEK_DERIVE的步骤,没有进行明确说明,⊙﹏⊙b汗 
不多说,直接上图吧 
这里写图片描述
简要说明:

  1. 黄色底色的2个框框,是PEK_DERIVE的2个入参;绿色底色的框框,是PEK_DERIVE的结果

  2. 图中的“Set Bit”(右边KSN的黄色框框 下面的步骤),是一个很简单的步骤:

    • 取KSN中最右边的21bit的EC(例如,01100000…1000,共21bit)
    • 得到EC中最右侧的bit “1”(01100000…1 000)
    • 将EC其余bit置为0,即获得Set Bit的结果(00000000…1 000)

That`s all~~~

  • 4
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值