dukpt 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -20,6 +20,9 @@ Or install it yourself as:
20
20
 
21
21
  # Instantiate a decrypter with your base derivation key (BDK)
22
22
  decrypter = DUKPT::Decrypter.new("0123456789ABCDEFFEDCBA9876543210")
23
+
24
+ # You can specify whether you want to use "ecb" cipher mode if needed. The default is "cbc".
25
+ decrypter = DUKPT::Decrypter.new("0123456789ABCDEFFEDCBA9876543210", "ecb")
23
26
 
24
27
  # Pass the ciphertext and the current Key Serial Number (KSN), as hex encoded strings, to the decryptor to get back the plaintext
25
28
  ksn = "FFFF9876543210E00008"
@@ -3,8 +3,10 @@ module DUKPT
3
3
  include Encryption
4
4
 
5
5
  attr_reader :bdk
6
- def initialize(bdk)
6
+
7
+ def initialize(bdk, mode=nil)
7
8
  @bdk = bdk
9
+ self.cipher_mode = mode.nil? ? 'cbc' : mode
8
10
  end
9
11
 
10
12
  def decrypt(cryptogram, ksn)
@@ -10,7 +10,18 @@ module DUKPT
10
10
  KEY_MASK = 0xC0C0C0C000000000C0C0C0C000000000
11
11
  PEK_MASK = 0x00000000000000FF00000000000000FF
12
12
  KSN_MASK = 0xFFFFFFFFFFFFFFE00000
13
-
13
+ DEK_MASK = 0x0000000000FF00000000000000FF0000 # Used by IDTECH reader
14
+
15
+ def cipher_mode=(cipher_type)
16
+ if cipher_type == "ecb"
17
+ @cipher_type_des = "des-ecb"
18
+ @cipher_type_tdes = "des-ede"
19
+ else
20
+ @cipher_type_des = "des-cbc"
21
+ @cipher_type_tdes = "des-ede-cbc"
22
+ end
23
+ end
24
+
14
25
  def derive_key(ipek, ksn)
15
26
  ksn_current = ksn.to_i(16)
16
27
 
@@ -51,10 +62,33 @@ module DUKPT
51
62
  hex_string_from_val((key.to_i(16) ^ PEK_MASK), 16)
52
63
  end
53
64
 
65
+ def dek_from_key(key)
66
+ key = key.to_i(16)
67
+
68
+ key = key ^ DEK_MASK
69
+
70
+ left = (key & MS16_MASK) >> 64
71
+ right = (key & LS16_MASK)
72
+
73
+ invariant_key_hex = hex_string_from_val(key, 16)
74
+
75
+ left = triple_des_encrypt(invariant_key_hex, hex_string_from_val(left, 8))
76
+ right = triple_des_encrypt(invariant_key_hex, hex_string_from_val(right, 8))
77
+
78
+ left = hex_string_from_val(left.to_i(16), 8)
79
+ right = hex_string_from_val(right.to_i(16), 8)
80
+
81
+ [left, right].join
82
+ end
83
+
54
84
  def derive_PEK(ipek, ksn)
55
85
  pek_from_key(derive_key(ipek, ksn))
56
86
  end
57
87
 
88
+ def derive_DEK(ipek, ksn)
89
+ dek_from_key(derive_key(ipek, ksn))
90
+ end
91
+
58
92
  def derive_IPEK(bdk, ksn)
59
93
  ksn_cleared_count = (ksn.to_i(16) & KSN_MASK) >> 16
60
94
  left_half_of_ipek = triple_des_encrypt(bdk, hex_string_from_val(ksn_cleared_count, 8))
@@ -63,23 +97,36 @@ module DUKPT
63
97
  ipek_derived = left_half_of_ipek + right_half_of_ipek
64
98
  end
65
99
 
100
+ def aes_decrypt(key, message)
101
+ openssl_encrypt("aes-128-cbc", key, message, false)
102
+ end
103
+
66
104
  def triple_des_decrypt(key, message)
67
- openssl_encrypt("des-ede-cbc", key, message, false)
105
+ openssl_encrypt(cipher_type_tdes, key, message, false)
68
106
  end
69
107
 
70
108
  def triple_des_encrypt(key, message)
71
- openssl_encrypt("des-ede-cbc", key, message, true)
109
+ openssl_encrypt(cipher_type_tdes, key, message, true)
72
110
  end
73
-
111
+
74
112
  def des_encrypt(key, message)
