ffi-libsodium 0.1.10 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e8f824b533e203a30b75bd97267e79eefbee9b04
4
- data.tar.gz: e791838d822463c909f23b885f48d9651e2c8dbc
3
+ metadata.gz: 95a7d9bb37cc560f3dfbb7a72a6bcf31ffdf63d6
4
+ data.tar.gz: 636823f16c86f508ff3180c56edb357a6b8afa2c
5
5
  SHA512:
6
- metadata.gz: de9b091d5911cfe41e0f34d15789a6a3dc4a2c608c760e0148542e7ec7c245531e7e2ac67879df21405dca1ea8931c64b02a817a25be73350395bf1bba7157a3
7
- data.tar.gz: 1336f51e32015d717ea5b409806fef90d342458528478d8c061a661e458f0c01e1f506c757da58d5b186a9c49817f454abc45b23c6ad0c7afab730598c5c5468
6
+ metadata.gz: e101ac68e41004c5b1dab8594baf37a6bd3c68fa6bb4981fdc556ef7d6d9cfac3e5aadaaec9c4ff11c524570fcf49500459aca5eed2486c8af7835235a0a5b61
7
+ data.tar.gz: 9c3e394cdf2941d370ad3c690c0bf17a335ba4cc9aba9aea5fa61b88bdff986369493be2348aa3d6663fff6e6e98c3aa6901d5fbefd5b59a5d3893f5bc696fa1
data/README.md CHANGED
@@ -11,7 +11,7 @@ bundle update
11
11
  require 'bundler/setup'
12
12
  require 'libsodium'
13
13
 
14
- password = 'test123'
14
+ password = Crypto.generichash('test123')
15
15
 
16
16
  salt = Crypto::PwHash::ScryptSalsa208SHA256.salt
17
17
  key = Crypto::PwHash.scryptsalsa208sha256(Crypto::Auth::KEYBYTES, password, salt)
@@ -46,7 +46,6 @@ module Crypto
46
46
  check_length(key, KEYBYTES, :SecretKey)
47
47
 
48
48
  ciphertext = Sodium::Buffer.new(:uchar, message_len + ABYTES)
49
- ciphertext.primitive = PRIMITIVE
50
49
  key.readonly if key.is_a?(Sodium::SecretBuffer)
51
50
  crypto_aead_chacha20poly1305_encrypt(ciphertext, nil, message, message_len, additional_data, get_size(additional_data), nil, nonce, key)
52
51
 
@@ -56,22 +55,28 @@ module Crypto
56
55
  end
57
56
 
58
57
  def decrypt(ciphertext, additional_data, nonce, key)
59
- unless ((ciphertext_len = get_size(ciphertext)) - ABYTES) > 0
58
+ ciphertext_len = get_size(ciphertext)
59
+ if (decrypted_len = ciphertext_len - ABYTES) > 0
60
+ check_length(nonce, NPUBBYTES, :Nonce)
61
+ check_length(key, KEYBYTES, :SecretKey)
62
+
63
+ decrypted = Sodium::Buffer.new(:uchar, decrypted_len)
64
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
65
+ if crypto_aead_chacha20poly1305_decrypt(decrypted, nil, nil, ciphertext, ciphertext_len, additional_data, get_size(additional_data), nonce, key) == 0
66
+ decrypted
67
+ else
68
+ raise Sodium::CryptoError, "Message forged", caller
69
+ end
70
+ else
60
71
  fail Sodium::LengthError, "Ciphertext is too short", caller
61
72
  end
62
- check_length(nonce, NPUBBYTES, :Nonce)
63
- check_length(key, KEYBYTES, :SecretKey)
64
-
65
- decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - ABYTES)
66
- key.readonly if key.is_a?(Sodium::SecretBuffer)
67
- unless crypto_aead_chacha20poly1305_decrypt(decrypted, nil, nil, ciphertext, ciphertext_len, additional_data, get_size(additional_data), nonce, key).zero?
68
- raise Sodium::CryptoError, "Message forged", caller
69
- end
70
-
71
- decrypted
72
73
  ensure
73
74
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
74
75
  end
75
76
  end
77
+
78
+ Chacha20Poly1305.freeze
76
79
  end
80
+
81
+ AEAD.freeze
77
82
  end
data/lib/crypto/auth.rb CHANGED
@@ -27,7 +27,6 @@ module Crypto
27
27
  check_length(key, KEYBYTES, :SecretKey)
28
28
 
29
29
  mac = Sodium::Buffer.new(:uchar, BYTES)
30
- mac.primitive = PRIMITIVE
31
30
  key.readonly if key.is_a?(Sodium::SecretBuffer)
32
31
  crypto_auth(mac, message, get_size(message), key)
33
32
 
@@ -41,12 +40,14 @@ module Crypto
41
40
  check_length(key, KEYBYTES, :SecretKey)
42
41
 
43
42
  key.readonly if key.is_a?(Sodium::SecretBuffer)
44
- crypto_auth_verify(mac, message, get_size(message), key).zero?
43
+ crypto_auth_verify(mac, message, get_size(message), key) == 0
45
44
  ensure
46
45
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
47
46
  end
48
47
  end
49
48
 
49
+ Auth.freeze
50
+
50
51
  module_function
51
52
 
