added basic libsodium public key signature sign/verify functionality
parent
057f093a32
commit
3fa19b57e3
|
@ -3,7 +3,7 @@ require "./spec_helper"
|
||||||
describe Cox do
|
describe Cox do
|
||||||
# TODO: Write tests
|
# TODO: Write tests
|
||||||
|
|
||||||
it "works" do
|
it "works for encrypting" do
|
||||||
data = "Hello World!"
|
data = "Hello World!"
|
||||||
|
|
||||||
# Alice is the sender
|
# Alice is the sender
|
||||||
|
@ -22,4 +22,18 @@ describe Cox do
|
||||||
|
|
||||||
String.new(decrypted).should eq(data)
|
String.new(decrypted).should eq(data)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "works for signing" do
|
||||||
|
message = "test"
|
||||||
|
|
||||||
|
signing_pair = Cox::SignKeyPair.new
|
||||||
|
|
||||||
|
# Create signature using the secret key
|
||||||
|
signature = Cox.sign(message, signing_pair.secret)
|
||||||
|
|
||||||
|
# Verify the signature on the message
|
||||||
|
verified = Cox.verify(signature, message, signing_pair.public)
|
||||||
|
|
||||||
|
verified.should eq(true)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
18
src/cox.cr
18
src/cox.cr
|
@ -22,6 +22,24 @@ module Cox
|
||||||
LibSodium.crypto_box_open_easy(output_buffer.to_unsafe, data_buffer.to_unsafe, data_size, nonce.pointer, sender_public_key.pointer, recipient_secret_key.pointer)
|
LibSodium.crypto_box_open_easy(output_buffer.to_unsafe, data_buffer.to_unsafe, data_size, nonce.pointer, sender_public_key.pointer, recipient_secret_key.pointer)
|
||||||
output_buffer
|
output_buffer
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.sign(message, secret_key : SignSecretKey)
|
||||||
|
message_buffer = message.to_slice
|
||||||
|
message_buffer_size = message_buffer.bytesize
|
||||||
|
signature_output_buffer = Bytes.new(LibSodium::SIGNATURE_BYTES)
|
||||||
|
|
||||||
|
LibSodium.crypto_sign_detached(signature_output_buffer.to_unsafe, 0, message_buffer.to_unsafe, message_buffer_size, secret_key.pointer)
|
||||||
|
signature_output_buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.verify(signature, message, public_key : SignPublicKey)
|
||||||
|
signature_buffer = signature.to_slice
|
||||||
|
message_buffer = message.to_slice
|
||||||
|
message_buffer_size = message_buffer.bytesize
|
||||||
|
|
||||||
|
verified = LibSodium.crypto_sign_verify_detached(signature_buffer.to_unsafe, message_buffer.to_unsafe, message_buffer_size, public_key.pointer)
|
||||||
|
verified.zero?
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if Cox::LibSodium.sodium_init() == -1
|
if Cox::LibSodium.sodium_init() == -1
|
||||||
|
|
|
@ -7,11 +7,17 @@ module Cox
|
||||||
fun crypto_box_secretkeybytes() : LibC::SizeT
|
fun crypto_box_secretkeybytes() : LibC::SizeT
|
||||||
fun crypto_box_noncebytes() : LibC::SizeT
|
fun crypto_box_noncebytes() : LibC::SizeT
|
||||||
fun crypto_box_macbytes() : 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
|
||||||
|
|
||||||
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
||||||
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
||||||
NONCE_BYTES = crypto_box_macbytes()
|
NONCE_BYTES = crypto_box_macbytes()
|
||||||
MAC_BYTES = crypto_box_macbytes()
|
MAC_BYTES = crypto_box_macbytes()
|
||||||
|
PUBLIC_SIGN_BYTES = crypto_sign_publickeybytes()
|
||||||
|
SECRET_SIGN_BYTES = crypto_sign_secretkeybytes()
|
||||||
|
SIGNATURE_BYTES = crypto_sign_bytes()
|
||||||
|
|
||||||
fun crypto_box_keypair(
|
fun crypto_box_keypair(
|
||||||
public_key_output : Pointer(LibC::UChar),
|
public_key_output : Pointer(LibC::UChar),
|
||||||
|
@ -35,5 +41,25 @@ module Cox
|
||||||
sender_public_key : Pointer(LibC::UChar),
|
sender_public_key : Pointer(LibC::UChar),
|
||||||
recipient_secret_key : Pointer(LibC::UChar)
|
recipient_secret_key : Pointer(LibC::UChar)
|
||||||
) : LibC::Int
|
) : LibC::Int
|
||||||
|
|
||||||
|
fun crypto_sign_keypair(
|
||||||
|
public_key_output : Pointer(LibC::UChar),
|
||||||
|
secret_key_output : Pointer(LibC::UChar)
|
||||||
|
) : LibC::Int
|
||||||
|
|
||||||
|
fun crypto_sign_detached(
|
||||||
|
signature_output : Pointer(LibC::UChar),
|
||||||
|
signature_output_size : LibC::ULongLong,
|
||||||
|
message : Pointer(LibC::UChar),
|
||||||
|
message_size : LibC::ULongLong,
|
||||||
|
secret_key : Pointer(LibC::UChar)
|
||||||
|
) : LibC::Int
|
||||||
|
|
||||||
|
fun crypto_sign_verify_detached(
|
||||||
|
signature : Pointer(LibC::UChar),
|
||||||
|
message : Pointer(LibC::UChar),
|
||||||
|
message_size : LibC::ULongLong,
|
||||||
|
public_key : Pointer(LibC::UChar)
|
||||||
|
) : LibC::Int
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
require "./lib_sodium"
|
||||||
|
|
||||||
|
module Cox
|
||||||
|
class SignKeyPair
|
||||||
|
property public : SignPublicKey
|
||||||
|
property secret : SignSecretKey
|
||||||
|
|
||||||
|
def initialize(@public, @secret)
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.new(pub : Bytes, sec : Bytes)
|
||||||
|
new(SignPublicKey.new(pub), SignSecretKey.new(sec))
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.new
|
||||||
|
public_key = Bytes.new(SignPublicKey::KEY_LENGTH)
|
||||||
|
secret_key = Bytes.new(SignSecretKey::KEY_LENGTH)
|
||||||
|
|
||||||
|
LibSodium.crypto_sign_keypair(public_key.to_unsafe, secret_key.to_unsafe)
|
||||||
|
|
||||||
|
new(public_key, secret_key)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
require "./lib_sodium"
|
||||||
|
|
||||||
|
module Cox
|
||||||
|
class SignPublicKey < Key
|
||||||
|
property bytes : Bytes
|
||||||
|
|
||||||
|
KEY_LENGTH = LibSodium::PUBLIC_SIGN_BYTES
|
||||||
|
|
||||||
|
def initialize(@bytes : Bytes)
|
||||||
|
if bytes.bytesize != KEY_LENGTH
|
||||||
|
raise ArgumentError.new("Public key must be #{KEY_LENGTH} bytes, got #{bytes.bytesize}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
require "./lib_sodium"
|
||||||
|
|
||||||
|
module Cox
|
||||||
|
class SignSecretKey < Key
|
||||||
|
property bytes : Bytes
|
||||||
|
|
||||||
|
KEY_LENGTH = LibSodium::SECRET_SIGN_BYTES
|
||||||
|
|
||||||
|
def initialize(@bytes : Bytes)
|
||||||
|
if bytes.bytesize != KEY_LENGTH
|
||||||
|
raise ArgumentError.new("Secret key must be #{KEY_LENGTH} bytes, got #{bytes.bytesize}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,15 @@
|
||||||
|
require "./lib_sodium"
|
||||||
|
|
||||||
|
module Cox
|
||||||
|
class Signature
|
||||||
|
property bytes : Bytes
|
||||||
|
|
||||||
|
KEY_LENGTH = LibSodium::SIGNATURE_BYTES
|
||||||
|
|
||||||
|
def initialize(@bytes : Bytes)
|
||||||
|
if bytes.bytesize != KEY_LENGTH
|
||||||
|
raise ArgumentError.new("Signature must be #{KEY_LENGTH} bytes, got #{bytes.bytesize}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue