8

为了

`BDK = "0123456789ABCDEFFEDCBA9876543210"` `KSN = "FFFF9876543210E00008"` 

生成的密文如下

"C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12"`

我在这里找到的。我知道这个密文是基于 BDK 和 KSN 的,但是这个 128 长度的密文是如何生成的呢?它涉及哪些步骤或用于此的算法?有人可以用简单的步骤解释一下。我发现很难理解我在谷歌搜索时得到的文件。

4

4 回答 4

15

关于DUKPT , Wiki上给出了一些解释。如果这还不够,这里有一些简短的解释。

引用http://www.maravis.com/library/derived-unique-key-per-transaction-dukpt/

什么是 DUKPT?

Derived Unique Key Per Transaction (DUKPT) 是一种密钥管理方案。它使用从加密的实体(或设备)和解密数据的实体(或设备)共享的秘密主密钥派生的一次性加密密钥。为什么选择 DUKPT?任何加密算法都仅与其密钥一样安全。如果用于使用该算法加密数据的密钥不安全,那么最强的算法将毫无用处。这就像用最大最强的锁锁住你的门,但如果你把钥匙藏在门垫下面,锁本身就没有用了。当我们谈论加密时,我们还需要记住,数据必须在另一端解密。通常,任何加密方案中最薄弱的环节是加密方和解密方之间的密钥共享。DUKPT 试图确保双方都可以加密和解密数据,而无需传递加密/解密密钥。VISA 发布的加密最佳实践文档还建议使用 DUKPT 来实现 PCI DSS 合规性。

DUKPT 的工作原理

DUKPT 使用一次性密钥,为每笔交易生成然后丢弃。这样做的好处是,如果其中一个密钥被泄露,那么只有一个事务会被泄露。使用 DUKPT,发起方(例如,PIN 输入设备或 PED)和接收方(处理器、网关等)共享一个密钥。此密钥实际上并未用于加密。相反,从该主密钥派生的另一个一次性密钥用于加密和解密数据。重要的是要注意,主密钥不应从派生的一次性密钥中恢复。要解密数据,接收端必须知道使用哪个主密钥来生成一次性密钥。这意味着接收端必须存储和跟踪每个设备的主密钥。对于支持很多设备的人来说,这可能是很多工作。需要更好的方法来处理这个问题。这就是它在现实生活中的工作方式:接收者有一个称为基本派生密钥 (BDK) 的主密钥。BDK 应该是保密的,永远不会与任何人共享。此密钥用于生成称为初始 Pin 加密密钥 (IPEK) 的密钥。由此生成一组称为 Future Keys 的密钥并丢弃 IPEK。每个 Future 密钥都由设备制造商嵌入到 PED 中,并与他们共享这些密钥。这个额外的推导步骤意味着接收器不必跟踪进入 PED 的每个密钥。它们可以在需要时重新生成。此密钥用于生成称为初始 Pin 加密密钥 (IPEK) 的密钥。由此生成一组称为 Future Keys 的密钥并丢弃 IPEK。每个 Future 密钥都由设备制造商嵌入到 PED 中,并与他们共享这些密钥。这个额外的推导步骤意味着接收器不必跟踪进入 PED 的每个密钥。它们可以在需要时重新生成。此密钥用于生成称为初始 Pin 加密密钥 (IPEK) 的密钥。由此生成一组称为 Future Keys 的密钥并丢弃 IPEK。每个 Future 密钥都由设备制造商嵌入到 PED 中,并与他们共享这些密钥。这个额外的推导步骤意味着接收器不必跟踪进入 PED 的每个密钥。它们可以在需要时重新生成。

在此处输入图像描述

接收器与 PED 制造商共享未来密钥,后者将一个密钥嵌入每个 PED。如果其中一个密钥被泄露,PED 可以使用从 BDK 派生的新 Future 密钥重新加密,因为 BDK 仍然是安全的。

加密和解密

当数据需要从 PED 发送到接收器时,该设备中的 Future 密钥用于生成一次性密钥,然后使用该密钥与加密算法一起加密数据。然后将该数据连同由设备 ID 和设备事务计数器组成的密钥序列号 (KSN) 一起发送到接收器。 在此处输入图像描述

基于 KSN,接收器然后生成 IPEK,并从中生成设备使用的未来密钥,然后生成用于加密数据的实际密钥。使用此密钥,接收方将能够解密数据。

Source

于 2013-07-07T17:16:03.927 回答
5

首先,让我引用您链接的完整源代码,其中您只提供了 3 行...

require 'bundler/setup'
require 'test/unit'
require 'dukpt'

class DUKPT::DecrypterTest < Test::Unit::TestCase

      def test_decrypt_track_data
        bdk = "0123456789ABCDEFFEDCBA9876543210"
        ksn = "FFFF9876543210E00008"
        ciphertext = "C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12"
        plaintext = "%B5452300551227189^HOGAN/PAUL ^08043210000000725000000?\x00\x00\x00\x00"

        decrypter = DUKPT::Decrypter.new(bdk, "cbc")
        assert_equal plaintext, decrypter.decrypt(ciphertext, ksn)
      end
end

现在,您要问的是“密文”是如何创建的......

嗯,我们知道的第一件事是它基于“明文”,在代码中用于验证解密是否有效。

明文是 0 填充的 - 它适合通过使用此 DecrypterTest TestCase 验证解密来测试的加密。

让我们看看编码代码然后......

我在https://github.com/Shopify/dukpt/blob/master/lib/dukpt/encryption.rb找到了相关的加密代码。

由于 DecrypterTEst 使用“cbc”,很明显加密使用:

 @cipher_type_des = "des-cbc"
 @cipher_type_tdes = "des-ede-cbc"

再深入一点加密代码,以下解决了我们对答案的追求:

ciphertext = des_encrypt(...

这表明我们确实在查看 DES 加密的结果。

现在,DES 的块大小为 64 位。那是(64/8 =)8字节二进制,或者 - 因为“密文”是字节的十六进制编码文本表示 - 16个字符十六进制。

密文”长度为 128 个十六进制字符,这意味着它包含(128 个十六进制字符/16 个十六进制字符=)8 个 DES 块,每个 64 位加密信息。

用一个简单的答案总结所有这些:

在查看"ciphertext"时,您正在查看(8 块)DES 加密数据,该数据使用人类可读的十六进制(2 个十六进制字符 = 1 个字节)表示法而不是 DES 加密的原始二进制字节表示生产。

至于“重新创建”密文所涉及的步骤,我倾向于告诉您简单地使用您提出问题的ruby​​ 项目的相关部分。只需查看源代码即可。https://github.com/Shopify/dukpt/blob/master/lib/dukpt/encryption.rb中的文件几乎解释了这一切,我很确定您需要的所有功能都可以在项目的 GitHub 上找到存储库。或者,您可以尝试自己重新创建它 - 使用您选择的首选编程语言。您只需要处理两件事:DES 加密/解密和 bin-to-hex/hex-to-bin 转换。

于 2013-07-07T17:11:17.247 回答
2

由于这是与此相关的第一个主题之一,我想我会分享我如何能够对密文进行编码。这是我第一次使用 Ruby,它专门用于 DUKPT

首先,我必须获得 ipek 和 pek(与解密相同)方法。然后解压明文字符串。将解压后的字符串转换为 72 字节数组(如果我的术语不正确,请再次原谅我)。

我注意到在 dukpt gem author 示例中,他使用了以下纯文本字符串

"%B5452300551227189^霍根/保罗^08043210000000725000000?\x00\x00\x00\x00"

我觉得这个字符串不正确,因为名称(AFAIK)后面不应该有空格..所以它应该是

"%B5452300551227189^霍根/保罗^08043210000000725000000?\x00\x00\x00\x00"

总而言之,这是我最终得到的解决方案,它可以加密一个字符串,然后使用 DUKPT 解密它

class Encrypt
include DUKPT::Encryption
attr_reader :bdk

def initialize(bdk, mode=nil)
  @bdk = bdk
  self.cipher_mode = mode.nil? ? 'cbc' : mode
end

def encrypt(plaintext, ksn)
  ipek = derive_IPEK(bdk, ksn)
  pek = derive_PEK(ipek, ksn)
  message =  plaintext.unpack("H*").first
  message = hex_string_from_unpacked(message, 72)
  encrypted_cryptogram = triple_des_encrypt(pek,message).upcase
  encrypted_cryptogram
end
def hex_string_from_unpacked val, bytes
  val.ljust(bytes * 2, "0")
end

结尾

Boomedukpt FFFF9876543210E00008 "%B5452300551227189^HOGAN/PAUL^08043210000000725000000?"

(我的红宝石,KSN 和纯文本字符串)

2542353435323330303535313232373138395e484f47414e2f5041554c5e30383034333231303030303030303732353030303030303f00000000000000000000000000000

(我的 ruby​​ gem 在调用 hex_string_from_unpacked 后对解压的字符串进行了放置)

C25C1D1197D31CAA87285D59A892047426D9182EC11353C0B82D407291CED53DA14FB107DC0AAB9974DB6E5943735BFFE7D72062708FB389E65A38C444432A6AF121B7F7EDD55

(我的 ruby​​ gem 放在加密字符串上)

%B5452300551227189^霍根/保罗^08043210000000725000000?

(在 dukpt gem 上调用解密后,我的 ruby​​ gem 做了一个 put)

于 2015-06-19T09:30:30.990 回答
0

看看这个:https ://github.com/sgbj/Dukpt.NET ,我遇到了类似的情况,我想知道当终端有自己的函数调用时如何在终端上实现dukpt,这些函数调用需要INIT和KSN来创建第一个密钥,所以我唯一的问题是确保在终端上生成 INIT 密钥的方式与上面提到的 repo 代码中的方式相同,这很简单,使用 ossl 加密库用于 3des 和 ebc 并应用适当的掩码.

于 2015-12-23T07:46:15.447 回答