rbthemis 0.10.0 → 0.11.0

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.
Files changed (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/rbthemis.rb +705 -0
  3. data/lib/rubythemis.rb +89 -25
  4. metadata +5 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 882a2cc4955dac5be7b20b4e72850118ccbd8d4d
4
- data.tar.gz: 181012eb67923ba79fd15514dba8f8e53efde6b1
3
+ metadata.gz: 8bb951f9da0bc027471c72aea7cd56eabc7991b1
4
+ data.tar.gz: 2f5d37f48f67ced53c083b259e4f0af4cb5253f9
5
5
  SHA512:
6
- metadata.gz: 3e1cd0ac78beeceb97aa708297f8c8ec80a7eb0c4e8b61f4f64535388531d25bbe790122e3504546546f0bd9cfae92f69c76270a7d779ca38f0edbe73bdc12e8
7
- data.tar.gz: 3e58ca419b4125a7e2717c7647d1db567251c71560758121b7e16e329111e983953784a3df7c1fd8624ac149c8e62705904db529113528cc9b1488af13854f65
6
+ metadata.gz: bf76747c0f1fc78e8d4f2a599877008586daaf24ee9bb57d86cfb989b524db3b7917bd9cb82b00c2366519c4499c0338eb112b4a33148bfa57bbf2a3b413ef37
7
+ data.tar.gz: 75686146b8c9f4801de42033fb1be44d1dea86618286f9ac5b93228f74cf66becb45a734acf13f25a8b0f7b7fd0b440405c59f7c366685bf72d08b13a4791ef2
data/lib/rbthemis.rb ADDED
@@ -0,0 +1,705 @@
1
+ #
2
+ # Copyright (c) 2015 Cossack Labs Limited
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+ #
16
+
17
+ require 'ffi'
18
+
19
+ module ThemisCommon
20
+ def string_to_pointer_size(string)
21
+ string_buf = FFI::MemoryPointer.new(
22
+ :char, string.force_encoding('BINARY').size)
23
+ string_buf.put_bytes(0, string.force_encoding('BINARY'),
24
+ 0, string.force_encoding('BINARY').size)
25
+ [string_buf, string.force_encoding('BINARY').size]
26
+ end
27
+ module_function :string_to_pointer_size
28
+ end
29
+
30
+ module ThemisImport
31
+ extend FFI::Library
32
+ ffi_lib 'themis'
33
+
34
+ callback :get_pub_key_by_id_type,
35
+ [:pointer, :int, :pointer, :int, :pointer], :int
36
+ callback :send_callback_type, [:pointer, :int, :uint], :int
37
+ callback :receive_callback_type, [:pointer, :int, :uint], :int
38
+
39
+ class CallbacksStruct < FFI::Struct
40
+ layout :send_data, :send_callback_type,
41
+ :receive_data, :receive_callback_type,
42
+ :state_changed, :pointer,
43
+ :get_pub_key_for_id, :get_pub_key_by_id_type,
44
+ :user_data, :pointer
45
+ end
46
+
47
+ attach_function :secure_session_create,
48
+ [:pointer, :uint, :pointer, :uint, :pointer], :pointer
49
+ attach_function :secure_session_destroy, [:pointer], :int
50
+ attach_function :secure_session_generate_connect_request,
51
+ [:pointer, :pointer, :pointer], :int
52
+
53
+ attach_function :secure_session_wrap,
54
+ [:pointer, :pointer, :int, :pointer, :pointer], :int
55
+ attach_function :secure_session_unwrap,
56
+ [:pointer, :pointer, :int, :pointer, :pointer], :int
57
+ attach_function :secure_session_is_established, [:pointer], :bool
58
+
59
+ attach_function :themis_secure_message_encrypt,
60
+ [:pointer, :int, :pointer, :int, :pointer,
61
+ :int, :pointer, :pointer], :int
62
+ attach_function :themis_secure_message_decrypt,
63
+ [:pointer, :int, :pointer, :int, :pointer,
64
+ :int, :pointer, :pointer], :int
65
+ attach_function :themis_secure_message_sign,
66
+ [:pointer, :int, :pointer, :int, :pointer,
67
+ :pointer], :int
68
+ attach_function :themis_secure_message_verify,
69
+ [:pointer, :int, :pointer, :int, :pointer,
70
+ :pointer], :int
71
+
72
+ attach_function :themis_gen_rsa_key_pair,
73
+ [:pointer, :pointer, :pointer, :pointer], :int
74
+ attach_function :themis_gen_ec_key_pair,
75
+ [:pointer, :pointer, :pointer, :pointer], :int
76
+
77
+ THEMIS_KEY_INVALID = 0
78
+ THEMIS_KEY_RSA_PRIVATE = 1
79
+ THEMIS_KEY_RSA_PUBLIC = 2
80
+ THEMIS_KEY_EC_PRIVATE = 3
81
+ THEMIS_KEY_EC_PUBLIC = 4
82
+
83
+ attach_function :themis_is_valid_asym_key, [:pointer, :int], :int
84
+ attach_function :themis_get_asym_key_kind, [:pointer, :int], :int
85
+
86
+ attach_function :themis_secure_cell_encrypt_seal,
87
+ [:pointer, :int, :pointer, :int, :pointer, :int,
88
+ :pointer, :pointer], :int
89
+ attach_function :themis_secure_cell_decrypt_seal,
90
+ [:pointer, :int, :pointer, :int, :pointer, :int,
91
+ :pointer, :pointer], :int
92
+
93
+ attach_function :themis_secure_cell_encrypt_token_protect,
94
+ [:pointer, :int, :pointer, :int, :pointer, :int,
95
+ :pointer, :pointer, :pointer, :pointer], :int
96
+ attach_function :themis_secure_cell_decrypt_token_protect,
97
+ [:pointer, :int, :pointer, :int, :pointer, :int,
98
+ :pointer, :int, :pointer, :pointer], :int
99
+
100
+ attach_function :themis_secure_cell_encrypt_context_imprint,
101
+ [:pointer, :int, :pointer, :int, :pointer, :int,
102
+ :pointer, :pointer], :int
103
+ attach_function :themis_secure_cell_decrypt_context_imprint,
104
+ [:pointer, :int, :pointer, :int, :pointer, :int,
105
+ :pointer, :pointer], :int
106
+
107
+ begin
108
+ attach_function :secure_comparator_create, [], :pointer
109
+ attach_function :secure_comparator_destroy, [:pointer], :int
110
+ attach_function :secure_comparator_append_secret,
111
+ [:pointer, :pointer, :int], :int
112
+ attach_function :secure_comparator_begin_compare,
113
+ [:pointer, :pointer, :pointer], :int
114
+ attach_function :secure_comparator_proceed_compare,
115
+ [:pointer, :pointer, :int, :pointer, :pointer], :int
116
+ attach_function :secure_comparator_get_result, [:pointer], :int
117
+ rescue FFI::NotFoundError
118
+ end
119
+ end
120
+
121
+ module Themis
122
+ extend ThemisCommon
123
+ extend ThemisImport
124
+
125
+ extend Gem::Deprecate
126
+
127
+ BUFFER_TOO_SMALL = 14
128
+ SUCCESS = 0
129
+ FAIL = 11
130
+ SEND_AS_IS = 1
131
+
132
+ ThemisError = Class.new(StandardError)
133
+
134
+ class Callbacks
135
+ def get_pub_key_by_id(id)
136
+ raise ThemisError, 'Callback is not implemented: get_pub_key_by_id'
137
+ end
138
+
139
+ def send(message)
140
+ raise ThemisError, 'Callback is not implemented: send'
141
+ end
142
+
143
+ def receive
144
+ raise ThemisError, 'Callback is not implemented: receive'
145
+ end
146
+ end
147
+
148
+ class SKeyPairGen
149
+ include ThemisCommon
150
+ include ThemisImport
151
+
152
+ def ec
153
+ private_key_length = FFI::MemoryPointer.new(:uint)
154
+ public_key_length = FFI::MemoryPointer.new(:uint)
155
+
156
+ res = themis_gen_ec_key_pair(
157
+ nil, private_key_length, nil, public_key_length)
158
+ if res != BUFFER_TOO_SMALL
159
+ raise ThemisError, "Themis failed generating EC KeyPair: #{res}"
160
+ end
161
+
162
+ private_key = FFI::MemoryPointer.new(:char, private_key_length.read_uint)
163
+ public_key = FFI::MemoryPointer.new(:char, public_key_length.read_uint)
164
+
165
+ res = themis_gen_ec_key_pair(
166
+ private_key, private_key_length, public_key, public_key_length)
167
+ if res != SUCCESS
168
+ raise ThemisError, "Themis failed generating EC KeyPair: #{res}"
169
+ end
170
+
171
+ [private_key.get_bytes(0, private_key_length.read_uint),
172
+ public_key.get_bytes(0, public_key_length.read_uint)]
173
+ end
174
+
175
+ def rsa
176
+ private_key_length = FFI::MemoryPointer.new(:uint)
177
+ public_key_length = FFI::MemoryPointer.new(:uint)
178
+
179
+ res = themis_gen_rsa_key_pair(
180
+ nil, private_key_length, nil, public_key_length)
181
+ if res != BUFFER_TOO_SMALL
182
+ raise ThemisError, "Themis failed generating RSA KeyPair: #{res}"
183
+ end
184
+
185
+ private_key = FFI::MemoryPointer.new(:char, private_key_length.read_uint)
186
+ public_key = FFI::MemoryPointer.new(:char, public_key_length.read_uint)
187
+
188
+ res = themis_gen_rsa_key_pair(
189
+ private_key, private_key_length, public_key, public_key_length)
190
+ if res != SUCCESS
191
+ raise ThemisError, "Themis failed generating RSA KeyPair: #{res}"
192
+ end
193
+
194
+ [private_key.get_bytes(0, private_key_length.read_uint),
195
+ public_key.get_bytes(0, public_key_length.read_uint)]
196
+ end
197
+ end
198
+
199
+ def Themis.valid_key(key)
200
+ if key.nil? || key.empty?
201
+ return false
202
+ end
203
+ key_, len_ = string_to_pointer_size(key)
204
+ return themis_is_valid_asym_key(key_, len_) == SUCCESS
205
+ end
206
+
207
+ def Themis.private_key(key)
208
+ key_, len_ = string_to_pointer_size(key)
209
+ kind = themis_get_asym_key_kind(key_, len_)
210
+ return kind == ThemisImport::THEMIS_KEY_RSA_PRIVATE \
211
+ || kind == ThemisImport::THEMIS_KEY_EC_PRIVATE
212
+ end
213
+
214
+ def Themis.public_key(key)
215
+ key_, len_ = string_to_pointer_size(key)
216
+ kind = themis_get_asym_key_kind(key_, len_)
217
+ return kind == ThemisImport::THEMIS_KEY_RSA_PUBLIC \
218
+ || kind == ThemisImport::THEMIS_KEY_EC_PUBLIC
219
+ end
220
+
221
+ class Ssession
222
+ include ThemisCommon
223
+ include ThemisImport
224
+
225
+ extend Gem::Deprecate
226
+
227
+ MAPPING = {}
228
+
229
+ GetPubKeyByIDCallback =
230
+ FFI::Function.new(:int, [:pointer, :int, :pointer, :int, :pointer]) do |id_buf, id_length, pubkey_buf, pubkey_length, obj|
231
+ pub_key = MAPPING[obj.read_uint64].get_pub_key_by_id(
232
+ id_buf.get_bytes(0, id_length))
233
+ return -1 unless pub_key
234
+ pubkey_buf.put_bytes(0, pub_key)
235
+ 0
236
+ end
237
+
238
+ def initialize(id, private_key, transport)
239
+ id_buf, id_length = string_to_pointer_size(id)
240
+ private_key_buf, private_key_length = string_to_pointer_size(private_key)
241
+
242
+ @callbacks = CallbacksStruct.new
243
+ @callbacks[:get_pub_key_for_id] = GetPubKeyByIDCallback
244
+
245
+ MAPPING[transport.object_id] = transport
246
+ @transport_obj_id = transport.object_id
247
+
248
+ @callbacks[:user_data] = FFI::MemoryPointer.new(:uint64)
249
+ @callbacks[:user_data].write_uint64(@transport_obj_id)
250
+
251
+ @session = secure_session_create(
252
+ id_buf, id_length, private_key_buf, private_key_length, @callbacks)
253
+
254
+ raise ThemisError, 'Secure Session failed creating' unless @session
255
+ end
256
+
257
+ def is_established
258
+ established?
259
+ end
260
+ deprecate(:is_established, :established?, 2018, 6)
261
+
262
+ def established?
263
+ secure_session_is_established @session
264
+ end
265
+
266
+ def connect_request
267
+ connect_request_length = FFI::MemoryPointer.new(:uint)
268
+ res = secure_session_generate_connect_request(
269
+ @session, nil, connect_request_length)
270
+ if res != BUFFER_TOO_SMALL
271
+ raise(ThemisError,
272
+ "Secure Session failed making connection request: #{res}")
273
+ end
274
+ connect_request = FFI::MemoryPointer.new(
275
+ :char, connect_request_length.read_uint)
276
+ res = secure_session_generate_connect_request(
277
+ @session, connect_request, connect_request_length)
278
+ if res != SUCCESS
279
+ raise(ThemisError,
280
+ "Secure Session failed making connection request: #{res}")
281
+ end
282
+ connect_request.get_bytes(0, connect_request_length.read_uint)
283
+ end
284
+
285
+ def unwrap(message)
286
+ message_, message_length_ = string_to_pointer_size message
287
+ unwrapped_message_length = FFI::MemoryPointer.new(:uint)
288
+
289
+ res = secure_session_unwrap(
290
+ @session, message_, message_length_, nil, unwrapped_message_length)
291
+ return SUCCESS, '' if res == SUCCESS
292
+ if res != BUFFER_TOO_SMALL
293
+ raise ThemisError, "Secure Session failed decrypting: #{res}"
294
+ end
295
+
296
+ unwrapped_message = FFI::MemoryPointer.new(
297
+ :char, unwrapped_message_length.read_uint)
298
+ res = secure_session_unwrap(@session, message_, message_length_,
299
+ unwrapped_message, unwrapped_message_length)
300
+ if res != SUCCESS && res != SEND_AS_IS
301
+ raise ThemisError, "Secure Session failed decrypting: #{res}"
302
+ end
303
+
304
+ [res, unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)]
305
+ end
306
+
307
+ def wrap(message)
308
+ message_, message_length_ = string_to_pointer_size(message)
309
+
310
+ wrapped_message_length = FFI::MemoryPointer.new(:uint)
311
+ res = secure_session_wrap(
312
+ @session, message_, message_length_, nil, wrapped_message_length)
313
+ if res != BUFFER_TOO_SMALL
314
+ raise ThemisError, "Secure Session failed encrypting: #{res}"
315
+ end
316
+
317
+ wrapped_message = FFI::MemoryPointer.new(
318
+ :char, wrapped_message_length.read_uint)
319
+ res = secure_session_wrap(@session, message_, message_length_,
320
+ wrapped_message, wrapped_message_length)
321
+ if res != SUCCESS && res != SEND_AS_IS
322
+ raise ThemisError, "Secure Session failed encrypting: #{res}"
323
+ end
324
+
325
+ wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
326
+ end
327
+
328
+ def finalize
329
+ res = secure_session_destroy(@session)
330
+ raise ThemisError, 'Secure Session failed destroying' if res != SUCCESS
331
+ end
332
+ end
333
+
334
+ class Smessage
335
+ include ThemisCommon
336
+ include ThemisImport
337
+
338
+ def initialize(private_key, peer_public_key)
339
+ if not Themis.valid_key(private_key)
340
+ raise ThemisError, "Secure Message: invalid private key"
341
+ end
342
+ if not Themis.valid_key(peer_public_key)
343
+ raise ThemisError, "Secure Message: invalid public key"
344
+ end
345
+ if not Themis.private_key(private_key)
346
+ raise ThemisError, "Secure Message: public key used instead of private"
347
+ end
348
+ if not Themis.public_key(peer_public_key)
349
+ raise ThemisError, "Secure Message: private key used instead of public"
350
+ end
351
+
352
+ @private_key, @private_key_length = string_to_pointer_size(private_key)
353
+ @peer_public_key, @peer_public_key_length =
354
+ string_to_pointer_size(peer_public_key)
355
+ end
356
+
357
+ def wrap(message)
358
+ message_, message_length_ = string_to_pointer_size(message)
359
+
360
+ wrapped_message_length = FFI::MemoryPointer.new(:uint)
361
+ res = themis_secure_message_encrypt(
362
+ @private_key, @private_key_length, @peer_public_key,
363
+ @peer_public_key_length, message_, message_length_,
364
+ nil, wrapped_message_length)
365
+ if res != BUFFER_TOO_SMALL
366
+ raise ThemisError, "Secure Message failed to encrypt: #{res}"
367
+ end
368
+
369
+ wrapped_message = FFI::MemoryPointer.new(
370
+ :char, wrapped_message_length.read_uint)
371
+ res = themis_secure_message_encrypt(
372
+ @private_key, @private_key_length, @peer_public_key,
373
+ @peer_public_key_length, message_, message_length_,
374
+ wrapped_message, wrapped_message_length)
375
+ if res != SUCCESS
376
+ raise ThemisError, "Secure Message failed to encrypt: #{res}"
377
+ end
378
+
379
+ wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
380
+ end
381
+
382
+ def unwrap(message)
383
+ message_, message_length_ = string_to_pointer_size(message)
384
+ unwrapped_message_length = FFI::MemoryPointer.new(:uint)
385
+ res = themis_secure_message_decrypt(
386
+ @private_key, @private_key_length, @peer_public_key,
387
+ @peer_public_key_length, message_, message_length_,
388
+ nil, unwrapped_message_length)
389
+ if res != BUFFER_TOO_SMALL
390
+ raise ThemisError, "Secure Message failed to decrypt: #{res}"
391
+ end
392
+
393
+ unwrapped_message = FFI::MemoryPointer.new(
394
+ :char, unwrapped_message_length.read_uint)
395
+ res = themis_secure_message_decrypt(
396
+ @private_key, @private_key_length, @peer_public_key,
397
+ @peer_public_key_length, message_, message_length_,
398
+ unwrapped_message, unwrapped_message_length)
399
+ if res != SUCCESS
400
+ raise ThemisError, "Secure Message failed to decrypt: #{res}"
401
+ end
402
+
403
+ unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
404
+ end
405
+ end
406
+
407
+ def Ssign(*args)
408
+ s_sign(*args)
409
+ end
410
+ deprecate :Ssign, :s_sign, 2018, 6
411
+
412
+ def s_sign(private_key, message)
413
+ if not valid_key(private_key)
414
+ raise ThemisError, "Secure Message: invalid private key"
415
+ end
416
+ if not private_key(private_key)
417
+ raise ThemisError, "Secure Message: public key used instead of private"
418
+ end
419
+
420
+ private_key_, private_key_length_ = string_to_pointer_size(private_key)
421
+ message_, message_length_ = string_to_pointer_size(message)
422
+
423
+ wrapped_message_length = FFI::MemoryPointer.new(:uint)
424
+ res = themis_secure_message_sign(
425
+ private_key_, private_key_length_, message_,
426
+ message_length_, nil, wrapped_message_length)
427
+ if res != BUFFER_TOO_SMALL
428
+ raise ThemisError, "Secure Message failed to sign: #{res}"
429
+ end
430
+
431
+ wrapped_message = FFI::MemoryPointer.new(
432
+ :char, wrapped_message_length.read_uint)
433
+ res = themis_secure_message_sign(
434
+ private_key_, private_key_length_, message_,
435
+ message_length_, wrapped_message, wrapped_message_length)
436
+ if res != SUCCESS
437
+ raise ThemisError, "Secure Message failed to sign: #{res}"
438
+ end
439
+
440
+ wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
441
+ end
442
+
443
+ def Sverify(*args)
444
+ s_verify(*args)
445
+ end
446
+ deprecate :Sverify, :s_verify, 2018, 6
447
+
448
+ def s_verify(peer_public_key, message)
449
+ if not valid_key(peer_public_key)
450
+ raise ThemisError, "Secure Message: invalid public key"
451
+ end
452
+ if not public_key(peer_public_key)
453
+ raise ThemisError, "Secure Message: private key used instead of public"
454
+ end
455
+
456
+ public_key_, public_key_length_ = string_to_pointer_size(peer_public_key)
457
+ message_, message_length_ = string_to_pointer_size(message)
458
+
459
+ unwrapped_message_length = FFI::MemoryPointer.new(:uint)
460
+ res = themis_secure_message_verify(
461
+ public_key_, public_key_length_, message_,
462
+ message_length_, nil, unwrapped_message_length)
463
+ if res != BUFFER_TOO_SMALL
464
+ raise ThemisError, "Secure Message failed to verify: #{res}"
465
+ end
466
+
467
+ unwrapped_message = FFI::MemoryPointer.new(
468
+ :char, unwrapped_message_length.read_uint)
469
+ res = themis_secure_message_verify(
470
+ public_key_, public_key_length_, message_,
471
+ message_length_, unwrapped_message, unwrapped_message_length)
472
+ if res != SUCCESS
473
+ raise ThemisError, "Secure Message failed to verify: #{res}"
474
+ end
475
+
476
+ unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
477
+ end
478
+
479
+ class Scell
480
+ include ThemisCommon
481
+ include ThemisImport
482
+
483
+ SEAL_MODE = 0
484
+ TOKEN_PROTECT_MODE = 1
485
+ CONTEXT_IMPRINT_MODE = 2
486
+
487
+ def initialize(key, mode)
488
+ @key, @key_length = string_to_pointer_size(key)
489
+ @mode = mode
490
+ end
491
+
492
+ def encrypt(message, context = nil)
493
+ message_, message_length_ = string_to_pointer_size(message)
494
+ context_, context_length_ =
495
+ context.nil? ? [nil, 0] : string_to_pointer_size(context)
496
+ encrypted_message_length = FFI::MemoryPointer.new(:uint)
497
+ enccontext_length = FFI::MemoryPointer.new(:uint)
498
+ case @mode
499
+ when SEAL_MODE
500
+ res = themis_secure_cell_encrypt_seal(
501
+ @key, @key_length, context_, context_length_, message_,
502
+ message_length_, nil, encrypted_message_length)
503
+ if res != BUFFER_TOO_SMALL
504
+ raise ThemisError, "Secure Cell (Seal) failed encrypting: #{res}"
505
+ end
506
+ encrypted_message = FFI::MemoryPointer.new(
507
+ :char, encrypted_message_length.read_uint)
508
+ res = themis_secure_cell_encrypt_seal(
509
+ @key, @key_length, context_, context_length_, message_,
510
+ message_length_, encrypted_message, encrypted_message_length)
511
+ if res != SUCCESS
512
+ raise ThemisError, "Secure Cell (Seal) failed encrypting: #{res}"
513
+ end
514
+ encrypted_message.get_bytes(0, encrypted_message_length.read_uint)
515
+ when TOKEN_PROTECT_MODE
516
+ res = themis_secure_cell_encrypt_token_protect(
517
+ @key, @key_length, context_, context_length_, message_,
518
+ message_length_, nil, enccontext_length, nil,
519
+ encrypted_message_length)
520
+ if res != BUFFER_TOO_SMALL
521
+ raise(ThemisError,
522
+ "Secure Cell (Token protect) failed encrypting: #{res}")
523
+ end
524
+ encrypted_message = FFI::MemoryPointer.new(
525
+ :char, encrypted_message_length.read_uint)
526
+ enccontext = FFI::MemoryPointer.new(:char, enccontext_length.read_uint)
527
+ res = themis_secure_cell_encrypt_token_protect(
528
+ @key, @key_length, context_, context_length_, message_,
529
+ message_length_, enccontext, enccontext_length, encrypted_message,
530
+ encrypted_message_length)
531
+ if res != SUCCESS
532
+ raise(ThemisError,
533
+ "Secure Cell (Token Protect) failed encrypting: #{res}")
534
+ end
535
+ [encrypted_message.get_bytes(0, encrypted_message_length.read_uint),
536
+ enccontext.get_bytes(0, enccontext_length.read_uint),]
537
+ when CONTEXT_IMPRINT_MODE
538
+ res = themis_secure_cell_encrypt_context_imprint(
539
+ @key, @key_length, message_, message_length_, context_,
540
+ context_length_, nil, encrypted_message_length)
541
+ if res != BUFFER_TOO_SMALL
542
+ raise(ThemisError,
543
+ "Secure Cell (Context Imprint) failed encrypting: #{res}")
544
+ end
545
+ encrypted_message = FFI::MemoryPointer.new(
546
+ :char, encrypted_message_length.read_uint)
547
+ res = themis_secure_cell_encrypt_context_imprint(
548
+ @key, @key_length, message_, message_length_, context_,
549
+ context_length_, encrypted_message, encrypted_message_length)
550
+ if res != SUCCESS
551
+ raise(ThemisError,
552
+ "Secure Cell (Context Imprint) failed encrypting: #{res}")
553
+ end
554
+ encrypted_message.get_bytes(0, encrypted_message_length.read_uint)
555
+ else
556
+ raise ThemisError, 'Secure Cell failed encrypting, undefined mode'
557
+ end
558
+ end
559
+
560
+ def decrypt(message, context = nil)
561
+ context_, context_length_ =
562
+ context.nil? ? [nil, 0] : string_to_pointer_size(context)
563
+ decrypted_message_length = FFI::MemoryPointer.new(:uint)
564
+ case @mode
565
+ when SEAL_MODE
566
+ message_, message_length_ = string_to_pointer_size(message)
567
+ res = themis_secure_cell_decrypt_seal(
568
+ @key, @key_length, context_, context_length_, message_,
569
+ message_length_, nil, decrypted_message_length)
570
+ if res != BUFFER_TOO_SMALL
571
+ raise ThemisError, "Secure Cell (Seal) failed decrypting: #{res}"
572
+ end
573
+ decrypted_message = FFI::MemoryPointer.new(
574
+ :char, decrypted_message_length.read_uint)
575
+ res = themis_secure_cell_decrypt_seal(
576
+ @key, @key_length, context_, context_length_, message_,
577
+ message_length_, decrypted_message, decrypted_message_length)
578
+ if res != SUCCESS
579
+ raise ThemisError, "Secure Cell (Seal) failed decrypting: #{res}"
580
+ end
581
+ decrypted_message.get_bytes(0, decrypted_message_length.read_uint)
582
+ when TOKEN_PROTECT_MODE
583
+ message_, enccontext = message
584
+ message__, message_length__ = string_to_pointer_size(message_)
585
+ enccontext_, enccontext_length = string_to_pointer_size(enccontext)
586
+ res = themis_secure_cell_decrypt_token_protect(
587
+ @key, @key_length, context_, context_length_, message__,
588
+ message_length__, enccontext_, enccontext_length, nil,
589
+ decrypted_message_length)
590
+ if res != BUFFER_TOO_SMALL
591
+ raise(ThemisError,
592
+ "Secure Cell (Token Protect) failed decrypting: #{res}")
593
+ end
594
+ decrypted_message = FFI::MemoryPointer.new(
595
+ :char, decrypted_message_length.read_uint)
596
+ res = themis_secure_cell_decrypt_token_protect(
597
+ @key, @key_length, context_, context_length_, message__,
598
+ message_length__, enccontext_, enccontext_length,
599
+ decrypted_message, decrypted_message_length)
600
+ if res != SUCCESS
601
+ raise(ThemisError,
602
+ "Secure Cell (Token Protect) failed decrypting: #{res}")
603
+ end
604
+ decrypted_message.get_bytes(0, decrypted_message_length.read_uint)
605
+ when CONTEXT_IMPRINT_MODE
606
+ message_, message_length_ = string_to_pointer_size(message)
607
+ res = themis_secure_cell_decrypt_context_imprint(
608
+ @key, @key_length, message_, message_length_, context_,
609
+ context_length_, nil, decrypted_message_length)
610
+ if res != BUFFER_TOO_SMALL
611
+ raise(ThemisError,
612
+ "Secure Cell (Context Imprint) failed decrypting: #{res}")
613
+ end
614
+ decrypted_message = FFI::MemoryPointer.new(
615
+ :char, decrypted_message_length.read_uint)
616
+ res = themis_secure_cell_decrypt_context_imprint(@key, @key_length,
617
+ message_, message_length_, context_, context_length_,
618
+ decrypted_message, decrypted_message_length)
619
+ if res != SUCCESS
620
+ raise(ThemisError,
621
+ "Secure Cell (Context Imprint) failed decrypting: #{res}")
622
+ end
623
+ decrypted_message.get_bytes(0, decrypted_message_length.read_uint)
624
+ else
625
+ raise ThemisError, 'Secure Cell failed encrypting, undefined mode'
626
+ end
627
+ end
628
+ end
629
+
630
+ class Scomparator
631
+ include ThemisCommon
632
+ include ThemisImport
633
+
634
+ MATCH = 21
635
+ NOT_MATCH = 22
636
+ NOT_READY = 0
637
+
638
+ def initialize(shared_secret)
639
+ shared_secret_buf, shared_secret_length =
640
+ string_to_pointer_size(shared_secret)
641
+ @comparator = secure_comparator_create
642
+ raise ThemisError, 'Secure Comparator failed creating' unless @comparator
643
+ res = secure_comparator_append_secret(
644
+ @comparator, shared_secret_buf, shared_secret_length)
645
+ if res != SUCCESS
646
+ raise ThemisError, 'Secure Comparator failed appending secret'
647
+ end
648
+ end
649
+
650
+ def finalize
651
+ res = secure_comparator_destroy(@comparator)
652
+ if res != SUCCESS
653
+ raise ThemisError, 'Secure Comparator failed destroying'
654
+ end
655
+ end
656
+
657
+ def begin_compare
658
+ res_length = FFI::MemoryPointer.new(:uint)
659
+ res = secure_comparator_begin_compare(@comparator, nil, res_length)
660
+ if res != BUFFER_TOO_SMALL
661
+ raise(ThemisError,
662
+ 'Secure Comparator failed making initialisation message')
663
+ end
664
+
665
+ res_buffer = FFI::MemoryPointer.new(:char, res_length.read_uint)
666
+ res = secure_comparator_begin_compare(@comparator, res_buffer, res_length)
667
+ if res != SUCCESS && res != SEND_AS_IS
668
+ raise(ThemisError,
669
+ 'Secure Comparator failed making initialisation message')
670
+ end
671
+
672
+ res_buffer.get_bytes(0, res_length.read_uint)
673
+ end
674
+
675
+ def proceed_compare(control_message)
676
+ message, message_length = string_to_pointer_size(control_message)
677
+ res_length = FFI::MemoryPointer.new(:uint)
678
+
679
+ res = secure_comparator_proceed_compare(
680
+ @comparator, message, message_length, nil, res_length)
681
+ return '' if res == SUCCESS
682
+ if res != BUFFER_TOO_SMALL
683
+ raise ThemisError, 'Secure Comparator failed proceeding message'
684
+ end
685
+
686
+ res_buffer = FFI::MemoryPointer.new(:char, res_length.read_uint)
687
+ res = secure_comparator_proceed_compare(
688
+ @comparator, message, message_length, res_buffer, res_length)
689
+ if res != SUCCESS && res != SEND_AS_IS
690
+ raise ThemisError, 'Secure Comparator failed proceeding message'
691
+ end
692
+
693
+ res_buffer.get_bytes(0, res_length.read_uint)
694
+ end
695
+
696
+ def result
697
+ secure_comparator_get_result(@comparator)
698
+ end
699
+ end
700
+
701
+ module_function :Ssign
702
+ module_function :Sverify
703
+ module_function :s_sign
704
+ module_function :s_verify
705
+ end
data/lib/rubythemis.rb CHANGED
@@ -14,6 +14,10 @@
14
14
  # limitations under the License.
15
15
  #
16
16
 
17
+ warn %(DEPRECATION WARNING: The `rubythemis` gem is deprecated. ) +
18
+ %(Please use "require 'rbthemis'" instead of "require 'rubythemis'". ) +
19
+ %(`rubythemis.rb` will be removed in 0.12.0 release.)
20
+
17
21
  require 'ffi'
18
22
 
19
23
  module ThemisCommon
@@ -56,18 +60,32 @@ module ThemisImport
56
60
  [:pointer, :pointer, :int, :pointer, :pointer], :int
57
61
  attach_function :secure_session_is_established, [:pointer], :bool
58
62
 
59
- attach_function :themis_secure_message_wrap,
63
+ attach_function :themis_secure_message_encrypt,
60
64
  [:pointer, :int, :pointer, :int, :pointer,
61
65
  :int, :pointer, :pointer], :int
62
- attach_function :themis_secure_message_unwrap,
66
+ attach_function :themis_secure_message_decrypt,
63
67
  [:pointer, :int, :pointer, :int, :pointer,
64
68
  :int, :pointer, :pointer], :int
69
+ attach_function :themis_secure_message_sign,
70
+ [:pointer, :int, :pointer, :int, :pointer,
71
+ :pointer], :int
72
+ attach_function :themis_secure_message_verify,
73
+ [:pointer, :int, :pointer, :int, :pointer,
74
+ :pointer], :int
65
75
 
