rbthemis 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
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