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.
@@ -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