Fix Sodium::SecureBuffer state transitions.
This commit is contained in:
parent
964fe714e9
commit
b212f6bacd
@ -51,17 +51,17 @@ describe Sodium::SecureBuffer do
|
|||||||
|
|
||||||
buf.noaccess
|
buf.noaccess
|
||||||
buf.@state.should eq Sodium::SecureBuffer::State::Noaccess
|
buf.@state.should eq Sodium::SecureBuffer::State::Noaccess
|
||||||
buf.readonly { }
|
buf.readonly { buf.@state.should eq Sodium::SecureBuffer::State::Readonly }
|
||||||
buf.@state.should eq Sodium::SecureBuffer::State::Noaccess
|
buf.@state.should eq Sodium::SecureBuffer::State::Noaccess
|
||||||
|
|
||||||
buf.readonly
|
buf.readonly
|
||||||
buf.@state.should eq Sodium::SecureBuffer::State::Readonly
|
buf.@state.should eq Sodium::SecureBuffer::State::Readonly
|
||||||
buf.readwrite { }
|
buf.readwrite { buf.@state.should eq Sodium::SecureBuffer::State::Readwrite }
|
||||||
buf.@state.should eq Sodium::SecureBuffer::State::Readonly
|
buf.@state.should eq Sodium::SecureBuffer::State::Readonly
|
||||||
|
|
||||||
buf.readwrite
|
buf.readwrite
|
||||||
buf.@state.should eq Sodium::SecureBuffer::State::Readwrite
|
buf.@state.should eq Sodium::SecureBuffer::State::Readwrite
|
||||||
buf.readonly { }
|
buf.readonly { buf.@state.should eq Sodium::SecureBuffer::State::Readwrite }
|
||||||
buf.@state.should eq Sodium::SecureBuffer::State::Readwrite
|
buf.@state.should eq Sodium::SecureBuffer::State::Readwrite
|
||||||
|
|
||||||
buf.wipe
|
buf.wipe
|
||||||
|
@ -21,19 +21,19 @@ module Sodium
|
|||||||
MAC_SIZE = LibSodium.crypto_secretbox_macbytes.to_i
|
MAC_SIZE = LibSodium.crypto_secretbox_macbytes.to_i
|
||||||
|
|
||||||
# Returns key
|
# Returns key
|
||||||
delegate to_slice, to: @buf
|
delegate to_slice, to: @key
|
||||||
|
|
||||||
# Generate a new random key held in a SecureBuffer.
|
# Generate a new random key held in a SecureBuffer.
|
||||||
def initialize
|
def initialize
|
||||||
@buf = SecureBuffer.random KEY_SIZE
|
@key = SecureBuffer.random KEY_SIZE
|
||||||
end
|
end
|
||||||
|
|
||||||
# Use an existing SecureBuffer.
|
# Use an existing SecureBuffer.
|
||||||
def initialize(@buf : SecureBuffer)
|
def initialize(@key : SecureBuffer)
|
||||||
if @buf.bytesize != KEY_SIZE
|
if @key.bytesize != KEY_SIZE
|
||||||
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{@buf.bytesize}")
|
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{@key.bytesize}")
|
||||||
end
|
end
|
||||||
@buf.readonly
|
@key.readonly
|
||||||
end
|
end
|
||||||
|
|
||||||
# Copy bytes to a new SecureBuffer
|
# Copy bytes to a new SecureBuffer
|
||||||
@ -43,7 +43,7 @@ module Sodium
|
|||||||
if bytes.bytesize != KEY_SIZE
|
if bytes.bytesize != KEY_SIZE
|
||||||
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}")
|
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}")
|
||||||
end
|
end
|
||||||
@buf = SecureBuffer.new bytes, erase: erase
|
@key = SecureBuffer.new bytes, erase: erase
|
||||||
end
|
end
|
||||||
|
|
||||||
# Encrypts data and returns {ciphertext, nonce}
|
# Encrypts data and returns {ciphertext, nonce}
|
||||||
@ -59,9 +59,10 @@ module Sodium
|
|||||||
raise ArgumentError.new("dst.bytesize must be src.bytesize + MAC_SIZE, got #{dst.bytesize}")
|
raise ArgumentError.new("dst.bytesize must be src.bytesize + MAC_SIZE, got #{dst.bytesize}")
|
||||||
end
|
end
|
||||||
nonce.used!
|
nonce.used!
|
||||||
if LibSodium.crypto_secretbox_easy(dst, src, src.bytesize, nonce.to_slice, self.to_slice) != 0
|
r = @key.readonly do
|
||||||
raise Sodium::Error.new("crypto_secretbox_easy")
|
LibSodium.crypto_secretbox_easy(dst, src, src.bytesize, nonce.to_slice, @key)
|
||||||
end
|
end
|
||||||
|
raise Sodium::Error.new("crypto_secretbox_easy") if r != 0
|
||||||
{dst, nonce}
|
{dst, nonce}
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -80,9 +81,10 @@ module Sodium
|
|||||||
if dst.bytesize != (src.bytesize - MAC_SIZE)
|
if dst.bytesize != (src.bytesize - MAC_SIZE)
|
||||||
raise ArgumentError.new("dst.bytesize must be src.bytesize - MAC_SIZE, got #{dst.bytesize}")
|
raise ArgumentError.new("dst.bytesize must be src.bytesize - MAC_SIZE, got #{dst.bytesize}")
|
||||||
end
|
end
|
||||||
if LibSodium.crypto_secretbox_open_easy(dst, src, src.bytesize, nonce.to_slice, self.to_slice) != 0
|
r = @key.readonly do
|
||||||
raise Sodium::Error::DecryptionFailed.new("crypto_secretbox_easy")
|
LibSodium.crypto_secretbox_open_easy(dst, src, src.bytesize, nonce.to_slice, @key)
|
||||||
end
|
end
|
||||||
|
raise Sodium::Error::DecryptionFailed.new("crypto_secretbox_easy") if r != 0
|
||||||
dst
|
dst
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -68,7 +68,12 @@ module Sodium
|
|||||||
# Returns key
|
# Returns key
|
||||||
# May permanently set key to readonly depending on class usage.
|
# May permanently set key to readonly depending on class usage.
|
||||||
def to_slice
|
def to_slice
|
||||||
readonly if @state == State::Noaccess
|
case @state
|
||||||
|
when State::Noaccess, State::Wiped
|
||||||
|
readonly
|
||||||
|
else
|
||||||
|
# Ok
|
||||||
|
end
|
||||||
Slice(UInt8).new @ptr, @bytesize
|
Slice(UInt8).new @ptr, @bytesize
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -154,16 +159,16 @@ module Sodium
|
|||||||
end
|
end
|
||||||
|
|
||||||
private def with_state(new_state : State)
|
private def with_state(new_state : State)
|
||||||
|
old_state = @state
|
||||||
# Only change when new_state needs more access than @state.
|
# Only change when new_state needs more access than @state.
|
||||||
if new_state >= @state
|
if old_state >= new_state
|
||||||
yield
|
yield
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
old_state = @state
|
|
||||||
set_state new_state
|
set_state new_state
|
||||||
yield
|
yield
|
||||||
ensure
|
ensure
|
||||||
set_state old_state if old_state
|
set_state old_state
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user