SecureBuffer for Chalsa.

master
Didactic Drunk 2019-07-08 16:08:39 -07:00
parent cfd8a10b6b
commit 65ad5987d4
2 changed files with 21 additions and 17 deletions

View File

@ -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 %}

View File

@ -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 %}