sodium 0.6.2 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -5,5 +5,8 @@ module Sodium::FFI::LibC
5
5
 
6
6
  ffi_lib FFI::Library::LIBC
7
7
 
8
+ attach_function 'calloc', [:size_t, :size_t], :pointer
9
+ attach_function 'free', [:pointer], :void
10
+
8
11
  attach_function 'mlock', [:pointer, :size_t], :int
9
12
  end
@@ -8,9 +8,9 @@ class Sodium::Hash
8
8
 
9
9
  Sodium::Buffer.empty self.implementation[:BYTES] do |digest|
10
10
  self.implementation.nacl(
11
- digest.to_str,
12
- message.to_str,
13
- message.to_str.bytesize
11
+ digest .to_ptr,
12
+ message.to_ptr,
13
+ message.bytesize
14
14
  ) or raise Sodium::CryptoError, 'failed to generate a hash for the message'
15
15
  end
16
16
  end
@@ -16,10 +16,10 @@ class Sodium::OneTimeAuth
16
16
 
17
17
  Sodium::Buffer.empty self.implementation[:BYTES] do |authenticator|
18
18
  self.implementation.nacl(
19
- authenticator.to_str,
20
- message.to_str,
21
- message.to_str.bytesize,
22
- @key.to_str
19
+ authenticator.to_ptr,
20
+ message .to_ptr,
21
+ message .bytesize,
22
+ @key .to_ptr
23
23
  ) or raise Sodium::CryptoError, 'failed to generate an authenticator'
24
24
  end
25
25
  end
@@ -29,10 +29,10 @@ class Sodium::OneTimeAuth
29
29
  authenticator = self.class._authenticator(authenticator)
30
30
 
31
31
  self.implementation.nacl_verify(
32
- authenticator.to_str,
33
- message.to_str,
34
- message.to_str.bytesize,
35
- @key.to_str
32
+ authenticator.to_ptr,
33
+ message .to_ptr,
34
+ message .bytesize,
35
+ @key .to_ptr
36
36
  )
37
37
  end
38
38
 
@@ -4,7 +4,7 @@ module Sodium::Random
4
4
  def self.bytes(size)
5
5
  Sodium::Buffer.empty(size) do |buffer|
6
6
  Sodium::FFI::Random.randombytes_buf(
7
- buffer.to_str,
7
+ buffer.to_ptr,
8
8
  buffer.bytesize
9
9
  )
10
10
  end
@@ -21,11 +21,11 @@ class Sodium::SecretBox
21
21
 
22
22
  Sodium::Buffer.empty(message.bytesize) do |ciphertext|
23
23
  self.implementation.nacl(
24
- ciphertext.to_str,
25
- message.to_str,
26
- message.to_str.bytesize,
27
- nonce.to_str,
28
- @key.to_str
24
+ ciphertext .to_ptr,
25
+ message .to_ptr,
26
+ message .bytesize,
27
+ nonce .to_ptr,
28
+ @key .to_ptr
29
29
  ) or raise Sodium::CryptoError, 'failed to close the secret box'
30
30
  end.ldrop self.implementation[:BOXZEROBYTES]
31
31
  end
@@ -36,11 +36,11 @@ class Sodium::SecretBox
36
36
 
37
37
  Sodium::Buffer.empty(ciphertext.bytesize) do |message|
38
38
  self.implementation.nacl_open(
39
- message.to_str,
40
- ciphertext.to_str,
41
- ciphertext.to_str.bytesize,
42
- nonce.to_str,
43
- @key.to_str
39
+ message .to_ptr,
40
+ ciphertext .to_ptr,
41
+ ciphertext .bytesize,
42
+ nonce .to_ptr,
43
+ @key .to_ptr
44
44
  ) or raise Sodium::CryptoError, 'failed to open the secret box'
45
45
  end.ldrop self.implementation[:ZEROBYTES]
46
46
  end
@@ -8,8 +8,8 @@ class Sodium::Sign
8
8
  secret_key = Sodium::Buffer.empty self.implementation[:SECRETKEYBYTES]
9
9
 
10
10
  self.implementation.nacl_keypair(
11
- public_key.to_str,
12
- secret_key.to_str
11
+ public_key.to_ptr,
12
+ secret_key.to_ptr
13
13
  ) or raise Sodium::CryptoError, 'failed to generate a keypair'
14
14
 
15
15
  return secret_key, public_key
@@ -22,11 +22,11 @@ class Sodium::Sign
22
22
  mlen = FFI::MemoryPointer.new(:ulong_long, 1, true)
23
23
 
24
24
  self.implementation.nacl_open(
25
- message.to_str,
25
+ message .to_ptr,
26
26
  mlen,
27
- signature.to_str,
28
- signature.to_str.bytesize,
29
- key.to_str
27
+ signature .to_ptr,
28
+ signature .bytesize,
29
+ key .to_ptr
30
30
  )
31
31
  end
32
32
 
@@ -40,18 +40,18 @@ class Sodium::Sign
40
40
  slen = FFI::MemoryPointer.new(:ulong_long, 1, true)
41
41
 
42
42
  self.implementation.nacl(
43
- signature.to_str,
43
+ signature .to_ptr,
44
44
  slen,
45
- message.to_str,
46
- message.to_str.bytesize,
47
- @key.to_str
45
+ message .to_ptr,
46
+ message .bytesize,
47
+ @key .to_ptr
48
48
  ) or raise Sodium::CryptoError, 'failed to generate signature'
49
49
 
50
50
  # signatures actually encode the message itself at the end, so we
51
51
  # slice off only the signature bytes
52
52
  signature.byteslice(
53
53
  0,
54
- slen.read_ulong_long - message.to_str.bytesize
54
+ slen.read_ulong_long - message.bytesize
55
55
  )
56
56
  end
57
57
 
@@ -9,12 +9,18 @@ namespace :compile do
9
9
  desc 'Compile the memory extension'
10
10
  task :memory => %{#{LIB_PATH}/sodium/ffi/#{MEMORY_LIB}}
11
11
 
12
- file %{#{LIB_PATH}/sodium/ffi/#{MEMORY_LIB}} => %{#{MEMORY_PATH}/Makefile} do
12
+ file %{#{LIB_PATH}/sodium/ffi/#{MEMORY_LIB}} => FileList[MEMORY_SRC] do
13
+ Dir.chdir(MEMORY_PATH) { ruby %{extconf.rb} }
13
14
  sh %{make -C #{MEMORY_PATH} install sitearchdir="#{LIB_PATH}"}
14
15
  end
15
16
 
16
- file %{#{MEMORY_PATH}/Makefile} => FileList[MEMORY_SRC] do
17
- Dir.chdir(MEMORY_PATH) { ruby %{extconf.rb} }
17
+ task :clean do
18
+ sh %{make -C #{MEMORY_PATH} realclean} if
19
+ File.exist? %{#{MEMORY_PATH}/Makefile}
20
+ end
21
+
22
+ task :clobber do
23
+ CLOBBER.add %{#{LIB_PATH}/sodium/ffi/#{MEMORY_LIB}}
18
24
  end
19
25
  end
20
26
 
@@ -22,3 +28,6 @@ desc 'Compile all native extensions'
22
28
  task :compile => %w{ compile:memory }
23
29
 
24
30
  task :test => %w{ compile }
31
+
32
+ task :clean => :'compile:clean'
33
+ task :clobber => :'compile:clobber'
@@ -36,11 +36,11 @@ describe Sodium::Auth::HMACSHA256 do
36
36
  self.klass.auth(
37
37
  self.key,
38
38
  self.plaintext
39
- ).to_str.must_equal self.authenticator
39
+ ).to_s.must_equal self.authenticator
40
40
 
41
41
  self.subject.auth(
42
42
  self.plaintext
43
- ).to_str.must_equal self.authenticator
43
+ ).to_s.must_equal self.authenticator
44
44
  end
45
45
 
46
46
  it 'must verify authenticators' do
@@ -35,11 +35,11 @@ describe Sodium::Auth::HMACSHA512256 do
35
35
  self.klass.auth(
36
36
  self.key,
37
37
  self.plaintext
38
- ).to_str.must_equal self.authenticator
38
+ ).to_s.must_equal self.authenticator
39
39
 
40
40
  self.subject.auth(
41
41
  self.plaintext
42
- ).to_str.must_equal self.authenticator
42
+ ).to_s.must_equal self.authenticator
43
43
  end
44
44
 
45
45
  it 'must verify authenticators' do
@@ -26,12 +26,12 @@ describe Sodium::Auth do
26
26
  sodium_mock_default(self.klass) do |klass, mock|
27
27
  mock.expect :[], 0, [:KEYBYTES]
28
28
 
29
- klass.key.to_str.must_equal ''
29
+ klass.key.to_s.must_equal ''
30
30
  end
31
31
  end
32
32
 
33
33
  it 'must raise when instantiating with an invalid key' do
34
- lambda { self.klass.new(self.key.to_str[0..-2]) }.
34
+ lambda { self.klass.new(self.key.to_s[0..-2]) }.
35
35
  must_raise Sodium::LengthError
36
36
  end
37
37
 
@@ -47,18 +47,18 @@ describe Sodium::Box::Curve25519XSalsa20Poly1305 do
47
47
  self.subject.box(
48
48
  self.plaintext,
49
49
  self.nonce
50
- ).to_str.must_equal self.ciphertext
50
+ ).to_s.must_equal self.ciphertext
51
51
  end
52
52
 
53
53
  it 'must open boxes' do
54
54
  self.subject.open(
55
55
  self.ciphertext,
56
56
  self.nonce
57
- ).to_str.must_equal self.plaintext
57
+ ).to_s.must_equal self.plaintext
58
58
  end
59
59
 
60
60
  it 'must generate shared keys' do
61
- self.subject.beforenm.to_str.must_equal self.shared_key
61
+ self.subject.beforenm.to_s.must_equal self.shared_key
62
62
  end
63
63
 
64
64
  it 'must generate closed boxes with shared keys' do
@@ -66,7 +66,7 @@ describe Sodium::Box::Curve25519XSalsa20Poly1305 do
66
66
  self.shared_key,
67
67
  self.plaintext,
68
68
  self.nonce
69
- ).to_str.must_equal self.ciphertext
69
+ ).to_s.must_equal self.ciphertext
70
70
  end
