Sodum::CryptoBox::SecretKey may derive keys from a seed.
Sodum::Sign::SecretKey may derive keys from a seed. Sodum::CryptoBox::Pair renamed to Sodum::CryptoBox::Boxmaster
parent
2f4d9ddb6b
commit
41a55a9593
|
@ -144,14 +144,14 @@ alice = Sodium::CryptoBox::SecretKey.new
|
|||
bob = Sodium::CryptoBox::SecretKey.new
|
||||
|
||||
# Precompute a shared secret between alice and bob.
|
||||
pair = alice.pair bob.public_key
|
||||
box = alice.box bob.public_key
|
||||
|
||||
# Encrypt a message for Bob using his public key, signing it with Alice's
|
||||
# secret key
|
||||
nonce, encrypted = pair.encrypt data
|
||||
nonce, encrypted = box.encrypt data
|
||||
|
||||
# Precompute within a block. The shared secret is wiped when the block exits.
|
||||
bob.pair alice.public_key do |pair|
|
||||
bob.box alice.public_key do |box|
|
||||
# Decrypt the message using Bob's secret key, and verify its signature against
|
||||
# Alice's public key
|
||||
decrypted = Sodium.decrypt(encrypted, nonce, alice.public, bob.secret)
|
||||
|
|
|
@ -1,6 +1,25 @@
|
|||
require "../../spec_helper"
|
||||
|
||||
private def new_key_bytes
|
||||
Sodium::CryptoBox::SecretKey.new.bytes
|
||||
end
|
||||
|
||||
describe Sodium::CryptoBox::SecretKey do
|
||||
it "loads keys" do
|
||||
key1 = Sodium::CryptoBox::SecretKey.new
|
||||
key2 = Sodium::CryptoBox::SecretKey.new key1.bytes, key1.public_key.bytes
|
||||
key1.bytes.should eq key2.bytes
|
||||
key1.public_key.bytes.should eq key2.public_key.bytes
|
||||
end
|
||||
|
||||
it "seed keys" do
|
||||
seed = Bytes.new Sodium::CryptoBox::SecretKey::SEED_SIZE
|
||||
key1 = Sodium::CryptoBox::SecretKey.new seed: seed
|
||||
key2 = Sodium::CryptoBox::SecretKey.new seed: seed
|
||||
key1.bytes.should eq key2.bytes
|
||||
key1.public_key.bytes.should eq key2.public_key.bytes
|
||||
end
|
||||
|
||||
it "easy encrypt/decrypt" do
|
||||
data = "Hello World!"
|
||||
|
||||
|
@ -12,15 +31,19 @@ describe Sodium::CryptoBox::SecretKey do
|
|||
|
||||
# Encrypt a message for Bob using his public key, signing it with Alice's
|
||||
# secret key
|
||||
pair = alice.pair bob.public_key
|
||||
nonce, encrypted = pair.encrypt_easy data
|
||||
box = alice.box bob.public_key
|
||||
nonce, encrypted = box.encrypt_easy data
|
||||
|
||||
# Decrypt the message using Bob's secret key, and verify its signature against
|
||||
# Alice's public key
|
||||
bob.pair alice.public_key do |pair|
|
||||
decrypted = pair.decrypt_easy encrypted, nonce: nonce
|
||||
bob.box alice.public_key do |box|
|
||||
decrypted = box.decrypt_easy encrypted, nonce: nonce
|
||||
|
||||
String.new(decrypted).should eq(data)
|
||||
end
|
||||
end
|
||||
|
||||
it "wipes keys" do
|
||||
check_wiped new_key_bytes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,28 @@
|
|||
require "../../spec_helper"
|
||||
require "../../../src/sodium/sign/secret_key"
|
||||
|
||||
private def new_key_bytes
|
||||
Sodium::Sign::SecretKey.new.bytes
|
||||
end
|
||||
|
||||
describe Sodium::Sign::SecretKey do
|
||||
it "loads keys" do
|
||||
key1 = Sodium::Sign::SecretKey.new
|
||||
key2 = Sodium::Sign::SecretKey.new key1.bytes, key1.public_key.bytes
|
||||
key1.bytes.should eq key2.bytes
|
||||
key1.public_key.bytes.should eq key2.public_key.bytes
|
||||
|
||||
# TODO: test loading when missing public_key
|
||||
end
|
||||
|
||||
it "seed keys" do
|
||||
seed = Bytes.new Sodium::Sign::SecretKey::SEED_SIZE
|
||||
key1 = Sodium::Sign::SecretKey.new seed: seed
|
||||
key2 = Sodium::Sign::SecretKey.new seed: seed
|
||||
key1.bytes.should eq key2.bytes
|
||||
key1.public_key.bytes.should eq key2.public_key.bytes
|
||||
end
|
||||
|
||||
it "signs and verifies" do
|
||||
message = "foo"
|
||||
skey = Sodium::Sign::SecretKey.new
|
||||
|
@ -19,4 +40,8 @@ describe Sodium::Sign::SecretKey do
|
|||
skey.public_key.verify_detached "bar", sig
|
||||
end
|
||||
end
|
||||
|
||||
it "checks wiped" do
|
||||
check_wiped new_key_bytes
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,2 +1,9 @@
|
|||
require "spec"
|
||||
require "../src/sodium"
|
||||
|
||||
def check_wiped(buf : Bytes)
|
||||
GC.collect
|
||||
buf.each do |b|
|
||||
raise "not wiped #{buf.inspect}" if b != 0_u8
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
require "../lib_sodium"
|
||||
|
||||
module Sodium::CryptoBox
|
||||
class Pair
|
||||
class Box
|
||||
include Wipe
|
||||
|
||||
# BUG: precompute size
|
|
@ -3,7 +3,7 @@ require "../lib_sodium"
|
|||
module Sodium::CryptoBox
|
||||
class PublicKey < Key
|
||||
include Wipe
|
||||
KEY_SIZE = LibSodium::PUBLIC_KEY_SIZE
|
||||
KEY_SIZE = LibSodium.crypto_box_publickeybytes
|
||||
|
||||
getter bytes : Bytes
|
||||
|
||||
|
|
|
@ -3,36 +3,55 @@ require "../lib_sodium"
|
|||
module Sodium::CryptoBox
|
||||
class SecretKey < Key
|
||||
include Wipe
|
||||
KEY_SIZE = LibSodium::SECRET_KEY_SIZE
|
||||
MAC_SIZE = LibSodium::MAC_SIZE
|
||||
KEY_SIZE = LibSodium.crypto_box_secretkeybytes
|
||||
SEED_SIZE = LibSodium.crypto_box_seedbytes
|
||||
MAC_SIZE = LibSodium::MAC_SIZE
|
||||
|
||||
getter public_key
|
||||
getter bytes : Bytes
|
||||
@seed : Bytes?
|
||||
|
||||
# Generate a new secret/public key pair.
|
||||
# Generate a new random secret/public key pair.
|
||||
def initialize
|
||||
pkey = Bytes.new(PublicKey::KEY_SIZE)
|
||||
@bytes = Bytes.new(KEY_SIZE)
|
||||
@public_key = PublicKey.new pkey
|
||||
LibSodium.crypto_box_keypair(pkey, @bytes)
|
||||
v = LibSodium.crypto_box_keypair(pkey, @bytes)
|
||||
if v != 0
|
||||
raise Sodium::Error.new("crypto_box_keypair #{v}")
|
||||
end
|
||||
end
|
||||
|
||||
# Use existing Secret and Public keys.
|
||||
def initialize(@bytes : Bytes, pkey : Bytes)
|
||||
# TODO: finish regenerating public_key
|
||||
if bytes.bytesize != KEY_SIZE
|
||||
raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}")
|
||||
end
|
||||
@public_key = PublicKey.new pkey
|
||||
end
|
||||
|
||||
# Return a Pair containing a precomputed shared secret for use with encryption/decryption.
|
||||
def pair(public_key) : Pair
|
||||
Pair.new self, public_key
|
||||
# Derive a new secret/public key pair based on a consistent seed.
|
||||
def initialize(*, seed : Bytes)
|
||||
raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE
|
||||
@seed = seed
|
||||
|
||||
pkey = Bytes.new(PublicKey::KEY_SIZE)
|
||||
@bytes = Bytes.new(KEY_SIZE)
|
||||
@public_key = PublicKey.new pkey
|
||||
if LibSodium.crypto_box_seed_keypair(pkey, @bytes, seed) != 0
|
||||
raise Sodium::Error.new("crypto_box_seed_keypair")
|
||||
end
|
||||
end
|
||||
|
||||
# Create a new pair and automatically close when the block exits.
|
||||
def pair(public_key)
|
||||
pa = pair public_key
|
||||
# Return a Box containing a precomputed shared secret for use with encryption/decryption.
|
||||
def box(public_key) : Box
|
||||
Box.new self, public_key
|
||||
end
|
||||
|
||||
# Create a new box and automatically close when the block exits.
|
||||
def box(public_key)
|
||||
pa = box public_key
|
||||
begin
|
||||
yield pa
|
||||
ensure
|
||||
|
|
|
@ -5,11 +5,16 @@ module Sodium
|
|||
|
||||
fun crypto_box_publickeybytes : LibC::SizeT
|
||||
fun crypto_box_secretkeybytes : LibC::SizeT
|
||||
fun crypto_box_seedbytes : LibC::SizeT
|
||||
fun crypto_box_noncebytes : LibC::SizeT
|
||||
fun crypto_box_macbytes : LibC::SizeT
|
||||
fun crypto_sign_publickeybytes : LibC::SizeT
|
||||
fun crypto_sign_secretkeybytes : LibC::SizeT
|
||||
fun crypto_sign_bytes : LibC::SizeT
|
||||
fun crypto_sign_seedbytes : LibC::SizeT
|
||||
fun crypto_secretbox_keybytes : LibC::SizeT
|
||||
fun crypto_secretbox_noncebytes : LibC::SizeT
|
||||
fun crypto_secretbox_macbytes : LibC::SizeT
|
||||
fun crypto_kdf_keybytes : LibC::SizeT
|
||||
fun crypto_kdf_contextbytes : LibC::SizeT
|
||||
fun crypto_pwhash_memlimit_min : LibC::SizeT
|
||||
|
@ -41,8 +46,6 @@ module Sodium
|
|||
SECRET_KEY_SIZE = crypto_box_secretkeybytes()
|
||||
NONCE_SIZE = crypto_box_noncebytes()
|
||||
MAC_SIZE = crypto_box_macbytes()
|
||||
PUBLIC_SIGN_SIZE = crypto_sign_publickeybytes()
|
||||
SECRET_SIGN_SIZE = crypto_sign_secretkeybytes()
|
||||
SIGNATURE_SIZE = crypto_sign_bytes()
|
||||
KDF_KEY_SIZE = crypto_kdf_keybytes()
|
||||
KDF_CONTEXT_SIZE = crypto_kdf_contextbytes()
|
||||
|
@ -82,7 +85,13 @@ module Sodium
|
|||
fun crypto_box_keypair(
|
||||
public_key_output : Pointer(LibC::UChar),
|
||||
secret_key_output : Pointer(LibC::UChar)
|
||||
)
|
||||
) : LibC::Int
|
||||
|
||||
fun crypto_box_seed_keypair(
|
||||
public_key_output : Pointer(LibC::UChar),
|
||||
secret_key_output : Pointer(LibC::UChar),
|
||||
seed : Pointer(LibC::UChar)
|
||||
) : LibC::Int
|
||||
|
||||
fun crypto_box_easy(
|
||||
output : Pointer(LibC::UChar),
|
||||
|
@ -107,6 +116,12 @@ module Sodium
|
|||
secret_key_output : Pointer(LibC::UChar)
|
||||
) : LibC::Int
|
||||
|
||||
fun crypto_sign_seed_keypair(
|
||||
public_key_output : Pointer(LibC::UChar),
|
||||
secret_key_output : Pointer(LibC::UChar),
|
||||
seed : Pointer(LibC::UChar)
|
||||
) : LibC::Int
|
||||
|
||||
fun crypto_sign_detached(
|
||||
signature_output : Pointer(LibC::UChar),
|
||||
signature_output_size : Pointer(LibC::ULongLong),
|
||||
|
@ -182,4 +197,12 @@ module Sodium
|
|||
output_len : UInt64
|
||||
) : LibC::Int
|
||||
end
|
||||
|
||||
if LibSodium.crypto_secretbox_noncebytes != LibSodium.crypto_box_noncebytes
|
||||
raise "Assumptions in this library regarding nonce sizes may not be valid"
|
||||
end
|
||||
|
||||
if LibSodium.crypto_secretbox_macbytes != LibSodium.crypto_box_macbytes
|
||||
raise "Assumptions in this library regarding mac sizes may not be valid"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -13,8 +13,9 @@ module Sodium
|
|||
# message = key.decrypt_easy encrypted, nonce
|
||||
# ```
|
||||
class SecretBox < Key
|
||||
KEY_SIZE = LibSodium::SECRET_KEY_SIZE
|
||||
MAC_SIZE = LibSodium::MAC_SIZE
|
||||
KEY_SIZE = LibSodium.crypto_secretbox_keybytes
|
||||
NONCE_SIZE = LibSodium.crypto_secretbox_noncebytes
|
||||
MAC_SIZE = LibSodium::MAC_SIZE
|
||||
|
||||
property bytes : Bytes
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ require "../lib_sodium"
|
|||
module Sodium
|
||||
class Sign::PublicKey < Key
|
||||
include Wipe
|
||||
KEY_SIZE = LibSodium::PUBLIC_SIGN_SIZE
|
||||
KEY_SIZE = LibSodium.crypto_sign_publickeybytes
|
||||
|
||||
getter bytes : Bytes
|
||||
|
||||
|
@ -20,7 +20,7 @@ module Sodium
|
|||
end
|
||||
|
||||
def verify_detached(message : Bytes, sig : Bytes)
|
||||
raise ArgumentError.new("Signature must be #{LibSodium::SIGNATURE_SIZE} bytes, got #{sig.bytesize}")
|
||||
raise ArgumentError.new("Signature must be #{LibSodium::SIGNATURE_SIZE} bytes, got #{sig.bytesize}") if sig.bytesize != LibSodium::SIGNATURE_SIZE
|
||||
|
||||
v = LibSodium.crypto_sign_verify_detached sig, message, message.bytesize, @bytes
|
||||
if v != 0
|
||||
|
|
|
@ -1,36 +1,53 @@
|
|||
require "../lib_sodium"
|
||||
|
||||
module Sodium
|
||||
# Usage:
|
||||
# ```
|
||||
# key = SecretKey.new
|
||||
# sig = key.sign_detached data
|
||||
# key.public_key.verify_detached data
|
||||
# ```
|
||||
class Sign::SecretKey < Sodium::Key
|
||||
include Wipe
|
||||
KEY_SIZE = LibSodium::SECRET_SIGN_SIZE
|
||||
KEY_SIZE = LibSodium.crypto_sign_secretkeybytes
|
||||
SEED_SIZE = LibSodium.crypto_sign_seedbytes
|
||||
|
||||
getter bytes : Bytes
|
||||
getter public_key
|
||||
@seed : Bytes?
|
||||
|
||||
# Generates a new secret/public key pair.
|
||||
# Generates a new random secret/public key pair.
|
||||
def initialize
|
||||
pkey = Bytes.new(Sign::PublicKey::KEY_SIZE)
|
||||
@bytes = Bytes.new(KEY_SIZE)
|
||||
@public_key = PublicKey.new pkey
|
||||
LibSodium.crypto_sign_keypair pkey, @bytes
|
||||
if LibSodium.crypto_sign_keypair(pkey, @bytes) != 0
|
||||
raise Sodium::Error.new("crypto_sign_keypair")
|
||||
end
|
||||
end
|
||||
|
||||
# Use existing Secret and Public keys.
|
||||
def initialize(@bytes : Bytes, pkey : Bytes)
|
||||
raise ArgumentError.new("Secret sign key must be #{KEY_SIZE}, got #{@bytes.bytesize}")
|
||||
def initialize(@bytes : Bytes, pkey : Bytes? = nil)
|
||||
pkey ||= Bytes.new(Sign::PublicKey::KEY_SIZE).tap do |pk|
|
||||
# BUG: Finish regenerating public_key
|
||||
raise "Needs crypto_sign_ed25519_sk_to_pk"
|
||||
end
|
||||
raise ArgumentError.new("Secret sign key must be #{KEY_SIZE}, got #{@bytes.bytesize}") unless @bytes.bytesize == KEY_SIZE
|
||||
@public_key = PublicKey.new pkey
|
||||
end
|
||||
|
||||
# def initialize(@bytes : Bytes)
|
||||
# if bytes.bytesize != KEY_SIZE
|
||||
# raise ArgumentError.new("Secret key must be #{KEY_SIZE} bytes, got #{bytes.bytesize}")
|
||||
# end
|
||||
# BUG: fix
|
||||
# @public_key = PublicKey.new Bytes.new(100)
|
||||
# raise "Needs crypto_sign_ed25519_sk_to_pk"
|
||||
# Also needs to differentiate from seed as a single parameter
|
||||
# end
|
||||
# Derive a new secret/public key pair based on a consistent seed.
|
||||
def initialize(*, seed : Bytes)
|
||||
raise ArgumentError.new("Secret sign seed must be #{SEED_SIZE}, got #{seed.bytesize}") unless seed.bytesize == SEED_SIZE
|
||||
@seed = seed
|
||||
|
||||
pkey = Bytes.new(Sign::PublicKey::KEY_SIZE)
|
||||
@bytes = Bytes.new(KEY_SIZE)
|
||||
@public_key = PublicKey.new pkey
|
||||
if LibSodium.crypto_sign_seed_keypair(pkey, @bytes, seed) != 0
|
||||
raise Sodium::Error.new("crypto_sign_seed_keypair")
|
||||
end
|
||||
end
|
||||
|
||||
# Signs message and returns a detached signature.
|
||||
# Verify using `secret_key.public_key.verify_detached(message, sig)`
|
||||
|
|
Loading…
Reference in New Issue