rbthemis 0.12.0 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/rbthemis.rb +418 -131
- metadata +7 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6b961537ca7de62ffe35b208cdb6cd859c30dcdea841f11ba313612018005da0
|
4
|
+
data.tar.gz: 86e0f4632b5a651cd9ed5085bab004a054f49ce6f10b01056ac480af553f734d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ddb38e6216be4223661725ad06d126759dca0eaca658a884114515f0fb9982e4433a80231a1ad476d6a2a4ef355ae49231449d16dbfc720556ca74533bb82fb7
|
7
|
+
data.tar.gz: 1299e49545f8e0ddecd6e5c446ad966e959d74474fd248a042f25889a34ba29d0a0ccbebd9fa8e001ad8d4f059398234636326006aad81542391f63e8107d86d
|
data/lib/rbthemis.rb
CHANGED
@@ -18,13 +18,16 @@ require 'ffi'
|
|
18
18
|
|
19
19
|
module ThemisCommon
|
20
20
|
def string_to_pointer_size(string)
|
21
|
-
string_buf = FFI::MemoryPointer.
|
22
|
-
|
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]
|
21
|
+
string_buf = FFI::MemoryPointer.from_string(string)
|
22
|
+
[string_buf, string.bytesize]
|
26
23
|
end
|
24
|
+
|
25
|
+
def empty?(value)
|
26
|
+
return value.nil? || value.empty?
|
27
|
+
end
|
28
|
+
|
27
29
|
module_function :string_to_pointer_size
|
30
|
+
module_function :empty?
|
28
31
|
end
|
29
32
|
|
30
33
|
module ThemisImport
|
@@ -73,6 +76,8 @@ module ThemisImport
|
|
73
76
|
[:pointer, :pointer, :pointer, :pointer], :int
|
74
77
|
attach_function :themis_gen_ec_key_pair,
|
75
78
|
[:pointer, :pointer, :pointer, :pointer], :int
|
79
|
+
attach_function :themis_gen_sym_key,
|
80
|
+
[:pointer, :pointer], :int
|
76
81
|
|
77
82
|
THEMIS_KEY_INVALID = 0
|
78
83
|
THEMIS_KEY_RSA_PRIVATE = 1
|
@@ -90,6 +95,13 @@ module ThemisImport
|
|
90
95
|
[:pointer, :int, :pointer, :int, :pointer, :int,
|
91
96
|
:pointer, :pointer], :int
|
92
97
|
|
98
|
+
attach_function :themis_secure_cell_encrypt_seal_with_passphrase,
|
99
|
+
[:pointer, :int, :pointer, :int, :pointer, :int,
|
100
|
+
:pointer, :pointer], :int
|
101
|
+
attach_function :themis_secure_cell_decrypt_seal_with_passphrase,
|
102
|
+
[:pointer, :int, :pointer, :int, :pointer, :int,
|
103
|
+
:pointer, :pointer], :int
|
104
|
+
|
93
105
|
attach_function :themis_secure_cell_encrypt_token_protect,
|
94
106
|
[:pointer, :int, :pointer, :int, :pointer, :int,
|
95
107
|
:pointer, :pointer, :pointer, :pointer], :int
|
@@ -127,9 +139,20 @@ module Themis
|
|
127
139
|
BUFFER_TOO_SMALL = 14
|
128
140
|
SUCCESS = 0
|
129
141
|
FAIL = 11
|
142
|
+
INVALID_ARGUMENT = 12
|
130
143
|
SEND_AS_IS = 1
|
131
144
|
|
132
|
-
|
145
|
+
# Common class of errors caused by Themis functions.
|
146
|
+
# You can access the numerical value via "error_code" attribute.
|
147
|
+
# Human-readable message is accessible via "message" attribute.
|
148
|
+
class ThemisError < StandardError
|
149
|
+
attr_reader :error_code
|
150
|
+
|
151
|
+
def initialize(error_code = INVALID_ARGUMENT)
|
152
|
+
super
|
153
|
+
@error_code = error_code
|
154
|
+
end
|
155
|
+
end
|
133
156
|
|
134
157
|
class Callbacks
|
135
158
|
def get_pub_key_by_id(id)
|
@@ -476,6 +499,26 @@ module Themis
|
|
476
499
|
unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
|
477
500
|
end
|
478
501
|
|
502
|
+
def gen_sym_key
|
503
|
+
key_length = FFI::MemoryPointer.new(:uint)
|
504
|
+
|
505
|
+
res = themis_gen_sym_key(nil, key_length)
|
506
|
+
if res != BUFFER_TOO_SMALL
|
507
|
+
raise ThemisError, "failed to get symmetric key size: #{res}"
|
508
|
+
end
|
509
|
+
|
510
|
+
key = FFI::MemoryPointer.new(:char, key_length.read_uint)
|
511
|
+
|
512
|
+
res = themis_gen_sym_key(key, key_length)
|
513
|
+
if res != SUCCESS
|
514
|
+
raise ThemisError, "failed to generate symmetric key: #{res}"
|
515
|
+
end
|
516
|
+
|
517
|
+
return key.get_bytes(0, key_length.read_uint)
|
518
|
+
end
|
519
|
+
|
520
|
+
# Scell base class is retained for compatibility.
|
521
|
+
# New code should use ScellSeal, ScellTokenProtect, or ScellContextImprint.
|
479
522
|
class Scell
|
480
523
|
include ThemisCommon
|
481
524
|
include ThemisImport
|
@@ -485,145 +528,388 @@ module Themis
|
|
485
528
|
CONTEXT_IMPRINT_MODE = 2
|
486
529
|
|
487
530
|
def initialize(key, mode)
|
531
|
+
# We could have replaced this with "self.new" but it's not possible
|
532
|
+
# to override new *and* keep Scell as superclass of ScellSeal et al.
|
533
|
+
# So we keep an instance of appropriate class here and never call
|
534
|
+
# superclass initialize in subclasses.
|
535
|
+
case mode
|
536
|
+
when SEAL_MODE
|
537
|
+
@cell = ScellSeal.new(key)
|
538
|
+
when TOKEN_PROTECT_MODE
|
539
|
+
@cell = ScellTokenProtect.new(key)
|
540
|
+
when CONTEXT_IMPRINT_MODE
|
541
|
+
@cell = ScellContextImprint.new(key)
|
542
|
+
else
|
543
|
+
raise ThemisError, "unknown Secure Cell mode: #{mode}"
|
544
|
+
end
|
545
|
+
warn "NOTE: #{self.class.name} is deprecated; use #{@cell.class.name} instead."
|
546
|
+
end
|
547
|
+
|
548
|
+
def encrypt(message, context = nil)
|
549
|
+
@cell.encrypt(message, context)
|
550
|
+
end
|
551
|
+
|
552
|
+
def decrypt(message, context = nil)
|
553
|
+
@cell.decrypt(message, context)
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
# Secure Cell in Seal mode.
|
558
|
+
class ScellSeal < Scell
|
559
|
+
include ThemisCommon
|
560
|
+
include ThemisImport
|
561
|
+
|
562
|
+
# Make a new Secure Cell with given key.
|
563
|
+
# The key must not be empty and is treated as binary data.
|
564
|
+
# You can use Themis::gen_sym_key to generate new keys.
|
565
|
+
def initialize(key)
|
566
|
+
if empty? key
|
567
|
+
raise ThemisError, "key cannot be empty"
|
568
|
+
end
|
488
569
|
@key, @key_length = string_to_pointer_size(key)
|
489
|
-
@mode = mode
|
490
570
|
end
|
491
571
|
|
572
|
+
# Encrypts message with given optional context.
|
573
|
+
# The context is cryptographically combined with message but is not included
|
574
|
+
# into encrypted data, you will need to provide the same context for decryption.
|
575
|
+
# Resulting encrypted message includes authentication token.
|
576
|
+
# Message must not be empty, but context may be omitted.
|
577
|
+
# Both message and context are treated as binary data.
|
492
578
|
def encrypt(message, context = nil)
|
579
|
+
if empty? message
|
580
|
+
raise ThemisError, "message cannot be empty"
|
581
|
+
end
|
582
|
+
|
493
583
|
message_, message_length_ = string_to_pointer_size(message)
|
494
584
|
context_, context_length_ =
|
495
585
|
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
500
|
-
|
501
|
-
|
502
|
-
|
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'
|
586
|
+
|
587
|
+
encrypted_length = FFI::MemoryPointer.new(:uint)
|
588
|
+
res = themis_secure_cell_encrypt_seal(
|
589
|
+
@key, @key_length, context_, context_length_,
|
590
|
+
message_, message_length_, nil, encrypted_length)
|
591
|
+
if res != BUFFER_TOO_SMALL
|
592
|
+
raise ThemisError.new(res), "encrypt failed"
|
557
593
|
end
|
594
|
+
|
595
|
+
encrypted_message = FFI::MemoryPointer.new(:char, encrypted_length.read_uint)
|
596
|
+
res = themis_secure_cell_encrypt_seal(
|
597
|
+
@key, @key_length, context_, context_length_,
|
598
|
+
message_, message_length_, encrypted_message, encrypted_length)
|
599
|
+
if res != SUCCESS
|
600
|
+
raise ThemisError.new(res), "encrypt failed"
|
601
|
+
end
|
602
|
+
|
603
|
+
encrypted_message.get_bytes(0, encrypted_length.read_uint)
|
558
604
|
end
|
559
605
|
|
606
|
+
# Decrypts message with given context.
|
607
|
+
# The context must be the same as the one used during encryption,
|
608
|
+
# or be omitted or set to nil if no context were used.
|
609
|
+
# Decrypted message is returned as binary data.
|
560
610
|
def decrypt(message, context = nil)
|
611
|
+
if empty? message
|
612
|
+
raise ThemisError, "message cannot be empty"
|
613
|
+
end
|
614
|
+
|
615
|
+
message_, message_length_ = string_to_pointer_size(message)
|
561
616
|
context_, context_length_ =
|
562
617
|
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
563
|
-
|
564
|
-
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
|
576
|
-
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
|
581
|
-
|
582
|
-
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
588
|
-
|
589
|
-
|
590
|
-
|
591
|
-
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
|
596
|
-
|
597
|
-
|
598
|
-
|
599
|
-
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
|
604
|
-
|
605
|
-
|
606
|
-
|
607
|
-
|
608
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
618
|
-
|
619
|
-
|
620
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
618
|
+
|
619
|
+
decrypted_length = FFI::MemoryPointer.new(:uint)
|
620
|
+
res = themis_secure_cell_decrypt_seal(
|
621
|
+
@key, @key_length, context_, context_length_,
|
622
|
+
message_, message_length_, nil, decrypted_length)
|
623
|
+
if res != BUFFER_TOO_SMALL
|
624
|
+
raise ThemisError.new(res), "decrypt failed"
|
625
|
+
end
|
626
|
+
|
627
|
+
decrypted_message = FFI::MemoryPointer.new(:char, decrypted_length.read_uint)
|
628
|
+
res = themis_secure_cell_decrypt_seal(
|
629
|
+
@key, @key_length, context_, context_length_,
|
630
|
+
message_, message_length_, decrypted_message, decrypted_length)
|
631
|
+
if res != SUCCESS
|
632
|
+
raise ThemisError.new(res), "decrypt failed"
|
633
|
+
end
|
634
|
+
|
635
|
+
decrypted_message.get_bytes(0, decrypted_length.read_uint)
|
636
|
+
end
|
637
|
+
end
|
638
|
+
|
639
|
+
# Secure Cell in Seal mode.
|
640
|
+
class ScellSealPassphrase < ScellSeal
|
641
|
+
include ThemisCommon
|
642
|
+
include ThemisImport
|
643
|
+
|
644
|
+
# Make a new Secure Cell with given passphrase.
|
645
|
+
# The passphrase must not be empty.
|
646
|
+
# If the passphrase is not binary it will be encoded in UTF-8 by default,
|
647
|
+
# you can use optional "encoding:" argument to use a different encoding.
|
648
|
+
def initialize(passphrase, encoding: Encoding::UTF_8)
|
649
|
+
if empty? passphrase
|
650
|
+
raise ThemisError, "passphrase cannot be empty"
|
651
|
+
end
|
652
|
+
if passphrase.encoding != Encoding::BINARY
|
653
|
+
passphrase = passphrase.encode(encoding)
|
654
|
+
end
|
655
|
+
@passphrase, @passphrase_length = string_to_pointer_size(passphrase)
|
656
|
+
end
|
657
|
+
|
658
|
+
# Encrypts message with given optional context.
|
659
|
+
# The context is cryptographically combined with message but is not included
|
660
|
+
# into encrypted data, you will need to provide the same context for decryption.
|
661
|
+
# Resulting encrypted message includes authentication token.
|
662
|
+
# Message must not be empty, but context may be omitted.
|
663
|
+
# Both message and context are treated as binary data.
|
664
|
+
def encrypt(message, context = nil)
|
665
|
+
if empty? message
|
666
|
+
raise ThemisError, "message cannot be empty"
|
667
|
+
end
|
668
|
+
|
669
|
+
message_, message_length_ = string_to_pointer_size(message)
|
670
|
+
context_, context_length_ =
|
671
|
+
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
672
|
+
|
673
|
+
encrypted_length = FFI::MemoryPointer.new(:uint)
|
674
|
+
res = themis_secure_cell_encrypt_seal_with_passphrase(
|
675
|
+
@passphrase, @passphrase_length, context_, context_length_,
|
676
|
+
message_, message_length_, nil, encrypted_length)
|
677
|
+
if res != BUFFER_TOO_SMALL
|
678
|
+
raise ThemisError.new(res), "encrypt failed"
|
679
|
+
end
|
680
|
+
|
681
|
+
encrypted_message = FFI::MemoryPointer.new(:char, encrypted_length.read_uint)
|
682
|
+
res = themis_secure_cell_encrypt_seal_with_passphrase(
|
683
|
+
@passphrase, @passphrase_length, context_, context_length_,
|
684
|
+
message_, message_length_, encrypted_message, encrypted_length)
|
685
|
+
if res != SUCCESS
|
686
|
+
raise ThemisError.new(res), "encrypt failed"
|
687
|
+
end
|
688
|
+
|
689
|
+
encrypted_message.get_bytes(0, encrypted_length.read_uint)
|
690
|
+
end
|
691
|
+
|
692
|
+
# Decrypts message with given context.
|
693
|
+
# The context must be the same as the one used during encryption,
|
694
|
+
# or be omitted or set to nil if no context were used.
|
695
|
+
# Decrypted message is returned as binary data.
|
696
|
+
def decrypt(message, context = nil)
|
697
|
+
if empty? message
|
698
|
+
raise ThemisError, "message cannot be empty"
|
699
|
+
end
|
700
|
+
|
701
|
+
message_, message_length_ = string_to_pointer_size(message)
|
702
|
+
context_, context_length_ =
|
703
|
+
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
704
|
+
|
705
|
+
decrypted_length = FFI::MemoryPointer.new(:uint)
|
706
|
+
res = themis_secure_cell_decrypt_seal_with_passphrase(
|
707
|
+
@passphrase, @passphrase_length, context_, context_length_,
|
708
|
+
message_, message_length_, nil, decrypted_length)
|
709
|
+
if res != BUFFER_TOO_SMALL
|
710
|
+
raise ThemisError.new(res), "decrypt failed"
|
711
|
+
end
|
712
|
+
|
713
|
+
decrypted_message = FFI::MemoryPointer.new(:char, decrypted_length.read_uint)
|
714
|
+
res = themis_secure_cell_decrypt_seal_with_passphrase(
|
715
|
+
@passphrase, @passphrase_length, context_, context_length_,
|
716
|
+
message_, message_length_, decrypted_message, decrypted_length)
|
717
|
+
if res != SUCCESS
|
718
|
+
raise ThemisError.new(res), "decrypt failed"
|
719
|
+
end
|
720
|
+
|
721
|
+
decrypted_message.get_bytes(0, decrypted_length.read_uint)
|
722
|
+
end
|
723
|
+
end
|
724
|
+
|
725
|
+
# Secure Cell in Token Protect mode.
|
726
|
+
class ScellTokenProtect < Scell
|
727
|
+
include ThemisCommon
|
728
|
+
include ThemisImport
|
729
|
+
|
730
|
+
# Make a new Secure Cell with given key.
|
731
|
+
# The key must not be empty and is treated as binary data.
|
732
|
+
# You can use Themis::gen_sym_key to generate new keys.
|
733
|
+
def initialize(key)
|
734
|
+
if empty? key
|
735
|
+
raise ThemisError, "key cannot be empty"
|
736
|
+
end
|
737
|
+
@key, @key_length = string_to_pointer_size(key)
|
738
|
+
end
|
739
|
+
|
740
|
+
# Encrypts message with given optional context.
|
741
|
+
# The context is cryptographically combined with message but is not included
|
742
|
+
# into encrypted data, you will need to provide the same context for decryption.
|
743
|
+
# Resulting encrypted message (the same length as input) and authentication token
|
744
|
+
# are returned separately; you will need to provide them both for decryption.
|
745
|
+
# Message must not be empty, but context may be omitted.
|
746
|
+
# Both message and context are treated as binary data.
|
747
|
+
def encrypt(message, context = nil)
|
748
|
+
if empty? message
|
749
|
+
raise ThemisError, "message cannot be empty"
|
750
|
+
end
|
751
|
+
|
752
|
+
message_, message_length_ = string_to_pointer_size(message)
|
753
|
+
context_, context_length_ =
|
754
|
+
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
755
|
+
|
756
|
+
auth_token_length = FFI::MemoryPointer.new(:uint)
|
757
|
+
encrypted_length = FFI::MemoryPointer.new(:uint)
|
758
|
+
res = themis_secure_cell_encrypt_token_protect(
|
759
|
+
@key, @key_length, context_, context_length_, message_, message_length_,
|
760
|
+
nil, auth_token_length, nil, encrypted_length)
|
761
|
+
if res != BUFFER_TOO_SMALL
|
762
|
+
raise ThemisError.new(res), "encrypt failed"
|
763
|
+
end
|
764
|
+
|
765
|
+
auth_token = FFI::MemoryPointer.new(:char, auth_token_length.read_uint)
|
766
|
+
encrypted_message = FFI::MemoryPointer.new(:char, encrypted_length.read_uint)
|
767
|
+
res = themis_secure_cell_encrypt_token_protect(
|
768
|
+
@key, @key_length, context_, context_length_, message_, message_length_,
|
769
|
+
auth_token, auth_token_length, encrypted_message, encrypted_length)
|
770
|
+
if res != SUCCESS
|
771
|
+
raise ThemisError.new(res), "encrypt failed"
|
772
|
+
end
|
773
|
+
|
774
|
+
[encrypted_message.get_bytes(0, encrypted_length.read_uint),
|
775
|
+
auth_token.get_bytes(0, auth_token_length.read_uint),]
|
776
|
+
end
|
777
|
+
|
778
|
+
# Decrypts message with given authentication token and context.
|
779
|
+
# The context must be the same as the one used during encryption,
|
780
|
+
# or be omitted or set to nil if no context were used.
|
781
|
+
# The token also must be the one returned during encryption.
|
782
|
+
# Decrypted message is returned as binary data.
|
783
|
+
def decrypt(message, token = nil, context = nil)
|
784
|
+
# For compatibility with older API we allow the message and token to be
|
785
|
+
# provided as a list in the first argument. In this case the second one
|
786
|
+
# contains (an optional) context. Then there is no third argument.
|
787
|
+
if message.kind_of? Array
|
788
|
+
context = token
|
789
|
+
message, token = message
|
790
|
+
end
|
791
|
+
|
792
|
+
if empty? message
|
793
|
+
raise ThemisError, "message cannot be empty"
|
626
794
|
end
|
795
|
+
if empty? token
|
796
|
+
raise ThemisError, "token cannot be empty"
|
797
|
+
end
|
798
|
+
|
799
|
+
message_, message_length_ = string_to_pointer_size(message)
|
800
|
+
token_, token_length_ = string_to_pointer_size(token)
|
801
|
+
context_, context_length_ =
|
802
|
+
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
803
|
+
|
804
|
+
decrypted_length = FFI::MemoryPointer.new(:uint)
|
805
|
+
res = themis_secure_cell_decrypt_token_protect(
|
806
|
+
@key, @key_length, context_, context_length_,
|
807
|
+
message_, message_length_, token_, token_length_,
|
808
|
+
nil, decrypted_length)
|
809
|
+
if res != BUFFER_TOO_SMALL
|
810
|
+
raise ThemisError.new(res), "decrypt failed"
|
811
|
+
end
|
812
|
+
|
813
|
+
decrypted_message = FFI::MemoryPointer.new(:char, decrypted_length.read_uint)
|
814
|
+
res = themis_secure_cell_decrypt_token_protect(
|
815
|
+
@key, @key_length, context_, context_length_,
|
816
|
+
message_, message_length_, token_, token_length_,
|
817
|
+
decrypted_message, decrypted_length)
|
818
|
+
if res != SUCCESS
|
819
|
+
raise ThemisError.new(res), "decrypt failed"
|
820
|
+
end
|
821
|
+
|
822
|
+
decrypted_message.get_bytes(0, decrypted_length.read_uint)
|
823
|
+
end
|
824
|
+
end
|
825
|
+
|
826
|
+
# Secure Cell in Context Imprint mode.
|
827
|
+
class ScellContextImprint < Scell
|
828
|
+
include ThemisCommon
|
829
|
+
include ThemisImport
|
830
|
+
|
831
|
+
# Make a new Secure Cell with given key.
|
832
|
+
# The key must not be empty and is treated as binary data.
|
833
|
+
# You can use Themis::gen_sym_key to generate new keys.
|
834
|
+
def initialize(key)
|
835
|
+
if empty? key
|
836
|
+
raise ThemisError, "key cannot be empty"
|
837
|
+
end
|
838
|
+
@key, @key_length = string_to_pointer_size(key)
|
839
|
+
end
|
840
|
+
|
841
|
+
# Encrypts message with given context.
|
842
|
+
# The context is cryptographically combined with message but is not included
|
843
|
+
# into encrypted data, you will need to provide the same context for decryption.
|
844
|
+
# Resulting encrypted message has the same length as input and does not include
|
845
|
+
# authentication data, so its integrity cannot be verified.
|
846
|
+
# Message and context must not be empty, both are treated as binary data.
|
847
|
+
def encrypt(message, context)
|
848
|
+
if empty? message
|
849
|
+
raise ThemisError, "message cannot be empty"
|
850
|
+
end
|
851
|
+
if empty? context
|
852
|
+
raise ThemisError, "context cannot be empty"
|
853
|
+
end
|
854
|
+
|
855
|
+
message_, message_length_ = string_to_pointer_size(message)
|
856
|
+
context_, context_length_ =
|
857
|
+
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
858
|
+
|
859
|
+
encrypted_length = FFI::MemoryPointer.new(:uint)
|
860
|
+
res = themis_secure_cell_encrypt_context_imprint(
|
861
|
+
@key, @key_length, message_, message_length_,
|
862
|
+
context_, context_length_, nil, encrypted_length)
|
863
|
+
if res != BUFFER_TOO_SMALL
|
864
|
+
raise ThemisError.new(res), "encrypt failed"
|
865
|
+
end
|
866
|
+
|
867
|
+
encrypted_message = FFI::MemoryPointer.new(:char, encrypted_length.read_uint)
|
868
|
+
res = themis_secure_cell_encrypt_context_imprint(
|
869
|
+
@key, @key_length, message_, message_length_,
|
870
|
+
context_, context_length_, encrypted_message, encrypted_length)
|
871
|
+
if res != SUCCESS
|
872
|
+
raise ThemisError.new(res), "encrypt failed"
|
873
|
+
end
|
874
|
+
|
875
|
+
encrypted_message.get_bytes(0, encrypted_length.read_uint)
|
876
|
+
end
|
877
|
+
|
878
|
+
# Decrypts message with given context.
|
879
|
+
# The context must be the same as the one used during encryption.
|
880
|
+
# Since Context Imprint mode does not include authentication data,
|
881
|
+
# integrity of the resulting message is not guaranteed.
|
882
|
+
# You need to verify it via some other means.
|
883
|
+
# Decrypted message is returned as binary data.
|
884
|
+
def decrypt(message, context)
|
885
|
+
if empty? message
|
886
|
+
raise ThemisError, "message cannot be empty"
|
887
|
+
end
|
888
|
+
if empty? context
|
889
|
+
raise ThemisError, "message cannot be empty"
|
890
|
+
end
|
891
|
+
|
892
|
+
message_, message_length_ = string_to_pointer_size(message)
|
893
|
+
context_, context_length_ =
|
894
|
+
context.nil? ? [nil, 0] : string_to_pointer_size(context)
|
895
|
+
|
896
|
+
decrypted_length = FFI::MemoryPointer.new(:uint)
|
897
|
+
res = themis_secure_cell_decrypt_context_imprint(
|
898
|
+
@key, @key_length, message_, message_length_,
|
899
|
+
context_, context_length_, nil, decrypted_length)
|
900
|
+
if res != BUFFER_TOO_SMALL
|
901
|
+
raise ThemisError.new(res), "decrypt failed"
|
902
|
+
end
|
903
|
+
|
904
|
+
decrypted_message = FFI::MemoryPointer.new(:char, decrypted_length.read_uint)
|
905
|
+
res = themis_secure_cell_decrypt_context_imprint(
|
906
|
+
@key, @key_length, message_, message_length_,
|
907
|
+
context_, context_length_, decrypted_message, decrypted_length)
|
908
|
+
if res != SUCCESS
|
909
|
+
raise ThemisError.new(res), "decrypt failed"
|
910
|
+
end
|
911
|
+
|
912
|
+
decrypted_message.get_bytes(0, decrypted_length.read_uint)
|
627
913
|
end
|
628
914
|
end
|
629
915
|
|
@@ -702,4 +988,5 @@ module Themis
|
|
702
988
|
module_function :Sverify
|
703
989
|
module_function :s_sign
|
704
990
|
module_function :s_verify
|
991
|
+
module_function :gen_sym_key
|
705
992
|
end
|
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.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- CossackLabs
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ffi
|
@@ -30,11 +30,10 @@ dependencies:
|
|
30
30
|
- - ">="
|
31
31
|
- !ruby/object:Gem::Version
|
32
32
|
version: 1.9.8
|
33
|
-
description: Themis is a
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
and cross-platform availability.
|
33
|
+
description: Themis is a convenient cryptographic library for data protection. It
|
34
|
+
provides secure messaging with forward secrecy and secure data storage. Themis is
|
35
|
+
aimed at modern development practices and has a unified API across 12 platforms,
|
36
|
+
including Ruby, JavaScript, iOS/macOS, Python, and Java/Android.
|
38
37
|
email: dev@cossacklabs.com
|
39
38
|
executables: []
|
40
39
|
extensions: []
|
@@ -60,7 +59,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
60
59
|
- !ruby/object:Gem::Version
|
61
60
|
version: '0'
|
62
61
|
requirements:
|
63
|
-
- libthemis, v0.
|
62
|
+
- libthemis, v0.13.0
|
64
63
|
rubygems_version: 3.0.2
|
65
64
|
signing_key:
|
66
65
|
specification_version: 4
|