Use crypto_box_beforenmbytes to precompute CryptoBox shared key.

This commit is contained in:
Didactic Drunk 2019-08-06 14:27:19 -07:00
parent 31c3ead851
commit d556e1c909
6 changed files with 61 additions and 25 deletions

View File

@ -7,6 +7,11 @@ require "../src/sodium"
{% end %}
puts ""
{% for name in %w(MAC_SIZE NM_SIZE) %}
puts "Sodium::CryptoBox::{{ name.id }} #{Sodium::CryptoBox::{{ name.id }}}"
{% end %}
puts ""
{% for name in %w(KEY_SIZE SEED_SIZE SIG_SIZE) %}
puts "Sodium::Sign::SecretKey::{{ name.id }} #{Sodium::Sign::SecretKey::{{ name.id }}}"
{% end %}

View File

@ -4,17 +4,27 @@ require "./crypto_box/secret_key"
require "./nonce"
module Sodium
# Use Sodium::CryptoBox::SecretKey#box
class CryptoBox
include Wipe
MAC_SIZE = LibSodium.crypto_box_macbytes.to_i
# :nodoc:
NM_SIZE = LibSodium.crypto_box_beforenmbytes.to_i
raise "NM_SIZE=#{NM_SIZE}, assumed it was 32" if NM_SIZE != 32
# BUG: precompute size
@[Wipe::Var]
@bytes = Bytes.new(1)
@key = StaticArray(UInt8, 32).new 0
# :nodoc:
# Used by SecretKey#box
def initialize(@secret_key : SecretKey, @public_key : PublicKey)
# TODO: precompute using crypto_box_beforenm
# Precalculate key for later use.
# Large speed gains with small data sizes and many messages.
# Small speed gains with large data sizes or few messages.
if LibSodium.crypto_box_beforenm(@key, @public_key.to_slice, @secret_key.to_slice) != 0
raise Error.new("crypto_box_beforenm")
end
end
# Encrypts data and returns {ciphertext, nonce}
@ -26,7 +36,7 @@ module Sodium
#
# Optionally supply a destination buffer.
def encrypt(src : Bytes, dst = Bytes.new(src.bytesize + MAC_SIZE), nonce = Nonce.new) : {Bytes, Nonce}
if LibSodium.crypto_box_easy(dst, src, src.bytesize, nonce.to_slice, @public_key.to_slice, @secret_key.to_slice) != 0
if LibSodium.crypto_box_easy_afternm(dst, src, src.bytesize, nonce.to_slice, @key.to_slice) != 0
raise Error.new("crypto_box_easy")
end
{dst, nonce}
@ -41,8 +51,8 @@ module Sodium
# Returns decrypted message.
#
# Optionally supply a destination buffer.
def decrypt(src : Bytes, dst = Bytes.new(src.bytesize - MAC_SIZE), nonce = Nonce.new) : Bytes
if LibSodium.crypto_box_open_easy(dst, src, src.bytesize, nonce.to_slice, @public_key.to_slice, @secret_key.to_slice) != 0
def decrypt(src : Bytes, dst = Bytes.new(src.bytesize - MAC_SIZE), nonce = Nonce.random) : Bytes
if LibSodium.crypto_box_open_easy_afternm(dst, src, src.bytesize, nonce.to_slice, @key) != 0
raise Error::DecryptionFailed.new("crypto_box_open_easy")
end
dst

View File

@ -5,8 +5,6 @@ require "../crypto_box"
class Sodium::CryptoBox
# Key used for encryption + authentication or encryption without authentication, not for unencrypted signing.
#
# If you don't want this behavior pass a duplicate of the key/seed to initialize().
class SecretKey < Key
KEY_SIZE = LibSodium.crypto_box_secretkeybytes.to_i
SEED_SIZE = LibSodium.crypto_box_seedbytes.to_i

View File

