Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new Secure Message API in RubyThemis #402

Merged
merged 3 commits into from Mar 4, 2019
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
109 changes: 85 additions & 24 deletions src/wrappers/themis/ruby/lib/rubythemis.rb
Expand Up @@ -56,18 +56,33 @@ class CallbacksStruct < FFI::Struct
[:pointer, :pointer, :int, :pointer, :pointer], :int
attach_function :secure_session_is_established, [:pointer], :bool

attach_function :themis_secure_message_wrap,
attach_function :themis_secure_message_encrypt,
[:pointer, :int, :pointer, :int, :pointer,
:int, :pointer, :pointer], :int
attach_function :themis_secure_message_unwrap,
attach_function :themis_secure_message_decrypt,
[:pointer, :int, :pointer, :int, :pointer,
:int, :pointer, :pointer], :int
attach_function :themis_secure_message_sign,
[:pointer, :int, :pointer, :int, :pointer,
:pointer], :int
attach_function :themis_secure_message_verify,
[:pointer, :int, :pointer, :int, :pointer,
:pointer], :int

attach_function :themis_gen_rsa_key_pair,
[:pointer, :pointer, :pointer, :pointer], :int
attach_function :themis_gen_ec_key_pair,
[:pointer, :pointer, :pointer, :pointer], :int

THEMIS_KEY_INVALID = 0
THEMIS_KEY_RSA_PRIVATE = 1
THEMIS_KEY_RSA_PUBLIC = 2
THEMIS_KEY_EC_PRIVATE = 3
THEMIS_KEY_EC_PUBLIC = 4

attach_function :themis_is_valid_asym_key, [:pointer, :int], :int
attach_function :themis_get_asym_key_kind, [:pointer, :int], :int

attach_function :themis_secure_cell_encrypt_seal,
[:pointer, :int, :pointer, :int, :pointer, :int,
:pointer, :pointer], :int
Expand Down Expand Up @@ -181,6 +196,28 @@ def rsa
end
end

def Themis.valid_key(key)
if key.nil? || key.empty?
return false
end
key_, len_ = string_to_pointer_size(key)
return themis_is_valid_asym_key(key_, len_) == SUCCESS
end

def Themis.private_key(key)
key_, len_ = string_to_pointer_size(key)
kind = themis_get_asym_key_kind(key_, len_)
return kind == ThemisImport::THEMIS_KEY_RSA_PRIVATE \
|| kind == ThemisImport::THEMIS_KEY_EC_PRIVATE
end

def Themis.public_key(key)
key_, len_ = string_to_pointer_size(key)
kind = themis_get_asym_key_kind(key_, len_)
return kind == ThemisImport::THEMIS_KEY_RSA_PUBLIC \
|| kind == ThemisImport::THEMIS_KEY_EC_PUBLIC
end

class Ssession
include ThemisCommon
include ThemisImport
Expand Down Expand Up @@ -299,6 +336,19 @@ class Smessage
include ThemisImport

def initialize(private_key, peer_public_key)
if not Themis.valid_key(private_key)
raise ThemisError, "Secure Message: invalid private key"
end
if not Themis.valid_key(peer_public_key)
raise ThemisError, "Secure Message: invalid public key"
end
if not Themis.private_key(private_key)
raise ThemisError, "Secure Message: public key used instead of private"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice checks :)

end
if not Themis.public_key(peer_public_key)
raise ThemisError, "Secure Message: private key used instead of public"
end

@private_key, @private_key_length = string_to_pointer_size(private_key)
@peer_public_key, @peer_public_key_length =
string_to_pointer_size(peer_public_key)
Expand All @@ -308,22 +358,22 @@ def wrap(message)
message_, message_length_ = string_to_pointer_size(message)