52
53
  def auth(*args)
data/lib/crypto/box.rb CHANGED
@@ -40,9 +40,7 @@ module Crypto
40
40
 
41
41
  def keypair
42
42
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
43
- public_key.primitive = PRIMITIVE
44
43
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
45
- secret_key.primitive = PRIMITIVE
46
44
  crypto_box_keypair(public_key, secret_key)
47
45
 
48
46
  [public_key, secret_key]
@@ -52,9 +50,7 @@ module Crypto
52
50
  check_length(seed, SEEDBYTES, :Seed)
53
51
 
54
52
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
55
- public_key.primitive = PRIMITIVE
56
53
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
57
- secret_key.primitive = PRIMITIVE
58
54
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
59
55
  crypto_box_seed_keypair(public_key, secret_key, seed)
60
56
 
@@ -65,8 +61,7 @@ module Crypto
65
61
 
66
62
  def memory_locked_keypair
67
63
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
68
- public_key.primitive = PRIMITIVE
69
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
64
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
70
65
  crypto_box_keypair(public_key, secret_key)
71
66
  secret_key.noaccess
72
67
 
@@ -77,8 +72,7 @@ module Crypto
77
72
  check_length(seed, SEEDBYTES, :Seed)
78
73
 
79
74
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
80
- public_key.primitive = PRIMITIVE
81
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
75
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
82
76
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
83
77
  crypto_box_seed_keypair(public_key, secret_key, seed)
84
78
  secret_key.noaccess
@@ -95,7 +89,6 @@ module Crypto
95
89
  check_length(secret_key, SECRETKEYBYTES, :SecretKey)
96
90
 
97
91
  ciphertext = Sodium::Buffer.new(:uchar, message_len + MACBYTES)
98
- ciphertext.primitive = PRIMITIVE
99
92
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
100
93
  crypto_box_easy(ciphertext, message, message_len, nonce, public_key, secret_key)
101
94
 
@@ -112,22 +105,22 @@ module Crypto
112
105
 
113
106
  decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - MACBYTES)
114
107
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
115
- unless crypto_box_open_easy(decrypted, ciphertext, ciphertext_len, nonce, public_key, secret_key).zero?
108
+ if crypto_box_open_easy(decrypted, ciphertext, ciphertext_len, nonce, public_key, secret_key) == 0
109
+ decrypted
110
+ else
116
111
  raise Sodium::CryptoError, "Message forged", caller
117
112
  end
118
-
119
- decrypted
120
113
  ensure
121
114
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
122
115
  end
123
116
 
124
117
  def easy_in_place(data, nonce, public_key, secret_key)
125
- message = get_string(data)
118
+ message = String(data)
126
119
  check_length(nonce, NONCEBYTES, :Nonce)
127
120
  check_length(public_key, PUBLICKEYBYTES, :PublicKey)
128
121
  check_length(secret_key, SECRETKEYBYTES, :SecretKey)
129
122
 
130
- message_len = get_size(message)
123
+ message_len = message.bytesize
131
124
  message << zeros(MACBYTES)
132
125
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
133
126
  crypto_box_easy(message, message, message_len, nonce, public_key, secret_key)
@@ -137,33 +130,36 @@ module Crypto
137
130
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
138
131
  end
139
132
 
140
- def open_easy_in_place(data, nonce, public_key, secret_key, utf8 = false)
141
- ciphertext = get_string(data)
142
- unless (message_len = get_size(ciphertext) - MACBYTES) > 0
143
- fail Sodium::LengthError, "Ciphertext is too short", caller
144
- end
145
-
146
- check_length(nonce, NONCEBYTES, :Nonce)
147
- check_length(public_key, PUBLICKEYBYTES, :PublicKey)
148
- check_length(secret_key, SECRETKEYBYTES, :SecretKey)
149
-
150
- secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
151
- unless crypto_box_open_easy(ciphertext, ciphertext, get_size(ciphertext), nonce, public_key, secret_key).zero?
152
- raise Sodium::CryptoError, "Message forged", caller
153
- end
154
-
155
- if utf8
156
- ciphertext.slice!(message_len..-1).force_encoding(Encoding::UTF_8)
133
+ def open_easy_in_place(data, nonce, public_key, secret_key, encoding = false)
134
+ ciphertext = String(data)
135
+ ciphertext_len = ciphertext.bytesize
136
+ if (message_len = ciphertext_len - MACBYTES) > 0
137
+ check_length(nonce, NONCEBYTES, :Nonce)
138
+ check_length(public_key, PUBLICKEYBYTES, :PublicKey)
139
+ check_length(secret_key, SECRETKEYBYTES, :SecretKey)
140
+
141
+ secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
142
+ if crypto_box_open_easy(ciphertext, ciphertext, ciphertext_len, nonce, public_key, secret_key) == 0
143
+ if encoding
144
+ ciphertext.slice!(message_len..-1).force_encoding(encoding)
145
+ else
146
+ ciphertext.slice!(message_len..-1)
147
+ end
148
+
149
+ ciphertext
150
+ else
151
+ raise Sodium::CryptoError, "Message forged", caller
152
+ end
157
153
  else
158
- ciphertext.slice!(message_len..-1)
154
+ fail Sodium::LengthError, "Ciphertext is too short", caller
159
155
  end
160
-
161
- ciphertext
162
156
  ensure
163
157
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
164
158
  end
165
159
  end
166
160
 
161
+ Box.freeze
162
+
167
163
  module_function
168
164
 
169
165
  def box(*args)
@@ -1,8 +1,8 @@
1
1
  require 'ffi'
2
2
  require_relative '../sodium/utils'
3
- require_relative '../sodium/errors'
4
3
  require_relative '../sodium/buffer'
5
4
  require_relative '../sodium/secret_buffer'
5
+ require_relative '../sodium/errors'
6
6
 
7
7
  module Crypto
8
8
  module GenericHash
@@ -46,28 +46,19 @@ module Crypto
46
46
  module_function
47
47
 
48
48
  def generichash(message, hash_size = BYTES, key = nil)
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} bytes", caller
51
- end
52
-
53
49
  if key
54
50
  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
51
  else
60
52
  key_len = 0
61
53
  end
62
54
 
63
55
  blake2b = Sodium::Buffer.new(:uchar, hash_size)
64
- blake2b.primitive = PRIMITIVE
65
56
  key.readonly if key.is_a?(Sodium::SecretBuffer)
66
- unless crypto_generichash(blake2b, hash_size, message, get_size(message), key, key_len).zero?
57
+ if crypto_generichash(blake2b, hash_size, message, get_size(message), key, key_len) == 0
58
+ blake2b
59
+ else
67
60
  raise Sodium::CryptoError
68
61
  end
69
-
70
- blake2b
71
62
  ensure
72
63
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
73
64
  end
@@ -75,47 +66,36 @@ module Crypto
75
66
  def init(key = nil, hash_size = BYTES)
76
67
  if key
77
68
  key_len = get_size(key)
78
-
79
- if key_len > KEYBYTES_MAX ||key_len < KEYBYTES_MIN
80
- fail Sodium::LengthError, "Key length must be between #{KEYBYTES_MIN} and #{KEYBYTES_MAX} bytes, got length=#{key_len} bytes", caller
81
- end
82
69
  else
83
70
  key_len = 0
84
71
  end
85
72
 
86
- if hash_size > BYTES_MAX ||hash_size < BYTES_MIN
87
- fail Sodium::LengthError, "Hash size must be between #{BYTES_MIN} and #{BYTES_MAX} bytes, got size=#{hash_size} bytes", caller
88
- end
89
-
90
73
  state = State.new
91
- blake2b = Sodium::Buffer.new(:uchar, hash_size)
92
- blake2b.primitive = PRIMITIVE
93
74
  key.readonly if key.is_a?(Sodium::SecretBuffer)
94
-
95
- unless crypto_generichash_init(state, key, key_len, hash_size).zero?
75
+ if crypto_generichash_init(state, key, key_len, hash_size) == 0
76
+ [state, Sodium::Buffer.new(:uchar, hash_size)]
77
+ else
96
78
  raise Sodium::CryptoError
97
79
  end
98
-
99
- [state, blake2b]
100
80
  ensure
101
81
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
102
82
  end
103
83
 
104
84
  def update(state, message)
105
- unless crypto_generichash_update(state, message, get_size(message)).zero?
106
- raise Sodium::CryptoError
107
- end
85
+ crypto_generichash_update(state, message, get_size(message))
108
86
  end
109
87
 
110
88
  def final(state, blake2b)
111
- unless crypto_generichash_final(state, blake2b, blake2b.size).zero?
89
+ if crypto_generichash_final(state, blake2b, blake2b.size) == 0
90
+ blake2b
91
+ else
112
92
  raise Sodium::CryptoError
113
93
  end
114
-
115
- blake2b
116
94
  end
117
95
  end
118
96
 
97
+ GenericHash.freeze
98
+
119
99
  module_function
120
100
 
121
101
  def generichash(*args)
@@ -36,7 +36,6 @@ module Crypto
36
36
  check_length(key, KEYBYTES, :SecretKey)
37
37
 
38
38
  out = Sodium::Buffer.new(:uchar, BYTES)
39
- out.primitive = PRIMITIVE
40
39
  key.readonly if key.is_a?(Sodium::SecretBuffer)
41
40
  crypto_onetimeauth(out, message, get_size(message), key)
42
41
 
@@ -50,7 +49,7 @@ module Crypto
50
49
  check_length(key, KEYBYTES, :SecretKey)
51
50
 
52
51
  key.readonly if key.is_a?(Sodium::SecretBuffer)
53
- crypto_onetimeauth_verify(out, message, get_size(message), key).zero?
52
+ crypto_onetimeauth_verify(out, message, get_size(message), key) == 0
54
53
  ensure
55
54
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
56
55
  end
@@ -73,13 +72,13 @@ module Crypto
73
72
 
74
73
  def final(state)
75
74
  out = Sodium::Buffer.new(:uchar, BYTES)
76
- out.primitive = PRIMITIVE
77
75
  crypto_onetimeauth_final(state, out)
78
-
79
76
  out
80
77
  end
81
78
  end
82
79
 
80
+ OneTimeAuth.freeze
81
+
83
82
  module_function
84
83
 
85
84
  def onetimeauth(*args)
@@ -49,51 +49,40 @@ module Crypto
49
49
  end
50
50
 
51
51
  def scryptsalsa208sha256(outlen, passwd, salt, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
52
- out = nil
53
52
  check_length(salt, SALTBYTES, :Salt)
54
- if opslimit < OPSLIMIT_INTERACTIVE
55
- fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit}", caller
56
- end
57
- if memlimit < MEMLIMIT_INTERACTIVE
58
- fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit}", caller
59
- end
60
53
 
61
- out = Sodium::SecretBuffer.new(outlen, PRIMITIVE)
62
- unless crypto_pwhash_scryptsalsa208sha256(out, outlen, passwd, get_size(passwd), salt, opslimit, memlimit).zero?
54
+ out = Sodium::SecretBuffer.new(outlen)
55
+ if crypto_pwhash_scryptsalsa208sha256(out, outlen, passwd, get_size(passwd), salt, opslimit, memlimit) == 0
56
+ out.noaccess
57
+ out
58
+ else
63
59
  raise NoMemoryError, "Failed to allocate memory max size=#{memlimit} bytes", caller
64
60
  end
65
-
66
- out
67
- ensure
68
- out.noaccess if out
69
61
  end
70
62
 
71
63
  def str(passwd, opslimit = OPSLIMIT_INTERACTIVE, memlimit = MEMLIMIT_INTERACTIVE)
72
- if opslimit < OPSLIMIT_INTERACTIVE
73
- fail Sodium::LengthError, "Opslimit must be at least #{OPSLIMIT_INTERACTIVE}, got #{opslimit}", caller
74
- end
75
- if memlimit < MEMLIMIT_INTERACTIVE
76
- fail Sodium::LengthError, "Memlimit must be at least #{MEMLIMIT_INTERACTIVE}, got #{memlimit}", caller
77
- end
78
-
79
64
  hashed_password = FFI::MemoryPointer.new(:char, STRBYTES)
80
- unless crypto_pwhash_scryptsalsa208sha256_str(hashed_password, passwd, get_size(passwd), opslimit, memlimit).zero?
65
+ if crypto_pwhash_scryptsalsa208sha256_str(hashed_password, passwd, get_size(passwd), opslimit, memlimit) == 0
66
+ hashed_password.get_string(0)
67
+ else
81
68
  raise NoMemoryError, "Failed to allocate memory max size=#{memlimit} bytes", caller
82
69
  end
83
-
84
- hashed_password.get_string(0)
85
70
  end
86
71
 
87
72
  def str_verify(str, passwd)
88
73
  check_length(str, STRBYTES - 1, :Str)
89
- crypto_pwhash_scryptsalsa208sha256_str_verify(str, passwd, get_size(passwd)).zero?
74
+ crypto_pwhash_scryptsalsa208sha256_str_verify(str, passwd, get_size(passwd)) == 0
90
75
  end
91
76
  end
92
77
 
78
+ ScryptSalsa208SHA256.freeze
79
+
93
80
  module_function
94
81
 
95
82
  def scryptsalsa208sha256(*args)
96
83
  ScryptSalsa208SHA256.scryptsalsa208sha256(*args)
97
84
  end
98
85
  end
86
+
87
+ PwHash.freeze
99
88
  end
@@ -27,7 +27,6 @@ module Crypto
27
27
  check_length(secret_key, SCALARBYTES, :SecretKey)
28
28
 
29
29
  public_key = Sodium::Buffer.new(:uchar, BYTES)
30
- public_key.primitive = PRIMITIVE
31
30
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
32
31
  crypto_scalarmult_base(public_key, secret_key)
33
32
 
@@ -40,7 +39,7 @@ module Crypto
40
39
  check_length(secret_key, SCALARBYTES, :SecretKey)
41
40
  check_length(public_key, BYTES, :PublicKey)
42
41
 
43
- shared_secret = Sodium::SecretBuffer.new(BYTES, PRIMITIVE)
42
+ shared_secret = Sodium::SecretBuffer.new(BYTES)
44
43
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
45
44
  crypto_scalarmult(shared_secret, secret_key, public_key)
46
45
  shared_secret.noaccess
@@ -51,6 +50,8 @@ module Crypto
51
50
  end
52
51
  end
53
52
 
53
+ ScalarMult.freeze
54
+
54
55
  module_function
55
56
 
56
57
  def scalarmut(*args)
@@ -37,7 +37,6 @@ module Crypto
37
37
  check_length(key, KEYBYTES, :SecretKey)
38
38
 
39
39
  ciphertext = Sodium::Buffer.new(:uchar, message_len + MACBYTES)
40
- ciphertext.primitive = PRIMITIVE
41
40
  key.readonly if key.is_a?(Sodium::SecretBuffer)
42
41
  crypto_secretbox_easy(ciphertext, message, message_len, nonce, key)
43
42
 
@@ -53,22 +52,21 @@ module Crypto
53
52
 
54
53
  decrypted = Sodium::Buffer.new(:uchar, ciphertext_len - MACBYTES)
55
54
  key.readonly if key.is_a?(Sodium::SecretBuffer)
56
-
57
- unless crypto_secretbox_open_easy(decrypted, ciphertext, ciphertext_len, nonce, key).zero?
55
+ if crypto_secretbox_open_easy(decrypted, ciphertext, ciphertext_len, nonce, key) == 0
56
+ decrypted
57
+ else
58
58
  raise Sodium::CryptoError, "Message forged", caller
59
59
  end
60
-
61
- decrypted
62
60
  ensure
63
61
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
64
62
  end
65
63
 
66
64
  def easy_in_place(data, nonce, key)
67
- message = get_string(data)
65
+ message = String(data)
68
66
  check_length(nonce, NONCEBYTES, :Nonce)
69
67
  check_length(key, KEYBYTES, :SecretKey)
70
68
 
71
- message_len = get_size(message)
69
+ message_len = message.bytesize
72
70
  message << zeros(MACBYTES)
73
71
  key.readonly if key.is_a?(Sodium::SecretBuffer)
74
72
  crypto_secretbox_easy(message, message, message_len, nonce, key)
@@ -78,32 +76,35 @@ module Crypto
78
76
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
79
77
  end
80
78
 
81
- def open_easy_in_place(data, nonce, key, utf8 = false)
82
- ciphertext = get_string(data)
83
- unless (message_len = get_size(ciphertext) - MACBYTES) > 0
84
- fail Sodium::LengthError, "Ciphertext is too short", caller
85
- end
86
-
87
- check_length(nonce, NONCEBYTES, :Nonce)
88
- check_length(key, KEYBYTES, :SecretKey)
89
-
90
- key.readonly if key.is_a?(Sodium::SecretBuffer)
91
- unless crypto_secretbox_open_easy(ciphertext, ciphertext, get_size(ciphertext), nonce, key).zero?
92
- raise Sodium::CryptoError, "Message forged", caller
93
- end
94
-
95
- if utf8
96
- ciphertext.slice!(message_len..-1).force_encoding(Encoding::UTF_8)
79
+ def open_easy_in_place(data, nonce, key, encoding = false)
80
+ ciphertext = String(data)
81
+ ciphertext_len = ciphertext.bytesize
82
+ if (message_len = ciphertext_len - MACBYTES) > 0
83
+ check_length(nonce, NONCEBYTES, :Nonce)
84
+ check_length(key, KEYBYTES, :SecretKey)
85
+
86
+ key.readonly if key.is_a?(Sodium::SecretBuffer)
87
+ if crypto_secretbox_open_easy(ciphertext, ciphertext, ciphertext_len, nonce, key) == 0
88
+ if encoding
89
+ ciphertext.slice!(message_len..-1).force_encoding(encoding)
90
+ else
91
+ ciphertext.slice!(message_len..-1)
92
+ end
93
+
94
+ ciphertext
95
+ else
96
+ raise Sodium::CryptoError, "Message forged", caller
97
+ end
97
98
  else
98
- ciphertext.slice!(message_len..-1)
99
+ fail Sodium::LengthError, "Ciphertext is too short", caller
99
100
  end
100
-
101
- ciphertext
102
101
  ensure
103
102
  key.noaccess if key.is_a?(Sodium::SecretBuffer)
104
103
  end
105
104
  end
106
105
 
106
+ SecretBox.freeze
107
+
107
108
  module_function
108
109
 
109
110
  def secretbox(*args)
@@ -26,7 +26,6 @@ module Crypto
26
26
  check_length(key, KEYBYTES, :SecretKey)
27
27
 
28
28
  siphash = Sodium::Buffer.new(:uchar, BYTES)
29
- siphash.primitive = PRIMITIVE
30
29
  key.readonly if key.is_a?(Sodium::SecretBuffer)
31
30
  crypto_shorthash(siphash, short_data, get_size(short_data), key)
32
31
 
@@ -36,6 +35,8 @@ module Crypto
36
35
  end
37
36
  end
38
37
 
38
+ ShortHash.freeze
39
+
39
40
  module_function
40
41
 
41
42
  def shorthash(*args)
data/lib/crypto/sign.rb CHANGED
@@ -33,9 +33,7 @@ module Crypto
33
33
 
34
34
  def keypair
35
35
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
36
- public_key.primitive = PRIMITIVE
37
36
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
38
- secret_key.primitive = PRIMITIVE
39
37
  crypto_sign_keypair(public_key, secret_key)
40
38
 
41
39
  [public_key, secret_key]
@@ -45,9 +43,7 @@ module Crypto
45
43
  check_length(seed, SEEDBYTES, :Seed)
46
44
 
47
45
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
48
- public_key.primitive = PRIMITIVE
49
46
  secret_key = Sodium::Buffer.new(:uchar, SECRETKEYBYTES)
50
- secret_key.primitive = PRIMITIVE
51
47
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
52
48
  crypto_sign_seed_keypair(public_key, secret_key, seed)
53
49
 
@@ -58,8 +54,7 @@ module Crypto
58
54
 
59
55
  def memory_locked_keypair
60
56
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
61
- public_key.primitive = PRIMITIVE
62
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
57
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
63
58
  crypto_sign_keypair(public_key, secret_key)
64
59
  secret_key.noaccess
65
60
 
@@ -70,8 +65,7 @@ module Crypto
70
65
  check_length(seed, SEEDBYTES, :Seed)
71
66
 
72
67
  public_key = Sodium::Buffer.new(:uchar, PUBLICKEYBYTES)
73
- public_key.primitive = PRIMITIVE
74
- secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES, PRIMITIVE)
68
+ secret_key = Sodium::SecretBuffer.new(SECRETKEYBYTES)
75
69
  seed.readonly if seed.is_a?(Sodium::SecretBuffer)
76
70
  crypto_sign_seed_keypair(public_key, secret_key, seed)
77
71
  secret_key.noaccess
@@ -86,7 +80,6 @@ module Crypto
86
80
  check_length(secret_key, SECRETKEYBYTES, :SecretKey)
87
81
 
88
82
  sealed_message = Sodium::Buffer.new(:uchar, message_len + BYTES)
89
- sealed_message.primitive = PRIMITIVE
90
83
  secret_key.readonly if secret_key.is_a?(Sodium::SecretBuffer)
91
84
  crypto_sign(sealed_message, nil, message, message_len, secret_key)
92
85
 
@@ -100,15 +93,17 @@ module Crypto
100
93
  check_length(public_key, PUBLICKEYBYTES, :PublicKey)
101
94
 
102
95
  unsealed_message = Sodium::Buffer.new(:uchar, sealed_message_len - BYTES)
103
- unsealed_message_len = FFI::MemoryPointer.new(:pointer)
104
- unless crypto_sign_open(unsealed_message, unsealed_message_len, sealed_message, sealed_message_len, public_key).zero?
96
+ unsealed_message_len = FFI::MemoryPointer.new(:ulong_long)
97
+ if crypto_sign_open(unsealed_message, unsealed_message_len, sealed_message, sealed_message_len, public_key) == 0
98
+ unsealed_message
99
+ else
105
100
  raise Sodium::CryptoError, "Incorrect signature", caller
106
101
  end
107
-
108
- unsealed_message
109
102
  end
110
103
  end
111
104
 
105
+ Sign.freeze
106
+
112
107
  module_function
113
108
 
114
109
  def sign(*args)
@@ -54,5 +54,7 @@ module Crypto
54
54
  secret_key.noaccess if secret_key.is_a?(Sodium::SecretBuffer)
55
55
  end
56
56
  end
57
+
58
+ Ed25519.freeze
57
59
  end
58
60
  end
data/lib/libsodium.rb CHANGED
@@ -2,19 +2,22 @@
2
2
  require_relative 'sodium'
3
3
  require_relative 'sodium/utils'
4
4
  require_relative 'sodium/buffer'
5
+ require_relative 'sodium/mprotect'
5
6
  require_relative 'sodium/secret_buffer'
7
+ Sodium.freeze
6
8
  require_relative 'random_bytes'
7
9
  require_relative 'crypto/secret_box'
8
10
  require_relative 'crypto/auth'
9
11
  require_relative 'crypto/aead/chacha20_poly1305'
10
12
  require_relative 'crypto/box'
13
+ require_relative 'crypto/sign/ed25519'
11
14
  require_relative 'crypto/sign'
12
15
  require_relative 'crypto/generic_hash'
13
16
  require_relative 'crypto/short_hash'
14
17
  require_relative 'crypto/pw_hash/scrypt_salsa208_sha256'
15
18
  require_relative 'crypto/one_time_auth'
16
19
  require_relative 'crypto/scalar_mult'
17
- require_relative 'crypto/sign/ed25519'
20
+ Crypto.freeze
18
21
 
19
22
  Thread.exclusive do
20
23
  if Sodium.init == -1
data/lib/random_bytes.rb CHANGED
@@ -20,3 +20,5 @@ module RandomBytes
20
20
  buf
21
21
  end
22
22
  end
23
+
24
+ RandomBytes.freeze
data/lib/sodium.rb CHANGED
@@ -16,53 +16,22 @@ module Sodium
16
16
  attach_function :sodium_munlock, [:pointer, :size_t], :int
17
17
  attach_function :sodium_malloc, [:size_t], :pointer
18
18
  attach_function :sodium_allocarray, [:size_t, :size_t], :pointer
19
- attach_function :sodium_mprotect_noaccess, [:pointer], :int
20
- attach_function :sodium_mprotect_readonly, [:pointer], :int
21
- attach_function :sodium_mprotect_readwrite, [:pointer], :int
22
19
 
23
20
  module_function
24
21
 
25
22
  def mlock(addr, len)
26
- unless sodium_mlock(addr, len).zero?
27
- raise MemoryError, "Could not lock length=#{len} bytes memory at address=#{addr.address}", caller
28
- end
23
+ sodium_mlock(addr, len) == 0 || raise(MemoryError, "Could not lock length=#{len} bytes memory at address=#{addr.address}", caller)
29
24
  end
30
25
 
31
26
  def munlock(addr, len)
32
- unless sodium_munlock(addr, len).zero?
33
- raise MemoryError, "Could not unlock length=#{len} bytes memory at address=#{addr.address}", caller
34
- end
27
+ sodium_munlock(addr, len) == 0 || raise(MemoryError, "Could not unlock length=#{len} bytes memory at address=#{addr.address}", caller)
35
28
  end
36
29
 
37
30
  def malloc(size)
38
- unless (mem = sodium_malloc(size))
39
- raise NoMemoryError, "Failed to allocate memory size=#{size} bytes", caller
40
- end
41
- mem
31
+ sodium_malloc(size) || raise(NoMemoryError, "Failed to allocate memory size=#{size} bytes", caller)
42
32
  end
43
33
 
44
34
  def allocarray(count, size)
45
- unless (mem = sodium_allocarray(count, size))
46
- raise NoMemoryError, "Failed to allocate memory size=#{count * size} bytes", caller
47
- end
48
- mem
49
- end
50
-
51
- def noaccess(ptr)
52
- unless sodium_mprotect_noaccess(ptr).zero?
53
- raise MemoryError, "Memory at address=#{ptr.address} is not secured with #{self}.malloc", caller
54
- end
55
- end
56
-
57
- def readonly(ptr)
58
- unless sodium_mprotect_readonly(ptr).zero?
59
- raise MemoryError, "Memory at address=#{ptr.address} is not secured with #{self}.malloc", caller
60
- end
61
- end
62
-
63
- def readwrite(ptr)
64
- unless sodium_mprotect_readwrite(ptr).zero?
65
- raise MemoryError, "Memory at address=#{ptr.address} is not secured with #{self}.malloc", caller
66
- end
35
+ sodium_allocarray(count, size) || raise(NoMemoryError, "Failed to allocate memory size=#{count * size} bytes", caller)
67
36
  end
68
37
  end
data/lib/sodium/buffer.rb CHANGED
@@ -2,12 +2,10 @@
2
2
 
3
3
  module Sodium
4
4
  class Buffer < FFI::MemoryPointer
5
- attr_accessor :primitive
6
-
7
- def to_bytes
5
+ def to_str
8
6
  read_bytes(size)
9
7
  end
10
-
11
- alias_method :to_str, :to_bytes
12
8
  end
9
+
10
+ Buffer.freeze
13
11
  end
data/lib/sodium/errors.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Sodium
2
- class CryptoError < StandardError; end
3
- class LengthError < ArgumentError; end
4
- class MemoryError < StandardError; end
2
+ CryptoError = Class.new(StandardError).freeze
3
+ LengthError = Class.new(ArgumentError).freeze
4
+ MemoryError = Class.new(StandardError).freeze
5
5
  end
@@ -0,0 +1,30 @@
1
+ require 'ffi'
2
+ require_relative 'errors'
3
+ require_relative 'utils'
4
+
5
+ module Sodium
6
+ module Mprotect
7
+ extend FFI::Library
8
+ ffi_lib :libsodium
9
+
10
+ attach_function :sodium_mprotect_noaccess, [:pointer], :int
11
+ attach_function :sodium_mprotect_readonly, [:pointer], :int
12
+ attach_function :sodium_mprotect_readwrite, [:pointer], :int
13
+
14
+ module_function
15
+
16
+ def noaccess(ptr)
17
+ sodium_mprotect_noaccess(ptr) == 0 || raise(MemoryError, "Memory at address=#{ptr.address} is not secured with Sodium.malloc", caller)
18
+ end
19
+
20
+ def readonly(ptr)
21
+ sodium_mprotect_readonly(ptr) == 0 || raise(MemoryError, "Memory at address=#{ptr.address} is not secured with Sodium.malloc", caller)
22
+ end
23
+
24
+ def readwrite(ptr)
25
+ sodium_mprotect_readwrite(ptr) == 0 || raise(MemoryError, "Memory at address=#{ptr.address} is not secured with Sodium.malloc", caller)
26
+ end
27
+ end
28
+
29
+ Mprotect.freeze
30
+ end
@@ -1,58 +1,61 @@
1
1
  require 'forwardable'
2
- require_relative 'utils'
3
2
  require_relative '../sodium'
3
+ require_relative 'mprotect'
4
4
  require 'ffi'
5
5
 
6
6
  module Sodium
7
7
  class SecretBuffer
8
8
  extend Forwardable
9
9
 
10
- attr_reader :size, :primitive, :to_ptr
11
- def_delegators :to_ptr, :address, :to_i
10
+ attr_reader :size, :to_ptr
11
+ def_delegators :@to_ptr, :address, :to_i
12
12
 
13
- def initialize(size, primitive = nil)
14
- @size = Utils.get_int(size)
15
- @primitive = primitive
16
- @to_ptr = Sodium.malloc(self.size)
13
+ def initialize(size)
14
+ @size = Integer(size)
15
+ @to_ptr = Sodium.malloc(@size)
17
16
  setup_finalizer
18
17
  end
19
18
 
20
19
  def free
21
20
  remove_finalizer
22
- readwrite
23
- Sodium.free(to_ptr)
24
- @size = @primitive = @to_ptr = nil
21
+ Sodium::Mprotect.readonly(@to_ptr)
22
+ Sodium.free(@to_ptr)
23
+ remove_instance_variable(:@size)
24
+ remove_instance_variable(:@to_ptr)
25
+ true
25
26
  end
26
27
 
27
28
  def noaccess
28
- Sodium.noaccess(to_ptr)
29
+ Sodium::Mprotect.noaccess(@to_ptr)
29
30
  end
30
31
 
31
32
  def readonly
32
- Sodium.readonly(to_ptr)
33
+ Sodium::Mprotect.readonly(@to_ptr)
33
34
  end
34
35
 
35
36
  def readwrite
36
- Sodium.readwrite(to_ptr)
37
+ Sodium::Mprotect.readwrite(@to_ptr)
37
38
  end
38
39
 
39
40
  private
40
41
 
41
42
  def setup_finalizer
42
- ObjectSpace.define_finalizer(to_ptr, self.class.free(to_ptr.address))
43
+ ObjectSpace.define_finalizer(@to_ptr, self.class.free(@to_ptr.address))
43
44
  end
44
45
 
45
46
  def remove_finalizer
46
- ObjectSpace.undefine_finalizer to_ptr
47
+ ObjectSpace.undefine_finalizer @to_ptr
47
48
  end
48
49
 
49
50
  def self.free(address)
50
51
  ->(obj_id) do
51
52
  ptr = FFI::Pointer.new(address)
52
- Sodium.readwrite(ptr)
53
+ Sodium::Mprotect.readonly(ptr)
53
54
  Sodium.free(ptr)
54
55
  true
55
56
  end
56
57
  end
57
58
  end
59
+
60
+ SecretBuffer.freeze
58
61
  end
data/lib/sodium/utils.rb CHANGED
@@ -1,68 +1,41 @@
1
- require_relative 'errors'
2
- require 'ffi'
1
+ require 'ffi'
2
+ require_relative 'secret_buffer'
3
+ require_relative 'errors'
3
4
 
4
5
  module Sodium
5
6
  module Utils
6
7
 
7
8
  module_function
8
9
 
9
- def check_length(data, length, description)
10
- if data.is_a?(String) ||data.respond_to?(:bytesize)
11
- unless data.bytesize == length
12
- fail Sodium::LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.bytesize} bytes", caller
13
- end
14
- elsif data.is_a?(FFI::Pointer) ||data.respond_to?(:size)
15
- unless data.size == length
16
- fail Sodium::LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.size} bytes", caller
17
- end
18
- else
19
- fail ArgumentError, "#{description} must be of type String or FFI::Pointer and be length=#{length} bytes long", caller
20
- end
21
-
22
- true
23
- end
24
-
25
- def get_pointer(ptr)
26
- if ptr.is_a?(FFI::Pointer)
27
- ptr
28
- elsif ptr.respond_to?(:to_ptr)
29
- ptr.to_ptr
30
- else
31
- fail ArgumentError, "#{ptr.class} is not a FFI::Pointer", caller
32
- end
33
- end
34
-
35
- def get_string(string)
36
- if string.is_a?(String)
37
- string
38
- elsif string.respond_to?(:to_str)
39
- string.to_str
40
- elsif string.respond_to?(:get_string)
41
- string.get_string(0)
42
- else
43
- fail ArgumentError, "#{string.class} is not a String", caller
44
- end
45
- end
46
-
47
- def get_int(int)
48
- if int.is_a?(Fixnum)
49
- int
50
- elsif int.respond_to?(:to_int)
51
- int.to_int
10
+ def get_size(data)
11
+ case data
12
+ when FFI::Pointer, SecretBuffer
13
+ data.size
14
+ when String
15
+ data.bytesize
16
+ when NilClass
17
+ 0
52
18
  else
53
- fail ArgumentError, "#{int.class} is not a Integer", caller
19
+ fail TypeError, "#{data.class} must be of type FFI::Pointer, Sodium::SecretBufffer, String or NilClass", caller
54
20
  end
55
21
  end
56
22
 
57
- def get_size(data)
58
- if data.is_a?(String) ||data.respond_to?(:bytesize)
59
- data.bytesize
60
- elsif data.is_a?(FFI::Pointer) ||data.respond_to?(:size)
61
- data.size
62
- elsif data.nil?
63
- 0
23
+ def check_length(data, length, description)
24
+ case data
25
+ when FFI::Pointer, SecretBuffer
26
+ if data.size == length
27
+ true
28
+ else
29
+ fail LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.size} bytes", caller
30
+ end
31
+ when String
32
+ if data.bytesize == length
33
+ true
34
+ else
35
+ fail LengthError, "Expected a length=#{length} bytes #{description}, got size=#{data.bytesize} bytes", caller
36
+ end
64
37
  else
65
- fail ArgumentError, "#{data.class} doesn't respond to :bytesize or :size", caller
38
+ fail TypeError, "#{data.class} must be of type FFI::Pointer, Sodium::SecretBufffer or String", caller
66
39
  end
67
40
  end
68
41
 
@@ -82,4 +55,6 @@ module Sodium
82
55
  [hex].pack(HEXY)
83
56
  end
84
57
  end
58
+
59
+ Utils.freeze
85
60
  end
@@ -1,3 +1,3 @@
1
1
  module Sodium
2
- VERSION = Gem::Version.new('0.1.10')
2
+ VERSION = Gem::Version.new('0.2.0')
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ffi-libsodium
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.10
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Hendrik Beskow
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-11 00:00:00.000000000 Z
11
+ date: 2014-12-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ffi
@@ -62,6 +62,7 @@ files:
62
62
  - lib/sodium.rb
63
63
  - lib/sodium/buffer.rb
64
64
  - lib/sodium/errors.rb
65
+ - lib/sodium/mprotect.rb
65
66
  - lib/sodium/secret_buffer.rb
66
67
  - lib/sodium/utils.rb
67
68
  - lib/sodium/version.rb