75
- openssl_encrypt("des-cbc", key, message, true)
113
+ openssl_encrypt(cipher_type_des, key, message, true)
76
114
  end
77
115
 
78
116
  private
117
+
118
+ def cipher_type_des
119
+ @cipher_type_des || "des-cbc"
120
+ end
121
+
122
+ def cipher_type_tdes
123
+ @cipher_type_tdes || "des-ede-cbc"
124
+ end
79
125
 
80
126
  def hex_string_from_val val, bytes
81
127
  val.to_s(16).rjust(bytes * 2, "0")
82
128
  end
129
+
83
130
  def encrypt_register(curkey, reg_8)
84
131
  left_key_half = (curkey & MS16_MASK) >> 64
85
132
  right_key_half = curkey & LS16_MASK
@@ -96,7 +143,6 @@ module DUKPT
96
143
  is_encrypt ? cipher.encrypt : cipher.decrypt
97
144
  cipher.padding = 0
98
145
  cipher.key = [key].pack('H*')
99
- # No Initial Vector is used in the process.
100
146
  cipher_result = ""
101
147
  cipher_result << cipher.update([message].pack('H*'))
102
148
  cipher_result << cipher.final
@@ -1,3 +1,3 @@
1
1
  module DUKPT
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -10,7 +10,7 @@ class DUKPT::DecrypterTest < Test::Unit::TestCase
10
10
  ciphertext = "C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12"
11
11
  plaintext = "%B5452300551227189^HOGAN/PAUL ^08043210000000725000000?\x00\x00\x00\x00"
12
12
 
13
- decrypter = DUKPT::Decrypter.new(bdk)
13
+ decrypter = DUKPT::Decrypter.new(bdk, "cbc")
14
14
  assert_equal plaintext, decrypter.decrypt(ciphertext, ksn)
15
15
  end
16
16
 
@@ -84,10 +84,35 @@ def test_derive_pek_counter_EFF800
84
84
  assert_equal '2542353435323330303535313232373138395e484f47414e2f5041554c2020202020205e30383034333231303030303030303732353030303030303f00000000', data_decrypted
85
85
  end
86
86
 
87
+ def test_triple_des_decrypt_with_ecb
88
+ self.cipher_mode = "ecb"
89
+ ciphertext = "C25C1D1197D31CAA87285D59A892047426D9182EC11353C051ADD6D0F072A6CB3436560B3071FC1FD11D9F7E74886742D9BEE0CFD1EA1064C213BB55278B2F12"
90
+ data_decrypted = triple_des_decrypt('27f66d5244ff621eaa6f6120edeb427f', ciphertext)
91
+ assert_equal '2542353435323330f2692820a5e12b9bbf110311e7d5453a0989597b8d3373e0718df68ec04a96ff0704673b0041cc2fe12da84c41b85772e98ed0f0d1ea1064', data_decrypted
92
+ end
93
+
87
94
  def test_unpacking_decrypted_data
88
95
  data_decrypted = '2542353435323330303535313232373138395e484f47414e2f5041554c2020202020205e30383034333231303030303030303732353030303030303f00000000'
89
96
  expected = "%B5452300551227189^HOGAN/PAUL ^08043210000000725000000?\x00\x00\x00\x00"
90
97
  assert_equal expected, [data_decrypted].pack('H*')
91
98
  end
92
99
 
100
+ def test_cipher_mode_ecb
101
+ self.cipher_mode = "ecb"
102
+ assert_equal cipher_type_des, "des-ecb"
103
+ assert_equal cipher_type_tdes, "des-ede"
104
+ end
105
+
106
+ def test_dek_from_key
107
+ key = "27F66D5244FF62E1AA6F6120EDEB4280"
108
+ dek = dek_from_key(key)
109
+ assert_equal "C39B2778B058AC376FB18DC906F75CBA", dek.upcase
110
+ end
111
+
112
+ def test_derive_dek_counter_13
113
+ ksn = "FFFF9876543210E00013"
114
+ dek = derive_DEK('6ac292faa1315b4d858ab3a3d7d5933a', ksn)
115
+ assert_equal '44893E3434ABDD6A817CE2841825E1FD', dek.upcase
116
+ end
117
+
93
118
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dukpt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-03-18 00:00:00.000000000 Z
13
+ date: 2013-05-21 00:00:00.000000000 Z
14
14
  dependencies: []
15
15
  description: Implements a Derived Unique Key Per Transaction (DUKPT) decrypter
16
16
  email: