rbthemis 0.12.0 → 0.13.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.
- 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
|