71
71
 
72
72
  it 'must open boxes with shared keys' do
@@ -74,6 +74,6 @@ describe Sodium::Box::Curve25519XSalsa20Poly1305 do
74
74
  self.shared_key,
75
75
  self.ciphertext,
76
76
  self.nonce
77
- ).to_str.must_equal self.plaintext
77
+ ).to_s.must_equal self.plaintext
78
78
  end
79
79
  end
@@ -24,29 +24,29 @@ describe Sodium::Box do
24
24
 
25
25
  it 'must mint keypairs from the default implementation' do
26
26
  sodium_mock_default(self.klass) do |klass, mock|
27
- mock.expect :nacl_keypair, true, [ '', '' ]
27
+ mock.expect :nacl_keypair, true, [ FFI::Pointer, FFI::Pointer ]
28
28
  mock.expect :[], 0, [:PUBLICKEYBYTES]
29
29
  mock.expect :[], 0, [:SECRETKEYBYTES]
30
30
 
31
31
  sk, pk = klass.keypair
32
32
 
33
- sk.to_str.must_equal ''
34
- pk.to_str.must_equal ''
33
+ sk.to_s.must_equal ''
34
+ pk.to_s.must_equal ''
35
35
  end
36
36
  end
37
37
 
38
38
  it 'must raise when instantiating with an invalid keypair' do
39
39
  secret_key, public_key = self.keypair
40
40
 
41
- lambda { self.klass.new(secret_key.to_str[0..-2], public_key) }.
41
+ lambda { self.klass.new(secret_key.to_s[0..-2], public_key) }.
42
42
  must_raise Sodium::LengthError
43
43
 
44
- lambda { self.klass.new(secret_key, public_key.to_str[0..-2]) }.
44
+ lambda { self.klass.new(secret_key, public_key.to_s[0..-2]) }.
45
45
  must_raise Sodium::LengthError
46
46
  end
47
47
 
48
48
  it 'must raise when receiving an invalid nonce' do
49
- lambda { self.subject.box('message', self.subject.nonce.to_str[0..-2]) }.
49
+ lambda { self.subject.box('message', self.subject.nonce.to_s[0..-2]) }.
50
50
  must_raise Sodium::LengthError
51
51
  end