wrapped_message_length = FFI::MemoryPointer.new(:uint)
res = themis_secure_message_wrap(
res = themis_secure_message_encrypt(
@private_key, @private_key_length, @peer_public_key,
@peer_public_key_length, message_, message_length_,
nil, wrapped_message_length)
if res != BUFFER_TOO_SMALL
raise ThemisError, "Secure Message failed encrypting: #{res}"
raise ThemisError, "Secure Message failed to encrypt: #{res}"
end

wrapped_message = FFI::MemoryPointer.new(
:char, wrapped_message_length.read_uint)
res = themis_secure_message_wrap(
res = themis_secure_message_encrypt(
@private_key, @private_key_length, @peer_public_key,
@peer_public_key_length, message_, message_length_,
wrapped_message, wrapped_message_length)
if res != SUCCESS
raise ThemisError, "Secure Message failed encrypting: #{res}"
raise ThemisError, "Secure Message failed to encrypt: #{res}"
end

wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
Expand All @@ -332,22 +382,22 @@ def wrap(message)
def unwrap(message)
message_, message_length_ = string_to_pointer_size(message)
unwrapped_message_length = FFI::MemoryPointer.new(:uint)
res = themis_secure_message_unwrap(
res = themis_secure_message_decrypt(
@private_key, @private_key_length, @peer_public_key,
@peer_public_key_length, message_, message_length_,
nil, unwrapped_message_length)
if res != BUFFER_TOO_SMALL
raise ThemisError, "Secure Message failed decrypting: #{res}"
raise ThemisError, "Secure Message failed to decrypt: #{res}"
end

unwrapped_message = FFI::MemoryPointer.new(
:char, unwrapped_message_length.read_uint)
res = themis_secure_message_unwrap(
res = themis_secure_message_decrypt(
@private_key, @private_key_length, @peer_public_key,
@peer_public_key_length, message_, message_length_,
unwrapped_message, unwrapped_message_length)
if res != SUCCESS
raise ThemisError, "Secure Message failed decrypting: #{res}"
raise ThemisError, "Secure Message failed to decrypt: #{res}"
end

unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
Expand All @@ -360,24 +410,31 @@ def Ssign(*args)
deprecate :Ssign, :s_sign, 2018, 6

def s_sign(private_key, message)
if not valid_key(private_key)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

technically speaking for user both these checks are the same -- wrong / empty / bad key.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would rather prefer to merge these checks in one, or use "Secure Message: private key used instead of public" as second error message

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a difference between "using an incorrect key" and "using a key incorrectly". If we get to the second check we are sure that the key is at least valid so we should not tell the user that their key is garbled or something.

I guess I'll reuse the same messages as for the encrypt/decrypt mode.

raise ThemisError, "Secure Message: invalid private key"
end
if not private_key(private_key)
raise ThemisError, "Secure Message: not a private key"
end

private_key_, private_key_length_ = string_to_pointer_size(private_key)
message_, message_length_ = string_to_pointer_size(message)

wrapped_message_length = FFI::MemoryPointer.new(:uint)
res = themis_secure_message_wrap(
private_key_, private_key_length_, nil, 0, message_,
res = themis_secure_message_sign(
private_key_, private_key_length_, message_,
message_length_, nil, wrapped_message_length)
if res != BUFFER_TOO_SMALL
raise ThemisError, "Secure Message failed singing: #{res}"
raise ThemisError, "Secure Message failed to sign: #{res}"
end

wrapped_message = FFI::MemoryPointer.new(
:char, wrapped_message_length.read_uint)
res = themis_secure_message_wrap(
private_key_, private_key_length_, nil, 0, message_,
res = themis_secure_message_sign(
private_key_, private_key_length_, message_,
message_length_, wrapped_message, wrapped_message_length)
if res != SUCCESS
raise ThemisError, "Secure Message failed singing: #{res}"
raise ThemisError, "Secure Message failed to sign: #{res}"
end

wrapped_message.get_bytes(0, wrapped_message_length.read_uint)
Expand All @@ -389,27 +446,31 @@ def Sverify(*args)
deprecate :Sverify, :s_verify, 2018, 6

def s_verify(peer_public_key, message)
include ThemisCommon
include ThemisImport
if not valid_key(peer_public_key)
raise ThemisError, "Secure Message: invalid public key"
end
if not public_key(peer_public_key)
raise ThemisError, "Secure Message: not a public key"
end

public_key_, public_key_length_ = string_to_pointer_size(peer_public_key)
message_, message_length_ = string_to_pointer_size(message)

unwrapped_message_length = FFI::MemoryPointer.new(:uint)
res = themis_secure_message_unwrap(
nil, 0, public_key_, public_key_length_, message_,
res = themis_secure_message_verify(
public_key_, public_key_length_, message_,
message_length_, nil, unwrapped_message_length)
if res != BUFFER_TOO_SMALL
raise ThemisError, "Secure Message failed verifying: #{res}"
raise ThemisError, "Secure Message failed to verify: #{res}"
end

unwrapped_message = FFI::MemoryPointer.new(
:char, unwrapped_message_length.read_uint)
res = themis_secure_message_unwrap(
nil, 0, public_key_, public_key_length_, message_,
res = themis_secure_message_verify(
public_key_, public_key_length_, message_,
message_length_, unwrapped_message, unwrapped_message_length)
if res != SUCCESS
raise ThemisError, "Secure Message failed verifying: #{res}"
raise ThemisError, "Secure Message failed to verify: #{res}"
end

unwrapped_message.get_bytes(0, unwrapped_message_length.read_uint)
Expand Down
13 changes: 12 additions & 1 deletion tests/rubythemis/smessage_test.rb
Expand Up @@ -52,7 +52,6 @@ def test_encrypt_decrypt
].each do |k1, k2|
assert_raise(Themis::ThemisError) do
smessage = Themis::Smessage.new(k1, k2)
encrypted_message = smessage.wrap(@message)
end
end

Expand All @@ -73,12 +72,24 @@ def test_encrypt_decrypt
end

def test_sign_verify
assert_raise(Themis::ThemisError) do
signed_message = Themis.s_sign('', @message)
end
assert_raise(Themis::ThemisError) do
signed_message = Themis.s_sign(@ec256_pub, @message)
end
assert_raise(Themis::ThemisError) do
signed_message = Themis.s_sign(@ec256_priv, '')
end

signed_message = Themis.s_sign(@ec256_priv, @message)
assert_raise(Themis::ThemisError) do
verified_message = Themis.s_verify('', signed_message)
end
assert_raise(Themis::ThemisError) do
verified_message = Themis.s_verify(@ec256_priv, signed_message)
end

@keys.each do |k|
signed_message = Themis.s_sign(k[0], @message)
verifyed_message = Themis.s_verify(k[1], signed_message)
Expand Down