dukpt 0.0.1 → 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +3 -0
- data/lib/dukpt/decrypter.rb +3 -1
- data/lib/dukpt/encryption.rb +52 -6
- data/lib/dukpt/version.rb +1 -1
- data/test/decrypter_test.rb +1 -1
- data/test/encryption_test.rb +25 -0
- metadata +2 -2
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"
|
data/lib/dukpt/decrypter.rb
CHANGED
data/lib/dukpt/encryption.rb
CHANGED
@@ -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(
|
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(
|
109
|
+
openssl_encrypt(cipher_type_tdes, key, message, true)
|
72
110
|
end
|
73
|
-
|
111
|
+
|
74
112
|
def des_encrypt(key, message)
|
75
|
-
openssl_encrypt(
|
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
|
data/lib/dukpt/version.rb
CHANGED
data/test/decrypter_test.rb
CHANGED
@@ -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
|
|
data/test/encryption_test.rb
CHANGED
@@ -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.
|
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-
|
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:
|