@ -12,6 +12,7 @@ module Sodium
fun crypto_box_noncebytes : LibC::SizeT
fun crypto_box_sealbytes : LibC::SizeT
fun crypto_box_macbytes : LibC::SizeT
fun crypto_box_beforenmbytes : LibC::SizeT
fun crypto_sign_publickeybytes : LibC::SizeT
fun crypto_sign_secretkeybytes : LibC::SizeT
fun crypto_sign_bytes : LibC::SizeT
@ -148,22 +149,45 @@ module Sodium
secret_key_output : Pointer(LibC::UChar)
) : LibC::Int
fun crypto_box_easy(
output : Pointer(LibC::UChar),
data : Pointer(LibC::UChar),
data_size : LibC::ULongLong,
nonce : Pointer(LibC::UChar),
recipient_public_key : Pointer(LibC::UChar),
sender_secret_key : Pointer(LibC::UChar)
fun crypto_box_beforenm(
k : Pointer(LibC::UChar),
pk : Pointer(LibC::UChar),
sk : Pointer(LibC::UChar)
) : LibC::Int
fun crypto_box_open_easy(
fun crypto_box_easy_afternm(
output : Pointer(LibC::UChar),
data : Pointer(LibC::UChar),
data_size : LibC::ULongLong,
nonce : Pointer(LibC::UChar),
sender_public_key : Pointer(LibC::UChar),
recipient_secret_key : Pointer(LibC::UChar)
key : Pointer(LibC::UChar)
) : LibC::Int
# TODO: possibly remove after switching to detached
fun crypto_box_open_easy_afternm(
output : Pointer(LibC::UChar),
data : Pointer(LibC::UChar),
data_size : LibC::ULongLong,
nonce : Pointer(LibC::UChar),
key : Pointer(LibC::UChar)
) : LibC::Int
fun crypto_box_detached_afternm(
output : Pointer(LibC::UChar),
mac : Pointer(LibC::UChar),
data : Pointer(LibC::UChar),
data_size : LibC::ULongLong,
nonce : Pointer(LibC::UChar),
key : Pointer(LibC::UChar)
) : LibC::Int
fun crypto_box_open_detached_afternm(
output : Pointer(LibC::UChar),
data : Pointer(LibC::UChar),
mac : Pointer(LibC::UChar),
data_size : LibC::ULongLong,
nonce : Pointer(LibC::UChar),
key : Pointer(LibC::UChar)
) : LibC::Int
fun crypto_box_seal(
@ -294,8 +318,7 @@ module Sodium
end
end
# Constant time memory compare.
# Raises unless comparison succeeds.
# Constant time memory compare. Raises unless comparison succeeds.
def self.memcmp!(a, b)
raise Error::MemcmpFailed.new unless memcmp(a, b)
true

View File

@ -2,12 +2,12 @@ require "./lib_sodium"
require "./wipe"
module Sodium
# Allocate guarded memory using [sodium_malloc](https://libsodium.gitbook.io/doc/memory_management)
class SecureBuffer
getter bytesize
delegate :+, :[], :[]=, to: to_slice
# Allocate guarded memory using [sodium_malloc](https://libsodium.gitbook.io/doc/memory_management)
def initialize(@bytesize : Int32)
@ptr = LibSodium.sodium_malloc @bytesize
end

View File

@ -3,15 +3,15 @@ require "../key"
require "./public_key"
module Sodium
# Key used for signing/verification only.
# Ed25519 secret key used for signing.
#
# If you don't want this behavior pass a duplicate of the key/seed to initialize().
# [https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures](https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures)
#
# Usage:
# ```
# key = SecretKey.new
# key = Sodium::Sign::SecretKey.new
# sig = key.sign_detached data
# key.public_key.verify_detached data
# key.public_key.verify_detached data, sig
# ```
class Sign::SecretKey < Sodium::Key
KEY_SIZE = LibSodium.crypto_sign_secretkeybytes.to_i