ffi-libsodium 0.0.1
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 +7 -0
- data/LICENSE +191 -0
- data/README.md +21 -0
- data/lib/crypto/aead/chacha20_poly1305.rb +75 -0
- data/lib/crypto/auth.rb +54 -0
- data/lib/crypto/box.rb +150 -0
- data/lib/crypto/generic_hash.rb +123 -0
- data/lib/crypto/one_time_auth.rb +87 -0
- data/lib/crypto/pw_hash/scrypt_salsa208_sha256.rb +101 -0
- data/lib/crypto/scalar_mult.rb +55 -0
- data/lib/crypto/secret_box.rb +101 -0
- data/lib/crypto/short_hash.rb +41 -0
- data/lib/crypto/sign.rb +102 -0
- data/lib/libsodium.rb +21 -0
- data/lib/random_bytes.rb +21 -0
- data/lib/sodium.rb +69 -0
- data/lib/sodium/buffer.rb +11 -0
- data/lib/sodium/secret_buffer.rb +58 -0
- data/lib/sodium/utils.rb +71 -0
- data/lib/sodium/version.rb +3 -0
- metadata +90 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
require_relative '../sodium'
|
|
2
|
+
require_relative '../sodium/utils'
|
|
3
|
+
require_relative '../sodium/buffer'
|
|
4
|
+
require_relative '../sodium/secret_buffer'
|
|
5
|
+
|
|
6
|
+
module Crypto
|
|
7
|
+
module GenericHash
|
|
8
|
+
extend FFI::Library
|
|
9
|
+
extend Sodium::Utils
|
|
10
|
+
|
|
11
|
+
ffi_lib :libsodium
|
|
12
|
+
|
|
13
|
+
attach_function :primitive, :crypto_generichash_primitive, [], :string
|
|
14
|
+
attach_function :bytes_min, :crypto_generichash_bytes_min, [], :size_t
|
|
15
|
+
attach_function :bytes_max, :crypto_generichash_bytes_max, [], :size_t
|
|
16
|
+
attach_function :bytes, :crypto_generichash_bytes, [], :size_t
|
|
17
|
+
attach_function :keybytes_min, :crypto_generichash_keybytes_min, [], :size_t
|
|
18
|
+
attach_function :keybytes_max, :crypto_generichash_keybytes_max, [], :size_t
|
|
19
|
+
attach_function :keybytes, :crypto_generichash_keybytes, [], :size_t
|
|
20
|
+
|
|
21
|
+
PRIMITIVE = primitive.freeze
|
|
22
|
+
BYTES_MIN = bytes_min.freeze
|
|
23
|
+
BYTES_MAX = bytes_max.freeze
|
|
24
|
+
BYTES = bytes.freeze
|
|
25
|
+
KEYBYTES_MIN = keybytes_min.freeze
|
|
26
|
+
KEYBYTES_MAX = keybytes_max.freeze
|
|
27
|
+
KEYBYTES = keybytes.freeze
|
|
28
|
+
|
|
29
|
+
attach_function :crypto_generichash, [:buffer_out, :size_t, :buffer_in, :ulong_long, :buffer_in, :size_t], :int, blocking: true
|
|
30
|
+
|
|
31
|
+
class State < FFI::Struct
|
|
32
|
+
pack 64
|
|
33
|
+
layout :h, [:uint64, 8],
|
|
34
|
+
:t, [:uint64, 2],
|
|
35
|
+
:f, [:uint64, 2],
|
|
36
|
+
:buf, [:uint8, 2 * 128],
|
|
37
|
+
:buflen, :size_t,
|
|
38
|
+
:last_node, :uint8
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
attach_function :crypto_generichash_init, [State.ptr, :buffer_in, :size_t, :size_t], :int, blocking: true
|
|
42
|
+
attach_function :crypto_generichash_update, [State.ptr, :buffer_in, :ulong_long], :int, blocking: true
|
|
43
|
+
attach_function :crypto_generichash_final, [State.ptr, :buffer_out, :ulong_long], :int, blocking: true
|
|
44
|
+
|
|
45
|
+
module_function
|
|
46
|
+
|
|
47
|
+
def generichash(message, hash_size = BYTES, key = nil)
|
|
48
|
+
message_len = get_size(message)
|
|
49
|
+
if hash_size > BYTES_MAX ||hash_size < BYTES_MIN
|
|
50
|
+
fail Sodium::LengthError, "Hash size must be between #{BYTES_MIN} and #{BYTES_MAX} bytes, got size=#{hash_size.to_int} bytes", caller
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
if key
|
|
54
|
+
key_len = get_size(key)
|
|
55
|
+
|
|
56
|
+
if key_len > KEYBYTES_MAX ||key_len < KEYBYTES_MIN
|
|
57
|
+
fail Sodium::LengthError, "Key length must be between #{KEYBYTES_MIN} and #{KEYBYTES_MAX} bytes, got length=#{key_len} bytes", caller
|
|
58
|
+
end
|
|
59
|
+
else
|
|
60
|
+
key_len = 0
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
blake2b = Sodium::Buffer.new(:uchar, hash_size)
|
|
64
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
65
|
+
rc = crypto_generichash(blake2b, hash_size, message, message_len, key, key_len)
|
|
66
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
67
|
+
if rc == -1
|
|
68
|
+
raise Sodium::CryptoError
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
blake2b
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def init(key = nil, hash_size = BYTES)
|
|
75
|
+
if key
|
|
76
|
+
key_len = get_size(key)
|
|
77
|
+
|
|
78
|
+
if key_len > KEYBYTES_MAX ||key_len < KEYBYTES_MIN
|
|
79
|
+
fail Sodium::LengthError, "Key length must be between #{KEYBYTES_MIN} and #{KEYBYTES_MAX} bytes, got length=#{key_len} bytes", caller
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
key_len = 0
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
if hash_size > BYTES_MAX ||hash_size < BYTES_MIN
|
|
86
|
+
fail Sodium::LengthError, "Hash size must be between #{BYTES_MIN} and #{BYTES_MAX} bytes, got size=#{hash_size.to_int} bytes", caller
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
state = State.new
|
|
90
|
+
blake2b = Sodium::Buffer.new(:uchar, hash_size)
|
|
91
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
92
|
+
rc = crypto_generichash_init(state, key, key_len, hash_size)
|
|
93
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
94
|
+
if rc == -1
|
|
95
|
+
raise Sodium::CryptoError
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
[state, blake2b]
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def update(state, message)
|
|
102
|
+
message_len = get_size(message)
|
|
103
|
+
|
|
104
|
+
if crypto_generichash_update(state, message, message_len) == -1
|
|
105
|
+
raise Sodium::CryptoError
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def final(state, blake2b)
|
|
110
|
+
get_pointer(blake2b)
|
|
111
|
+
|
|
112
|
+
if crypto_generichash_final(state, blake2b, blake2b.size) == -1
|
|
113
|
+
raise Sodium::CryptoError
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
blake2b
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def self.generichash(*args)
|
|
121
|
+
GenericHash.generichash(*args)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require_relative '../sodium'
|
|
2
|
+
require_relative '../sodium/utils'
|
|
3
|
+
require_relative '../sodium/buffer'
|
|
4
|
+
require_relative '../sodium/secret_buffer'
|
|
5
|
+
|
|
6
|
+
module Crypto
|
|
7
|
+
module OneTimeAuth
|
|
8
|
+
extend FFI::Library
|
|
9
|
+
extend Sodium::Utils
|
|
10
|
+
|
|
11
|
+
ffi_lib :libsodium
|
|
12
|
+
|
|
13
|
+
attach_function :primitive, :crypto_onetimeauth_primitive, [], :string
|
|
14
|
+
attach_function :bytes, :crypto_onetimeauth_bytes, [], :size_t
|
|
15
|
+
attach_function :keybytes, :crypto_onetimeauth_keybytes, [], :size_t
|
|
16
|
+
|
|
17
|
+
PRIMITIVE = primitive.freeze
|
|
18
|
+
BYTES = bytes.freeze
|
|
19
|
+
KEYBYTES = keybytes.freeze
|
|
20
|
+
|
|
21
|
+
attach_function :crypto_onetimeauth, [:buffer_out, :buffer_in, :ulong_long, :buffer_in], :int
|
|
22
|
+
attach_function :crypto_onetimeauth_verify, [:buffer_in, :buffer_in, :ulong_long, :buffer_in], :int
|
|
23
|
+
|
|
24
|
+
class State < FFI::Struct
|
|
25
|
+
layout :aligner, :ulong_long,
|
|
26
|
+
:opaque, [:uchar, 136]
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
attach_function :crypto_onetimeauth_init, [State.ptr, :buffer_in], :int
|
|
30
|
+
attach_function :crypto_onetimeauth_update, [State.ptr, :buffer_in, :ulong_long], :int
|
|
31
|
+
attach_function :crypto_onetimeauth_final, [State.ptr, :buffer_out], :int
|
|
32
|
+
|
|
33
|
+
module_function
|
|
34
|
+
|
|
35
|
+
def onetimeauth(message, key)
|
|
36
|
+
message_len = get_size(message)
|
|
37
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
38
|
+
|
|
39
|
+
out = Sodium::Buffer.new(:uchar, BYTES)
|
|
40
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
41
|
+
crypto_onetimeauth(out, message, message_len, key)
|
|
42
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
43
|
+
|
|
44
|
+
out
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def verify(out, message, key)
|
|
48
|
+
check_length(out, BYTES, :Authenticator)
|
|
49
|
+
message_len = get_size(message)
|
|
50
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
51
|
+
|
|
52
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
53
|
+
rc = crypto_onetimeauth_verify(out, message, message_len, key)
|
|
54
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
55
|
+
|
|
56
|
+
rc == 0
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def init(key)
|
|
60
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
61
|
+
|
|
62
|
+
state = State.new
|
|
63
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
64
|
+
crypto_onetimeauth_init(state, key)
|
|
65
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
66
|
+
|
|
67
|
+
state
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def update(state, message)
|
|
71
|
+
message_len = get_size(message)
|
|
72
|
+
|
|
73
|
+
crypto_onetimeauth_update(state, message, message_len)
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def final(state)
|
|
77
|
+
out = Sodium::Buffer.new(:uchar, BYTES)
|
|
78
|
+
crypto_onetimeauth_final(state, out)
|
|
79
|
+
|
|
80
|
+
out
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def self.onetimeauth(*args)
|
|
85
|
+
OneTimeAuth.onetimeauth(*args)
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require_relative '../../sodium'
|
|
2
|
+
require_relative '../../sodium/utils'
|
|
3
|
+
require_relative '../../sodium/buffer'
|
|
4
|
+
require_relative '../../sodium/secret_buffer'
|
|
5
|
+
require_relative '../../random_bytes'
|
|
6
|
+
|
|
7
|
+
module Crypto
|
|
8
|
+
module PwHash
|
|
9
|
+
module ScryptSalsa208SHA256
|
|
10
|
+
PACK_C = 'c*'.freeze
|
|
11
|
+
PRIMITIVE = 'scryptsalsa208sha256'.freeze
|
|
12
|
+
|
|
13
|
+
extend FFI::Library
|
|
14
|
+
extend Sodium::Utils
|
|
15
|
+
|
|
16
|
+
ffi_lib :libsodium
|
|
17
|
+
|
|
18
|
+
class << self
|
|
19
|
+
def crypto_pwhash_scryptsalsa208sha256_primitive
|
|
20
|
+
PRIMITIVE
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
alias_method :primitive, :crypto_pwhash_scryptsalsa208sha256_primitive
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
attach_function :saltbytes, :crypto_pwhash_scryptsalsa208sha256_saltbytes, [], :size_t
|
|
27
|
+
attach_function :strbytes, :crypto_pwhash_scryptsalsa208sha256_strbytes, [], :size_t
|
|
28
|
+
attach_function :strprefix, :crypto_pwhash_scryptsalsa208sha256_strprefix, [], :string
|
|
29
|
+
attach_function :opslimit_interactive, :crypto_pwhash_scryptsalsa208sha256_opslimit_interactive, [], :size_t
|
|
30
|
+
attach_function :memlimit_interactive, :crypto_pwhash_scryptsalsa208sha256_memlimit_interactive, [], :size_t
|
|
31
|
+
attach_function :opslimit_sensitive, :crypto_pwhash_scryptsalsa208sha256_opslimit_sensitive, [], :size_t
|
|
32
|
+
attach_function :memlimit_sensitive, :crypto_pwhash_scryptsalsa208sha256_memlimit_sensitive, [], :size_t
|
|
33
|
+
|
|
34
|
+
SALTBYTES = saltbytes.freeze
|
|
35
|
+
STRBYTES = strbytes.freeze
|
|
36
|
+
STRPREFIX = strprefix.freeze
|
|
37
|
+
OPSLIMIT_INTERACTIVE = opslimit_interactive.freeze
|
|
38
|
+
MEMLIMIT_INTERACTIVE = memlimit_interactive.freeze
|
|
39
|
+
OPSLIMIT_SENSITIVE = opslimit_sensitive.freeze
|
|
40
|
+
MEMLIMIT_SENSITIVE = memlimit_sensitive.freeze
|
|
41
|
+
|
|
42
|
+
attach_function :crypto_pwhash_scryptsalsa208sha256, [:buffer_out, :ulong_long, :buffer_in, :ulong_long, :buffer_in, :ulong_long, :size_t], :int, blocking: true
|
|
43
|
+
attach_function :crypto_pwhash_scryptsalsa208sha256_str, [:buffer_out, :buffer_in, :ulong_long, :ulong_long, :size_t], :int, blocking: true
|
|
44
|
+
attach_function :crypto_pwhash_scryptsalsa208sha256_str_verify, [:buffer_in, :buffer_in, :ulong_long], :int, blocking: true
|
|
45
|
+
|
|
46
|
+
module_function
|
|
47
|
+
|
|
48
|
+
def salt
|
|
49
|
+
RandomBytes.buf(SALTBYTES)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def scryptsalsa208sha256(passwd, outlen, salt, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
|
|
53
|
+
passwd_len = get_size(passwd)
|
|
54
|
+
check_length(salt, SALTBYTES, :Salt)
|
|
55
|
+
if opslimit < OPSLIMIT_INTERACTIVE
|
|
56
|
+
fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit.to_int}", caller
|
|
57
|
+
end
|
|
58
|
+
if memlimit < MEMLIMIT_INTERACTIVE
|
|
59
|
+
fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit.to_int}", caller
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
out = Sodium::SecretBuffer.new(outlen)
|
|
63
|
+
rc = crypto_pwhash_scryptsalsa208sha256(out, outlen, passwd, passwd_len, salt, opslimit, memlimit)
|
|
64
|
+
out.noaccess
|
|
65
|
+
if rc == -1
|
|
66
|
+
raise NoMemoryError, "Failed to allocate memory max size=#{memlimit.to_int} bytes", caller
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
out
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def str(passwd, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
|
|
73
|
+
passwd_len = get_size(passwd)
|
|
74
|
+
if opslimit < OPSLIMIT_INTERACTIVE
|
|
75
|
+
fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit.to_int}", caller
|
|
76
|
+
end
|
|
77
|
+
if memlimit < MEMLIMIT_INTERACTIVE
|
|
78
|
+
fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit.to_int}", caller
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
hashed_password = FFI::MemoryPointer.new(:char, STRBYTES)
|
|
82
|
+
if crypto_pwhash_scryptsalsa208sha256_str(hashed_password, passwd, passwd_len, opslimit, memlimit) == -1
|
|
83
|
+
raise NoMemoryError, "Failed to allocate memory max size=#{memlimit.to_int} bytes", caller
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
hashed_password.read_array_of_char(STRBYTES).pack(PACK_C)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def str_verify(str, passwd)
|
|
90
|
+
check_length(str, STRBYTES, :Str)
|
|
91
|
+
passwd_len = get_size(passwd)
|
|
92
|
+
|
|
93
|
+
crypto_pwhash_scryptsalsa208sha256_str_verify(str, passwd, passwd_len) == 0
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def self.scryptsalsa208sha256(*args)
|
|
98
|
+
ScryptSalsa208SHA256.scryptsalsa208sha256(*args)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
require_relative '../sodium'
|
|
2
|
+
require_relative '../sodium/utils'
|
|
3
|
+
require_relative '../sodium/buffer'
|
|
4
|
+
require_relative '../sodium/secret_buffer'
|
|
5
|
+
require_relative '../random_bytes'
|
|
6
|
+
|
|
7
|
+
module Crypto
|
|
8
|
+
module ScalarMult
|
|
9
|
+
extend FFI::Library
|
|
10
|
+
extend Sodium::Utils
|
|
11
|
+
|
|
12
|
+
ffi_lib :libsodium
|
|
13
|
+
|
|
14
|
+
attach_function :primitive, :crypto_scalarmult_primitive, [], :string
|
|
15
|
+
attach_function :bytes, :crypto_scalarmult_bytes, [], :size_t
|
|
16
|
+
attach_function :scalarbytes, :crypto_scalarmult_scalarbytes, [], :size_t
|
|
17
|
+
|
|
18
|
+
PRIMITIVE = primitive.freeze
|
|
19
|
+
BYTES = bytes.freeze
|
|
20
|
+
SCALARBYTES = scalarbytes.freeze
|
|
21
|
+
|
|
22
|
+
attach_function :crypto_scalarmult_base, [:buffer_out, :buffer_in], :int
|
|
23
|
+
attach_function :crypto_scalarmult, [:buffer_out, :buffer_in, :buffer_in], :int
|
|
24
|
+
|
|
25
|
+
module_function
|
|
26
|
+
|
|
27
|
+
def base(secret_key)
|
|
28
|
+
check_length(secret_key, SCALARBYTES, :SecretKey)
|
|
29
|
+
|
|
30
|
+
public_key = Sodium::Buffer.new(:uchar, BYTES)
|
|
31
|
+
secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
|
|
32
|
+
crypto_scalarmult_base(public_key, secret_key)
|
|
33
|
+
secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
|
|
34
|
+
|
|
35
|
+
public_key
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def scalarmut(secret_key, public_key)
|
|
39
|
+
check_length(secret_key, SCALARBYTES, :SecretKey)
|
|
40
|
+
check_length(public_key, SCALARBYTES, :PublicKey)
|
|
41
|
+
|
|
42
|
+
shared_secret = Sodium::SecretBuffer.new(BYTES)
|
|
43
|
+
secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
|
|
44
|
+
crypto_scalarmult(shared_secret, secret_key, public_key)
|
|
45
|
+
secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
|
|
46
|
+
shared_secret.noaccess
|
|
47
|
+
|
|
48
|
+
shared_secret
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def self.scalarmut(*args)
|
|
53
|
+
ScalarMult.scalarmut(*args)
|
|
54
|
+
end
|
|
55
|
+
end
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
require_relative '../sodium'
|
|
2
|
+
require_relative '../sodium/utils'
|
|
3
|
+
require_relative '../sodium/buffer'
|
|
4
|
+
require_relative '../sodium/secret_buffer'
|
|
5
|
+
require_relative '../random_bytes'
|
|
6
|
+
|
|
7
|
+
module Crypto
|
|
8
|
+
module SecretBox
|
|
9
|
+
extend FFI::Library
|
|
10
|
+
extend Sodium::Utils
|
|
11
|
+
|
|
12
|
+
ffi_lib :libsodium
|
|
13
|
+
|
|
14
|
+
attach_function :primitive, :crypto_secretbox_primitive, [], :string
|
|
15
|
+
attach_function :keybytes, :crypto_secretbox_keybytes, [], :size_t
|
|
16
|
+
attach_function :noncebytes, :crypto_secretbox_noncebytes, [], :size_t
|
|
17
|
+
attach_function :macbytes, :crypto_secretbox_macbytes, [], :size_t
|
|
18
|
+
|
|
19
|
+
PRIMITIVE = primitive.freeze
|
|
20
|
+
KEYBYTES = keybytes.freeze
|
|
21
|
+
NONCEBYTES = noncebytes.freeze
|
|
22
|
+
MACBYTES = macbytes.freeze
|
|
23
|
+
|
|
24
|
+
attach_function :crypto_secretbox_easy, [:buffer_out, :buffer_in, :ulong_long, :buffer_in, :buffer_in], :int, blocking: true
|
|
25
|
+
attach_function :crypto_secretbox_open_easy, [:buffer_out, :buffer_in, :ulong_long, :buffer_in, :buffer_in], :int, blocking: true
|
|
26
|
+
|
|
27
|
+
module_function
|
|
28
|
+
|
|
29
|
+
def nonce
|
|
30
|
+
RandomBytes.buf(NONCEBYTES)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def easy(message, nonce, key)
|
|
34
|
+
message_len = get_size(message)
|
|
35
|
+
check_length(nonce, NONCEBYTES, :Nonce)
|
|
36
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
37
|
+
|
|
38
|
+
ciphertext = Sodium::Buffer.new(:uchar, MACBYTES + message_len)
|
|
39
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
40
|
+
crypto_secretbox_easy(ciphertext, message, message_len, nonce, key)
|
|
41
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
42
|
+
|
|
43
|
+
ciphertext
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def open_easy(ciphertext, nonce, key)
|
|
47
|
+
ciphertext_len = get_size(ciphertext)
|
|
48
|
+
check_length(nonce, NONCEBYTES, :Nonce)
|
|
49
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
50
|
+
|
|
51
|
+
decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - MACBYTES)
|
|
52
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
53
|
+
rc = crypto_secretbox_open_easy(decrypted, ciphertext, ciphertext_len, nonce, key)
|
|
54
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
55
|
+
if rc == -1
|
|
56
|
+
raise Sodium::CryptoError, "Message forged", caller
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
decrypted
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def easy_in_place(data, nonce, key)
|
|
63
|
+
message = get_string(data)
|
|
64
|
+
check_length(nonce, NONCEBYTES, :Nonce)
|
|
65
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
66
|
+
|
|
67
|
+
message_len = message.bytesize
|
|
68
|
+
message << zeros(MACBYTES)
|
|
69
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
70
|
+
crypto_secretbox_easy(message, message, message_len, nonce, key)
|
|
71
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
72
|
+
|
|
73
|
+
message
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def open_easy_in_place(data, nonce, key, utf8 = false)
|
|
77
|
+
ciphertext = get_string(data)
|
|
78
|
+
unless (message_len = ciphertext.bytesize - MACBYTES) > 0
|
|
79
|
+
fail Sodium::LengthError, "Ciphertext is too short", caller
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
check_length(nonce, NONCEBYTES, :Nonce)
|
|
83
|
+
check_length(key, KEYBYTES, :SecretKey)
|
|
84
|
+
|
|
85
|
+
key.readonly if key.is_a?(Sodium::SecretBuffer)
|
|
86
|
+
rc = crypto_secretbox_open_easy(ciphertext, ciphertext, ciphertext.bytesize, nonce, key)
|
|
87
|
+
key.noaccess if key.is_a?(Sodium::SecretBuffer)
|
|
88
|
+
if rc == -1
|
|
89
|
+
raise Sodium::CryptoError, "Message forged", caller
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
if utf8
|
|
93
|
+
ciphertext.slice!(message_len..-1).force_encoding(Encoding::UTF_8)
|
|
94
|
+
else
|
|
95
|
+
ciphertext.slice!(message_len..-1)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
ciphertext
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|