2017-07-12 05:13:52 +02:00
|
|
|
require "./lib_sodium"
|
2018-02-14 01:39:15 +01:00
|
|
|
require "random/secure"
|
2017-07-12 05:13:52 +02:00
|
|
|
|
2019-06-29 01:17:09 +02:00
|
|
|
module Sodium
|
2017-07-12 05:13:52 +02:00
|
|
|
class Nonce
|
2019-08-06 23:30:16 +02:00
|
|
|
class Error < Sodium::Error
|
|
|
|
class Reused < Error
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
NONCE_SIZE = LibSodium::NONCE_SIZE.to_i
|
|
|
|
|
2019-08-07 07:56:49 +02:00
|
|
|
getter? used = false
|
|
|
|
|
|
|
|
# Only use with single use keys.
|
|
|
|
property? reusable = false
|
2017-07-12 05:13:52 +02:00
|
|
|
|
2019-08-07 01:45:20 +02:00
|
|
|
# Returns bytes
|
2019-11-11 04:00:22 +01:00
|
|
|
delegate_to_slice to: @bytes
|
2019-06-28 02:35:31 +02:00
|
|
|
|
2019-09-13 11:04:49 +02:00
|
|
|
delegate bytesize, to: @bytes
|
|
|
|
|
2017-07-12 05:13:52 +02:00
|
|
|
def initialize(@bytes : Bytes)
|
2019-06-25 18:29:16 +02:00
|
|
|
if bytes.bytesize != NONCE_SIZE
|
|
|
|
raise ArgumentError.new("Nonce must be #{NONCE_SIZE} bytes, got #{bytes.bytesize}")
|
2017-07-12 05:13:52 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2019-08-06 23:30:16 +02:00
|
|
|
def self.random
|
|
|
|
self.new Random::Secure.random_bytes(NONCE_SIZE)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.zero
|
|
|
|
self.new Bytes.new(NONCE_SIZE)
|
|
|
|
end
|
|
|
|
|
|
|
|
def increment
|
|
|
|
LibSodium.sodium_increment @bytes, @bytes.bytesize
|
|
|
|
@used = false
|
|
|
|
end
|
|
|
|
|
|
|
|
def used!
|
|
|
|
raise Error::Reused.new("attempted nonce reuse") if @used
|
2019-08-07 07:56:49 +02:00
|
|
|
@used = true unless @reusable
|
2017-07-12 05:13:52 +02:00
|
|
|
end
|
2019-08-31 07:30:21 +02:00
|
|
|
|
|
|
|
module SerializeConverter
|
|
|
|
def self.to_json(value : Nonce, json : JSON::Builder)
|
|
|
|
json.string Base64.strict_encode(value.to_slice)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.from_json(value : JSON::PullParser) : Nonce
|
|
|
|
Nonce.new Base64.decode(value.read_string)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.to_yaml(value : Nonce, yaml : YAML::Nodes::Builder)
|
|
|
|
yaml.scalar Base64.strict_encode(value.to_slice)
|
|
|
|
end
|
|
|
|
|
|
|
|
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Nonce
|
|
|
|
node.raise "Expected scalar, not #{node.class}" unless node.is_a?(YAML::Nodes::Scalar)
|
|
|
|
Nonce.new Base64.decode(node.value)
|
|
|
|
end
|
|
|
|
end
|
2017-07-12 05:13:52 +02:00
|
|
|
end
|
|
|
|
end
|