tem_ruby 0.10.0 → 0.10.1
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/CHANGELOG +2 -0
- data/Manifest +11 -6
- data/lib/tem/{buffers.rb → apdus/buffers.rb} +6 -1
- data/lib/tem/{keys.rb → apdus/keys.rb} +9 -4
- data/lib/tem/{lifecycle.rb → apdus/lifecycle.rb} +6 -1
- data/lib/tem/{tag.rb → apdus/tag.rb} +6 -1
- data/lib/tem/builders/abi.rb +482 -0
- data/lib/tem/builders/crypto.rb +115 -0
- data/lib/tem/definitions/abi.rb +67 -0
- data/lib/tem/ecert.rb +1 -1
- data/lib/tem/keys/asymmetric.rb +116 -0
- data/lib/tem/keys/key.rb +48 -0
- data/lib/tem/keys/symmetric.rb +47 -0
- data/lib/tem/sec_assembler.rb +1 -2
- data/lib/tem/secpack.rb +5 -4
- data/lib/tem/tem.rb +5 -5
- data/lib/tem/toolkit.rb +2 -1
- data/lib/tem_ruby.rb +14 -6
- data/tem_ruby.gemspec +7 -11
- data/test/builders/test_abi_builder.rb +298 -0
- data/test/test_driver.rb +4 -4
- data/test/test_tem.rb +4 -3
- metadata +28 -26
- data/lib/tem/abi.rb +0 -55
- data/lib/tem/crypto_abi.rb +0 -264
data/lib/tem/crypto_abi.rb
DELETED
@@ -1,264 +0,0 @@
|
|
1
|
-
require 'openssl'
|
2
|
-
require 'digest'
|
3
|
-
require 'yaml'
|
4
|
-
|
5
|
-
module Tem::CryptoAbi
|
6
|
-
include Tem::Abi
|
7
|
-
|
8
|
-
# The methods that will be mixed into the TEM module
|
9
|
-
module MixedMethods
|
10
|
-
# Reads a TEM-encoded big number.
|
11
|
-
def read_tem_bignum(buffer, offset, length)
|
12
|
-
return buffer[offset...(offset+length)].inject(0) do |num, digit|
|
13
|
-
num = (num << 8) | digit
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
# Returns the TEM encoding for a big number.
|
18
|
-
def to_tem_bignum(n)
|
19
|
-
if n.kind_of? OpenSSL::BN
|
20
|
-
len = n.num_bytes
|
21
|
-
bytes = (0...len).map do |i|
|
22
|
-
bit_i = (len - i) * 8
|
23
|
-
v = 0
|
24
|
-
1.upto(8) do
|
25
|
-
bit_i -= 1
|
26
|
-
v = (v << 1) | (n.bit_set?(bit_i) ? 1 : 0)
|
27
|
-
end
|
28
|
-
v
|
29
|
-
end
|
30
|
-
return bytes
|
31
|
-
else
|
32
|
-
q = 0
|
33
|
-
until n == 0 do
|
34
|
-
q << (n & 0xFF)
|
35
|
-
n >>= 8
|
36
|
-
end
|
37
|
-
return q.reverse
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def load_tem_key_material(key, syms, buffer, offset)
|
42
|
-
lengths = (0...syms.length).map do |i|
|
43
|
-
read_tem_short buffer, offset + i * 2
|
44
|
-
end
|
45
|
-
offsets = [offset + syms.length * 2]
|
46
|
-
syms.each_index { |i| offsets[i + 1] = offsets[i] + lengths[i] }
|
47
|
-
syms.each_index do |i|
|
48
|
-
key.send((syms[i].to_s + '=').to_sym,
|
49
|
-
read_tem_bignum(buffer, offsets[i], lengths[i]))
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
# The length of a TEM symmetric key.
|
54
|
-
def tem_symmetric_key_length
|
55
|
-
16 # 128 bits
|
56
|
-
end
|
57
|
-
|
58
|
-
def read_tem_key(buffer, offset)
|
59
|
-
key_type = read_tem_ubyte buffer, offset
|
60
|
-
case key_type
|
61
|
-
when 0x99
|
62
|
-
key = buffer[offset, tem_symmetric_key_length]
|
63
|
-
when 0xAA, 0x55
|
64
|
-
key = OpenSSL::PKey::RSA.new
|
65
|
-
syms = (key_type == 0xAA) ? [:e, :n] : [:p, :q, :dmp1, :dmq1, :iqmp]
|
66
|
-
load_tem_key_material key, syms, buffer, offset + 1
|
67
|
-
if key_type == 0x55
|
68
|
-
# a bit of math to rebuild the public key
|
69
|
-
key.n = key.p * key.q
|
70
|
-
p1, q1 = key.p - 1, key.q - 1
|
71
|
-
p1q1 = p1 * q1
|
72
|
-
# HACK: I haven't figured out how to restore d from dmp1 and dmq1, so
|
73
|
-
# I'm betting on the fact that e must be a small prime
|
74
|
-
emp1 = key.dmp1.mod_inverse(p1)
|
75
|
-
emq1 = key.dmq1.mod_inverse(q1)
|
76
|
-
key.e = (emp1 < emq1) ? emp1 : emq1
|
77
|
-
key.d = key.e.mod_inverse(p1q1)
|
78
|
-
end
|
79
|
-
else
|
80
|
-
raise "Invalid key type #{'%02x' % key_type}"
|
81
|
-
end
|
82
|
-
return new_key_from_ssl(key, (key_type == 0xAA))
|
83
|
-
end
|
84
|
-
|
85
|
-
def to_tem_key(ssl_key, type)
|
86
|
-
if [:private, :public].include? type
|
87
|
-
# asymmetric key
|
88
|
-
syms = (type == :public) ? [:e, :n] : [:p, :q, :dmp1, :dmq1, :iqmp]
|
89
|
-
numbers = syms.map { |s| to_tem_bignum ssl_key.send(s) }
|
90
|
-
return [(type == :public) ? 0xAA : 0x55, numbers.map { |n| to_tem_ushort(n.length) }, numbers].flatten
|
91
|
-
else
|
92
|
-
# symmetric key
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
# Creates a new TEM key wrapper from a SSL key
|
97
|
-
def new_key_from_ssl(ssl_key, is_public)
|
98
|
-
if ssl_key.kind_of? OpenSSL::PKey::RSA
|
99
|
-
AsymmetricKey.new ssl_key, is_public, :pkcs1
|
100
|
-
else
|
101
|
-
SymmetricKey.new ssl_key
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Compute a cryptographic hash in the same way that the TEM does.
|
106
|
-
def hash_for_tem(data)
|
107
|
-
data = data.pack 'C*' unless data.kind_of? String
|
108
|
-
Digest::SHA1.digest(data).unpack 'C*'
|
109
|
-
end
|
110
|
-
end
|
111
|
-
|
112
|
-
self.extend MixedMethods
|
113
|
-
include MixedMethods
|
114
|
-
def self.included(klass)
|
115
|
-
klass.extend MixedMethods
|
116
|
-
end
|
117
|
-
|
118
|
-
def hash_for_tem(data)
|
119
|
-
Tem::CryptoAbi.hash_for_tem data
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.load_ssl(ssl_key)
|
123
|
-
return { :pubkey => AsymmetricKey.new(ssl_key, true, :pkcs1),
|
124
|
-
:privkey => AsymmetricKey.new(ssl_key, false, :pkcs1) }
|
125
|
-
end
|
126
|
-
|
127
|
-
def self.generate_ssl_kp
|
128
|
-
return Tem::CryptoAbi::AsymmetricKey.generate_ssl_kp
|
129
|
-
end
|
130
|
-
|
131
|
-
def self.generate_ssl_sk
|
132
|
-
return Tem::CryptoAbi::SymmetricKey.generate_ssl_sk
|
133
|
-
end
|
134
|
-
|
135
|
-
# Wraps a TEM asymmetric key.
|
136
|
-
class AsymmetricKey
|
137
|
-
attr_reader :ssl_key
|
138
|
-
|
139
|
-
def self.new_from_array(array)
|
140
|
-
AsymmetricKey.new(OpenSSL::PKey::RSA.new(array[0]), *array[1..-1])
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.new_from_yaml_str(yaml_str)
|
144
|
-
array = YAML.load yaml_str
|
145
|
-
new_from_array array
|
146
|
-
end
|
147
|
-
|
148
|
-
def to_array
|
149
|
-
[@ssl_key.to_pem, @is_public, @padding_type]
|
150
|
-
end
|
151
|
-
|
152
|
-
def to_yaml_str
|
153
|
-
self.to_array.to_yaml.to_s
|
154
|
-
end
|
155
|
-
|
156
|
-
# Generate an asymmetric OpenSSL key pair
|
157
|
-
def self.generate_ssl_kp
|
158
|
-
return OpenSSL::PKey::RSA.generate(2048, 65537)
|
159
|
-
end
|
160
|
-
|
161
|
-
def initialize(ssl_key, is_public, padding_type)
|
162
|
-
@ssl_key = ssl_key
|
163
|
-
@is_public = is_public ? true : false
|
164
|
-
@padding_type = padding_type
|
165
|
-
|
166
|
-
case padding_type
|
167
|
-
when :oaep
|
168
|
-
@padding_id = OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING
|
169
|
-
@padding_bytes = 42
|
170
|
-
when :pkcs1
|
171
|
-
@padding_id = OpenSSL::PKey::RSA::PKCS1_PADDING
|
172
|
-
@padding_bytes = 11
|
173
|
-
else
|
174
|
-
raise "Unknown padding type #{padding_type}\n"
|
175
|
-
end
|
176
|
-
|
177
|
-
@size = 0
|
178
|
-
n = is_public ? @ssl_key.n : (@ssl_key.p * @ssl_key.q)
|
179
|
-
while n != 0 do
|
180
|
-
@size += 1
|
181
|
-
n >>= 8
|
182
|
-
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def to_tem_key
|
186
|
-
Tem::CryptoAbi.to_tem_key @ssl_key, (@is_public ? :public : :private)
|
187
|
-
end
|
188
|
-
|
189
|
-
def chug_data(data, in_size, &chug_block)
|
190
|
-
output = data.class.new
|
191
|
-
i = 0
|
192
|
-
while i < data.length do
|
193
|
-
block_size = (data.length - i < in_size) ? data.length - i : in_size
|
194
|
-
if data.kind_of? String
|
195
|
-
block = data[i...(i+block_size)]
|
196
|
-
else
|
197
|
-
block = data[i...(i+block_size)].pack('C*')
|
198
|
-
end
|
199
|
-
o_block = yield block
|
200
|
-
if data.kind_of? String
|
201
|
-
output += o_block
|
202
|
-
else
|
203
|
-
output += o_block.unpack('C*')
|
204
|
-
end
|
205
|
-
i += block_size
|
206
|
-
end
|
207
|
-
return output
|
208
|
-
end
|
209
|
-
|
210
|
-
def encrypt_decrypt(data, in_size, op)
|
211
|
-
chug_data(data, in_size) { |block| @ssl_key.send op, block, @padding_id }
|
212
|
-
end
|
213
|
-
|
214
|
-
def encrypt(data)
|
215
|
-
encrypt_decrypt data, @size - @padding_bytes,
|
216
|
-
@is_public ? :public_encrypt : :private_encrypt
|
217
|
-
end
|
218
|
-
|
219
|
-
def decrypt(data)
|
220
|
-
encrypt_decrypt data, @size,
|
221
|
-
@is_public ? :public_decrypt : :private_decrypt
|
222
|
-
end
|
223
|
-
|
224
|
-
def sign(data)
|
225
|
-
data = data.pack 'C*' if data.respond_to? :pack
|
226
|
-
# PKCS1-padding is forced in by openssl... sigh!
|
227
|
-
out_data = @ssl_key.sign OpenSSL::Digest::SHA1.new, data
|
228
|
-
data.respond_to?(:pack) ? out_data : out_data.unpack('C*')
|
229
|
-
end
|
230
|
-
|
231
|
-
def verify(data, signature)
|
232
|
-
data = data.pack 'C*' if data.respond_to? :pack
|
233
|
-
signature = signature.pack 'C*' if signature.respond_to? :pack
|
234
|
-
# PKCS1-padding is forced in by openssl... sigh!
|
235
|
-
@ssl_key.verify OpenSSL::Digest::SHA1.new, signature, data
|
236
|
-
end
|
237
|
-
|
238
|
-
def is_public?
|
239
|
-
@is_public
|
240
|
-
end
|
241
|
-
end
|
242
|
-
|
243
|
-
# Wraps a TEM symmetric key
|
244
|
-
def SymmetricKey
|
245
|
-
def initialize(ssl_key)
|
246
|
-
@key = ssl_key
|
247
|
-
@cipher = OpenSSL::Cipher::Cipher.new 'aes-128-ecb'
|
248
|
-
@cipher.key = @key
|
249
|
-
@cipher.iv = "\0" * 16
|
250
|
-
end
|
251
|
-
|
252
|
-
def encrypt(data)
|
253
|
-
end
|
254
|
-
|
255
|
-
def decrypt(data)
|
256
|
-
end
|
257
|
-
|
258
|
-
def sign(data)
|
259
|
-
end
|
260
|
-
|
261
|
-
def verify(data)
|
262
|
-
end
|
263
|
-
end
|
264
|
-
end
|