52
52
 
@@ -3,29 +3,35 @@ require 'test_helper'
3
3
  describe Sodium::Buffer do
4
4
  subject { Sodium::Buffer }
5
5
 
6
+ def trigger_gc!
7
+ GC.start
8
+ 1_000_000.times { Object.new }
9
+ GC.start
10
+ end
11
+
6
12
  it '::key must securely generate random keys of specified length' do
7
13
  Sodium::Random.stub(:bytes, lambda {|l| ' ' * l }) do
8
- subject.key( 7).to_str.must_equal(' ' * 7)
9
- subject.key( 8).to_str.must_equal(' ' * 8)
10
- subject.key(16).to_str.must_equal(' ' * 16)
11
- subject.key(32).to_str.must_equal(' ' * 32)
12
- subject.key(64).to_str.must_equal(' ' * 64)
14
+ subject.key( 7).to_s.must_equal(' ' * 7)
15
+ subject.key( 8).to_s.must_equal(' ' * 8)
16
+ subject.key(16).to_s.must_equal(' ' * 16)
17
+ subject.key(32).to_s.must_equal(' ' * 32)
18
+ subject.key(64).to_s.must_equal(' ' * 64)
13
19
  end
14
20
  end
15
21
 
16
22
  it '::nonce must securely generate random nonces of specified length' do
17
23
  Sodium::Random.stub(:bytes, lambda {|l| ' ' * l }) do
18
- subject.nonce( 7).to_str.must_equal(' ' * 7)
19
- subject.nonce( 8).to_str.must_equal(' ' * 8)
20
- subject.nonce(16).to_str.must_equal(' ' * 16)
21
- subject.nonce(32).to_str.must_equal(' ' * 32)
22
- subject.nonce(64).to_str.must_equal(' ' * 64)
24
+ subject.nonce( 7).to_s.must_equal(' ' * 7)
25
+ subject.nonce( 8).to_s.must_equal(' ' * 8)
26
+ subject.nonce(16).to_s.must_equal(' ' * 16)
27
+ subject.nonce(32).to_s.must_equal(' ' * 32)
28
+ subject.nonce(64).to_s.must_equal(' ' * 64)
23
29
  end
24
30
  end
25
31
 
26
32
  it '::empty must generate an empty buffer of specified length' do
27
- subject.empty(32).to_str.must_equal("\0" * 32)
28
- subject.empty(40).to_str.must_equal("\0" * 40)
33
+ subject.empty(32).to_s.must_equal("\0" * 32)
34
+ subject.empty(40).to_s.must_equal("\0" * 40)
29
35
  end
30
36
 
31
37
  it '::empty must yield to a block when given' do
@@ -38,43 +44,44 @@ describe Sodium::Buffer do
38
44
  end
39
45
 
40
46
  it '::ljust must pad zero bytes on the end' do
41
- subject.ljust('xyz', 5).to_str.must_equal "xyz\0\0"
47
+ subject.ljust('xyz', 5).to_s.must_equal "xyz\0\0"
42
48
  end
43
49
 
44
50
  it '::ljust must not pad bytes when not needed' do
45
- subject.ljust('xyz', 2).to_str.must_equal 'xyz'
51
+ subject.ljust('xyz', 2).to_s.must_equal 'xyz'
46
52
  end
47
53
 
48
54
  it '::rjust must pad zero bytes onto the front' do
49
- subject.rjust('xyz', 5).to_str.must_equal "\0\0xyz"
55
+ subject.rjust('xyz', 5).to_s.must_equal "\0\0xyz"
50
56
  end
51
57
 
52
58
  it '::rjust must not pad bytes when not needed' do
53
- subject.rjust('xyz', 2).to_str.must_equal 'xyz'
59
+ subject.rjust('xyz', 2).to_s.must_equal 'xyz'
54
60
  end
55
61
 
56
62
  it '::lpad must prepend the required number of bytes' do
57
- subject.lpad('xyz', 0).to_str.must_equal 'xyz'
58
- subject.lpad('xyz', 2).to_str.must_equal "\0\0xyz"
63
+ subject.lpad('xyz', 0).to_s.must_equal 'xyz'
64
+ subject.lpad('xyz', 2).to_s.must_equal "\0\0xyz"
59
65
  end
60
66
 
61
67
  it '::rpad must append the required number of bytes' do
62
- subject.rpad('xyz', 0).to_str.must_equal 'xyz'
63
- subject.rpad('xyz', 2).to_str.must_equal "xyz\0\0"
68
+ subject.rpad('xyz', 0).to_s.must_equal 'xyz'
69
+ subject.rpad('xyz', 2).to_s.must_equal "xyz\0\0"
64
70
  end
65
71
 
66
72
  it '::new must create a buffer containing the specified string' do
67
- subject.new('xyz' ).to_str.must_equal('xyz')
68
- subject.new('xyz' * 50).to_str.must_equal('xyz' * 50)
73
+ subject.new('xyz' ).to_s.must_equal('xyz')
74
+ subject.new('xyz' * 50).to_s.must_equal('xyz' * 50)
69
75
  end
70
76
 
71
77
  it '::new must do optional length checking' do
72
- lambda { subject.new('xyz', 4).to_str }.
78
+ lambda { subject.new('xyz', 4).to_s }.
73
79
  must_raise Sodium::LengthError
74
80
  end
75
81
 
76
82
  it '#initialize must freeze its bytes' do
77
- subject.new('s').to_str.must_be :frozen?
83
+ subject.new('s').to_ptr.must_be :frozen?
84
+ subject.new('s').to_s .must_be :frozen?
78
85
  end
79
86
 
80
87
  it '#initialize must wipe the memory from the original string' do
@@ -87,27 +94,27 @@ describe Sodium::Buffer do
87
94
  it '#initialize must prevent the string from being paged to disk'
88
95
 
89
96
  it '#== must compare equality of two buffers' do
90
- subject.new('xyz').==('xyz') .must_equal true
91
- subject.new('xyz').==('xy') .must_equal false
92
- subject.new('xyz').==('xyzz').must_equal false
93
- subject.new('xyz').==('abc') .must_equal false
97
+ subject.new('xyz').must_be :==, 'xyz'
98
+ subject.new('xyz').wont_be :==, 'xy'
99
+ subject.new('xyz').wont_be :==, 'xyzz'
100
+ subject.new('xyz').wont_be :==, 'abc'
94
101
  end
95
102
 
96
103
  it '#== must compare equality of two buffers in constant time'
97
104
 
98
105
  it '#+ must append two buffers' do
99
- subject.new('xyz').+('abc').to_str.must_equal 'xyzabc'
106
+ subject.new('xyz').+('abc').to_s.must_equal 'xyzabc'
100
107
  end
101
108
 
102
109
  it '#^ must XOR two buffers' do
103
- subject.new('xyz').^('xyz').to_str.must_equal "\0\0\0"
104
- subject.new('xyz').^('xyz').to_str.must_equal "\0\0\0"
110
+ subject.new('xyz').^('xyz').to_s.must_equal "\0\0\0"
111
+ subject.new('xyz').^('xyz').to_s.must_equal "\0\0\0"
105
112
  end
106
113
 
107
114
  it '#[]= must allow replacement of byte ranges' do
108
- subject.new('xyz').tap {|b| b[0, 3] = 'abc' }.to_str.must_equal 'abc'
109
- subject.new('xyz').tap {|b| b[0, 2] = 'ab' }.to_str.must_equal 'abz'
110
- subject.new('xyz').tap {|b| b[2, 1] = 'c' }.to_str.must_equal 'xyc'
115
+ subject.new('xyz').tap {|b| b[0, 3] = 'abc' }.to_s.must_equal 'abc'
116
+ subject.new('xyz').tap {|b| b[0, 2] = 'ab' }.to_s.must_equal 'abz'
117
+ subject.new('xyz').tap {|b| b[2, 1] = 'c' }.to_s.must_equal 'xyc'
111
118
  end
112
119
 
113
120
  it '#[]= must not allow resizing the buffer' do
@@ -117,61 +124,61 @@ describe Sodium::Buffer do
117
124
  lambda { subject.new('xyz')[2, 2] = 'ab' }.must_raise ArgumentError
118
125
  end
119
126
 
120
- it '#[] must accept an indivdual byte offset to return' do
121
- subject.new('xyz').tap do |buffer|
122
- buffer[-4].to_str.must_equal ''
123
- buffer[-3].to_str.must_equal 'x'
124
- buffer[-2].to_str.must_equal 'y'
125
- buffer[-1].to_str.must_equal 'z'
126
- buffer[ 0].to_str.must_equal 'x'
127
- buffer[ 1].to_str.must_equal 'y'
128
- buffer[ 2].to_str.must_equal 'z'
129
- buffer[ 3].to_str.must_equal ''
130
- end
131
- end
132
-
133
- it '#[] must accept ranges of bytes to return' do
134
- subject.new('xyz').tap do |buffer|
135
- buffer[ 0.. 0].to_str.must_equal 'x'
136
- buffer[ 0.. 1].to_str.must_equal 'xy'
137
- buffer[ 0.. 2].to_str.must_equal 'xyz'
138
- buffer[ 0.. 3].to_str.must_equal 'xyz'
139
- buffer[ 1..-1].to_str.must_equal 'yz'
140
- buffer[ 2..-2].to_str.must_equal ''
141
- buffer[-3..-1].to_str.must_equal 'xyz'
142
- buffer[-4.. 1].to_str.must_equal ''
143
- end
144
- end
145
-
146
127
  it '#[] must accept an offset and number of bytes to return' do
147
128
  subject.new('xyz').tap do |buffer|
148
- buffer[ 0, 0].to_str.must_equal ''
149
- buffer[ 0, 1].to_str.must_equal 'x'
150
- buffer[ 0, 3].to_str.must_equal 'xyz'
151
- buffer[ 2, 4].to_str.must_equal 'z'
152
- buffer[ 2, 1].to_str.must_equal 'z'
153
- buffer[-2, 1].to_str.must_equal 'y'
154
- buffer[ 0, -1].to_str.must_equal ''
129
+ buffer[ 0, 0].to_s.must_equal ''
130
+ buffer[ 0, 1].to_s.must_equal 'x'
131
+ buffer[ 0, 3].to_s.must_equal 'xyz'
132
+ buffer[ 2, 1].to_s.must_equal 'z'
155
133
  end
156
134
  end
157
135
 
158
- it '#[] must return its length' do
136
+ it '#bytesize must return its length' do
159
137
  subject.new('testing').bytesize.must_equal 7
160
138
  end
161
139
 
162
140
  it '#ldrop must drop bytes off the left' do
163
- subject.new('xyz').ldrop(2).to_str.must_equal('z')
141
+ subject.new('xyz').ldrop(2).to_s.must_equal('z')
164
142
  end
165
143
 
166
144
  it '#rdrop must drop bytes off the right' do
167
- subject.new('xyz').rdrop(2).to_str.must_equal('x')
145
+ subject.new('xyz').rdrop(2).to_s.must_equal('x')
168
146
  end
169
147
 
170
148
  it '#inspect must not reveal its instance variables' do
171
149
  subject.new('blah').inspect.wont_include 'blah'
172
150
  end
173
151
 
174
- it '#to_str must return its internal bytes' do
175
- subject.new('xyz').to_str.must_equal('xyz')
152
+ it '#to_s must return its internal bytes' do
153
+ subject.new('xyz').to_s.must_equal('xyz')
154
+ end
155
+
156
+ it '#to_ptr must return the live pointer to its data' do
157
+ subject.new('xyz').to_ptr.read_bytes(3).must_equal('xyz')
158
+ end
159
+
160
+
161
+ it 'must wipe its contents when garbage collected' do
162
+ address = lambda { Sodium::Buffer.new('xyz').to_ptr.address }
163
+ pointer = FFI::Pointer.new(address.call)
164
+
165
+ trigger_gc!
166
+
167
+ pointer.read_bytes(3).wont_equal('xyz')
168
+ end
169
+
170
+ it 'must free its contents when garbage collected' do
171
+ flag = MiniTest::Mock.new
172
+ free = lambda {|pointer| flag.called(pointer) }
173
+ flag.expect :called, nil, [ FFI::Pointer ]
174
+
175
+ Sodium::FFI::LibC.stub(:free, free) do
176
+ Sodium::Buffer.new('xyz')
177
+
178
+ trigger_gc!
179
+ end
180
+
181
+
182
+ flag.verify
176
183
  end
177
184
  end