66
76
  attach_function :themis_gen_rsa_key_pair,
67
77
  [:pointer, :pointer, :pointer, :pointer], :int
68
78
  attach_function :themis_gen_ec_key_pair,
69
79
  [:pointer, :pointer, :pointer, :pointer], :int
70
- attach_function :themis_version, [], :string
80
+
81
+ THEMIS_KEY_INVALID = 0
82
+ THEMIS_KEY_RSA_PRIVATE = 1
83
+ THEMIS_KEY_RSA_PUBLIC = 2
84
+ THEMIS_KEY_EC_PRIVATE = 3
85
+ THEMIS_KEY_EC_PUBLIC = 4
86
+
87
+ attach_function :themis_is_valid_asym_key, [:pointer, :int], :int
88
+ attach_function :themis_get_asym_key_kind, [:pointer, :int], :int
71
89
 
72
90
  attach_function :themis_secure_cell_encrypt_seal,
73
91
  [:pointer, :int, :pointer, :int, :pointer, :int,
@@ -182,6 +200,28 @@ module Themis
182
200
  end
183
201
  end
184
202
 
203
+ def Themis.valid_key(key)
204
+ if key.nil? || key.empty?
205
+ return false
206
+ end
207
+ key_, len_ = string_to_pointer_size(key)
208
+ return themis_is_valid_asym_key(key_, len_) == SUCCESS
209
+ end
210
+
211
+ def Themis.private_key(key)
212
+ key_, len_ = string_to_pointer_size(key)
213
+ kind = themis_get_asym_key_kind(key_, len_)
214
+ return kind == ThemisImport::THEMIS_KEY_RSA_PRIVATE \
215
+ || kind == ThemisImport::THEMIS_KEY_EC_PRIVATE
216
+ end
217
+
218
+ def Themis.public_key(key)
219
+ key_, len_ = string_to_pointer_size(key)
220
+ kind = themis_get_asym_key_kind(key_, len_)
221
+ return kind == ThemisImport::THEMIS_KEY_RSA_PUBLIC \
222
+ || kind == ThemisImport::THEMIS_KEY_EC_PUBLIC
223
+ end
224
+
185
225
  class Ssession
186
226
  include ThemisCommon
187
227
  include ThemisImport
@@ -300,6 +340,19 @@ module Themis
300
340
  include ThemisImport
301
341
 
302
342
  def initialize(private_key, peer_public_key)
343
+ if not Themis.valid_key(private_key)
344
+ raise ThemisError, "Secure Message: invalid private key"
345
+ end
346
+ if not Themis.valid_key(peer_public_key)
347
+ raise ThemisError, "Secure Message: invalid public key"
348
+ end
349
+ if not Themis.private_key(private_key)
350
+ raise ThemisError, "Secure Message: public key used instead of private"
351
+ end
352
+ if not Themis.public_key(peer_public_key)
353
+ raise ThemisError, "Secure Message: private key used instead of public"
354
+ end
355
+
303
356
  @private_key, @private_key_length = string_to_pointer_size(private_key)
304
357
  @peer_public_key, @peer_public_key_length =
305
358
  string_to_pointer_size(peer_public_key)
@@ -309,22 +362,22 @@ module Themis
309
362
  message_, message_length_ = string_to_pointer_size(message)
310
363
 
311
364
  wrapped_message_length = FFI::MemoryPointer.new(:uint)
312
- res = themis_secure_message_wrap(
365
+ res = themis_secure_message_encrypt(
313
366
  @private_key, @private_key_length, @peer_public_key,
314
367
  @peer_public_key_length, message_, message_length_,
315
368
  nil, wrapped_message_length)
316
369
  if res != BUFFER_TOO_SMALL
317
- raise ThemisError, "Secure Message failed encrypting: #{res}"
370
+ raise ThemisError, "Secure Message failed to encrypt: #{res}"
318
371
  end
319
372
 
320
373
  wrapped_message = FFI::MemoryPointer.new(
321
374
  :char, wrapped_message_length.read_uint)
322
- res = themis_secure_message_wrap(
375
+ res = themis_secure_message_encrypt(
323
376
  @private_key, @private_key_length, @peer_public_key,
324
377
  @peer_public_key_length, message_, message_length_,
325
378
  wrapped_message, wrapped_message_length)
326
379
  if res != SUCCESS
327
- raise ThemisError, "Secure Message failed encrypting: #{res}"
380
+ raise ThemisError, "Secure Message failed to encrypt: #{res}"
328
381
  end
329
382
 
330
383
  wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
@@ -333,22 +386,22 @@ module Themis
333
386
  def unwrap(message)
334
387
  message_, message_length_ = string_to_pointer_size(message)
335
388
  unwrapped_message_length = FFI::MemoryPointer.new(:uint)
336
- res = themis_secure_message_unwrap(
389
+ res = themis_secure_message_decrypt(
337
390
  @private_key, @private_key_length, @peer_public_key,
338
391
  @peer_public_key_length, message_, message_length_,
339
392
  nil, unwrapped_message_length)
340
393
  if res != BUFFER_TOO_SMALL
341
- raise ThemisError, "Secure Message failed decrypting: #{res}"
394
+ raise ThemisError, "Secure Message failed to decrypt: #{res}"
342
395
  end
343
396
 
344
397
  unwrapped_message = FFI::MemoryPointer.new(
345
398
  :char, unwrapped_message_length.read_uint)
346
- res = themis_secure_message_unwrap(
399
+ res = themis_secure_message_decrypt(
347
400
  @private_key, @private_key_length, @peer_public_key,
348
401
  @peer_public_key_length, message_, message_length_,
349
402
  unwrapped_message, unwrapped_message_length)
350
403
  if res != SUCCESS
351
- raise ThemisError, "Secure Message failed decrypting: #{res}"
404
+ raise ThemisError, "Secure Message failed to decrypt: #{res}"
352
405
  end
353
406
 
354
407
  unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
@@ -361,24 +414,31 @@ module Themis
361
414
  deprecate :Ssign, :s_sign, 2018, 6
362
415
 
363
416
  def s_sign(private_key, message)
417
+ if not valid_key(private_key)
418
+ raise ThemisError, "Secure Message: invalid private key"
419
+ end
420
+ if not private_key(private_key)
421
+ raise ThemisError, "Secure Message: public key used instead of private"
422
+ end
423
+
364
424
  private_key_, private_key_length_ = string_to_pointer_size(private_key)
365
425
  message_, message_length_ = string_to_pointer_size(message)
366
426
 
367
427
  wrapped_message_length = FFI::MemoryPointer.new(:uint)
368
- res = themis_secure_message_wrap(
369
- private_key_, private_key_length_, nil, 0, message_,
428
+ res = themis_secure_message_sign(
429
+ private_key_, private_key_length_, message_,
370
430
  message_length_, nil, wrapped_message_length)
371
431
  if res != BUFFER_TOO_SMALL
372
- raise ThemisError, "Secure Message failed singing: #{res}"
432
+ raise ThemisError, "Secure Message failed to sign: #{res}"
373
433
  end
374
434
 
375
435
  wrapped_message = FFI::MemoryPointer.new(
376
436
  :char, wrapped_message_length.read_uint)
377
- res = themis_secure_message_wrap(
378
- private_key_, private_key_length_, nil, 0, message_,
437
+ res = themis_secure_message_sign(
438
+ private_key_, private_key_length_, message_,
379
439
  message_length_, wrapped_message, wrapped_message_length)
380
440
  if res != SUCCESS
381
- raise ThemisError, "Secure Message failed singing: #{res}"
441
+ raise ThemisError, "Secure Message failed to sign: #{res}"
382
442
  end
383
443
 
384
444
  wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
@@ -390,27 +450,31 @@ module Themis
390
450
  deprecate :Sverify, :s_verify, 2018, 6
391
451
 
392
452
  def s_verify(peer_public_key, message)
393
- include ThemisCommon
394
- include ThemisImport
453
+ if not valid_key(peer_public_key)
454
+ raise ThemisError, "Secure Message: invalid public key"
455
+ end
456
+ if not public_key(peer_public_key)
457
+ raise ThemisError, "Secure Message: private key used instead of public"
458
+ end
395
459
 
396
460
  public_key_, public_key_length_ = string_to_pointer_size(peer_public_key)
397
461
  message_, message_length_ = string_to_pointer_size(message)
398
462
 
399
463
  unwrapped_message_length = FFI::MemoryPointer.new(:uint)
400
- res = themis_secure_message_unwrap(
401
- nil, 0, public_key_, public_key_length_, message_,
464
+ res = themis_secure_message_verify(
465
+ public_key_, public_key_length_, message_,
402
466
  message_length_, nil, unwrapped_message_length)
403
467
  if res != BUFFER_TOO_SMALL
404
- raise ThemisError, "Secure Message failed verifying: #{res}"
468
+ raise ThemisError, "Secure Message failed to verify: #{res}"
405
469
  end
406
470
 
407
471
  unwrapped_message = FFI::MemoryPointer.new(
408
472
  :char, unwrapped_message_length.read_uint)
409
- res = themis_secure_message_unwrap(
410
- nil, 0, public_key_, public_key_length_, message_,
473
+ res = themis_secure_message_verify(
474
+ public_key_, public_key_length_, message_,
411
475
  message_length_, unwrapped_message, unwrapped_message_length)
412
476
  if res != SUCCESS
413
- raise ThemisError, "Secure Message failed verifying: #{res}"
477
+ raise ThemisError, "Secure Message failed to verify: #{res}"
414
478
  end
415
479
 
416
480
  unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rbthemis
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - CossackLabs
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-02-06 00:00:00.000000000 Z
11
+ date: 2019-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -40,6 +40,7 @@ executables: []
40
40
  extensions: []
41
41
  extra_rdoc_files: []
42
42
  files:
43
+ - lib/rbthemis.rb
43
44
  - lib/rubythemis.rb
44
45
  homepage: http://cossacklabs.com/
45
46
  licenses:
@@ -61,9 +62,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
61
62
  - !ruby/object:Gem::Version
62
63
  version: '0'
63
64
  requirements:
64
- - libthemis, v0.10.0
65
+ - libthemis, v0.11.0
65
66
  rubyforge_project:
66
- rubygems_version: 2.4.8
67
+ rubygems_version: 2.5.2.1
67
68
  signing_key:
68
69
  specification_version: 4
69
70
  summary: Data security library for network communication and data storage for Ruby