SecureBuffer for Chalsa.
parent
cfd8a10b6b
commit
65ad5987d4
|
@ -6,17 +6,24 @@ require "../../../src/sodium/cipher/chalsa"
|
||||||
describe Sodium::Cipher::{{ name.id }} do
|
describe Sodium::Cipher::{{ name.id }} do
|
||||||
it "xors" do
|
it "xors" do
|
||||||
data = Bytes.new(100)
|
data = Bytes.new(100)
|
||||||
|
|
||||||
cipher1 = Sodium::Cipher::{{ name.id }}.new
|
cipher1 = Sodium::Cipher::{{ name.id }}.new
|
||||||
cipher2 = Sodium::Cipher::{{ name.id }}.new
|
cipher2 = Sodium::Cipher::{{ name.id }}.new
|
||||||
|
|
||||||
key = cipher1.random_key
|
key = cipher1.random_key
|
||||||
|
cipher2.key = key
|
||||||
|
|
||||||
nonce = cipher1.random_nonce
|
nonce = cipher1.random_nonce
|
||||||
|
cipher2.nonce = nonce
|
||||||
|
|
||||||
|
|
||||||
output = cipher1.update data
|
output = cipher1.update data
|
||||||
|
output.should_not eq data # Verify encryption did something.
|
||||||
cipher1.update(data).should_not eq output # Verify offset is incremented.
|
cipher1.update(data).should_not eq output # Verify offset is incremented.
|
||||||
cipher1.final.should eq Bytes.new(0)
|
cipher1.final.should eq Bytes.new(0)
|
||||||
|
|
||||||
cipher2.key = key
|
|
||||||
cipher2.nonce = nonce
|
|
||||||
cipher2.update(output).should eq data
|
cipher2.update(output).should eq data
|
||||||
|
cipher2.final.should eq Bytes.new(0)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
|
@ -1,17 +1,12 @@
|
||||||
require "../lib_sodium"
|
require "../lib_sodium"
|
||||||
require "../wipe"
|
require "../secure_buffer"
|
||||||
|
|
||||||
module Sodium::Cipher
|
module Sodium::Cipher
|
||||||
# The great beat you can eat!
|
# The great beat you can eat!
|
||||||
#
|
#
|
||||||
# What? They're both dance?
|
# What? They're both dance?
|
||||||
#
|
|
||||||
# WARNING: This class takes ownership of any key material passed to it.
|
|
||||||
#
|
|
||||||
# WARNING: Not validated against test vectors. You should probably write some before using.
|
|
||||||
abstract class Chalsa
|
abstract class Chalsa
|
||||||
@[Wipe::Var]
|
@key : Bytes | SecureBuffer | Nil
|
||||||
@key : Bytes?
|
|
||||||
@nonce : Bytes?
|
@nonce : Bytes?
|
||||||
|
|
||||||
# Advanced usage. Don't touch.
|
# Advanced usage. Don't touch.
|
||||||
|
@ -25,7 +20,7 @@ module Sodium::Cipher
|
||||||
self.nonce = nonce if nonce
|
self.nonce = nonce if nonce
|
||||||
end
|
end
|
||||||
|
|
||||||
def key=(key : Bytes)
|
def key=(key : Bytes | SecureBuffer)
|
||||||
raise ArgumentError.new("key must be #{key_size} bytes, got #{key.bytesize}") if key.bytesize != key_size
|
raise ArgumentError.new("key must be #{key_size} bytes, got #{key.bytesize}") if key.bytesize != key_size
|
||||||
@key = key
|
@key = key
|
||||||
key
|
key
|
||||||
|
@ -38,7 +33,7 @@ module Sodium::Cipher
|
||||||
end
|
end
|
||||||
|
|
||||||
def random_key
|
def random_key
|
||||||
self.key = Random::Secure.random_bytes key_size
|
self.key = SecureBuffer.random key_size
|
||||||
end
|
end
|
||||||
|
|
||||||
def random_nonce
|
def random_nonce
|
||||||
|
@ -50,13 +45,13 @@ module Sodium::Cipher
|
||||||
update src, Bytes.new(src.bytesize)
|
update src, Bytes.new(src.bytesize)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Provided for compatibility with block ciphers.
|
# Provided for compatibility with block or tagged ciphers.
|
||||||
# Stream ciphers don't have additional data.
|
# Stream ciphers don't have additional data.
|
||||||
def final
|
def final
|
||||||
Bytes.new(0)
|
Bytes.new(0)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Sadness...
|
# Always returns false. Sadness...
|
||||||
def edible?
|
def edible?
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
|
@ -76,14 +71,16 @@ module Sodium::Cipher
|
||||||
# This class mimicks the OpenSSL::Cipher interface with minor differences.
|
# This class mimicks the OpenSSL::Cipher interface with minor differences.
|
||||||
#
|
#
|
||||||
# See `spec/sodium/cipher/chalsa_spec.cr` for examples on how to use this class.
|
# See `spec/sodium/cipher/chalsa_spec.cr` for examples on how to use this class.
|
||||||
|
#
|
||||||
|
# WARNING: Not validated against test vectors. You should probably write some before using this class.
|
||||||
class {{ key.id }} < Chalsa
|
class {{ key.id }} < Chalsa
|
||||||
# Xor's src with the cipher output and places in dst.
|
# Xor's src with the cipher output and places in dst.
|
||||||
#
|
#
|
||||||
# src and dst may be the same object but should not overlap.
|
# src and dst may be the same object but should not overlap.
|
||||||
def update(src : Bytes, dst : Bytes) : Bytes
|
def update(src : Bytes, dst : Bytes) : Bytes
|
||||||
if (key = @key) && (nonce = @nonce)
|
if (k = @key) && (n = @nonce)
|
||||||
raise ArgumentError.new("src and dst bytesize must be identical") if src.bytesize != dst.bytesize
|
raise ArgumentError.new("src and dst bytesize must be identical") if src.bytesize != dst.bytesize
|
||||||
if LibSodium.crypto_stream_{{ val.id }}_xor_ic(dst, src, src.bytesize, nonce, @offset, key) != 0
|
if LibSodium.crypto_stream_{{ val.id }}_xor_ic(dst, src, src.bytesize, n, @offset, k.to_slice) != 0
|
||||||
raise Sodium::Error.new("crypto_stream_{{ val.id }}_xor_ic")
|
raise Sodium::Error.new("crypto_stream_{{ val.id }}_xor_ic")
|
||||||
end
|
end
|
||||||
@offset += src.bytesize
|
@offset += src.bytesize
|
||||||
|
@ -94,11 +91,11 @@ module Sodium::Cipher
|
||||||
end
|
end
|
||||||
|
|
||||||
def key_size
|
def key_size
|
||||||
LibSodium.crypto_stream_chacha20_ietf_keybytes
|
LibSodium.crypto_stream_chacha20_ietf_keybytes.to_i32
|
||||||
end
|
end
|
||||||
|
|
||||||
def nonce_size
|
def nonce_size
|
||||||
LibSodium.crypto_stream_chacha20_ietf_noncebytes
|
LibSodium.crypto_stream_chacha20_ietf_noncebytes.to_i32
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
{% end %}
|
{% end %}
|
||||||
|
|
Loading…
Reference in New Issue