commit
2d0f329774
14
README.md
14
README.md
|
@ -40,6 +40,19 @@ nonce, encrypted = Cox.encrypt(data, bob.public, alice.secret)
|
|||
decrypted = Cox.decrypt(encrypted, nonce, alice.public, bob.secret)
|
||||
|
||||
String.new(decrypted) # => "Hello World!"
|
||||
|
||||
|
||||
# Public key signing
|
||||
|
||||
message = "Hello World!"
|
||||
|
||||
signing_pair = Cox::SignKeyPair.new
|
||||
|
||||
# Sign the message
|
||||
signature = Cox.sign_detached(message, signing_pair.secret)
|
||||
|
||||
# And verify
|
||||
Cox.verify_detached(signature, message, signing_pair.public) # => true
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
@ -53,3 +66,4 @@ String.new(decrypted) # => "Hello World!"
|
|||
## Contributors
|
||||
|
||||
- [andrewhamon](https://github.com/andrewhamon) Andrew Hamon - creator, maintainer
|
||||
- [dorkrawk](https://github.com/dorkrawk) Dave Schwantes - contributor
|
||||
|
|
|
@ -3,7 +3,7 @@ require "./spec_helper"
|
|||
describe Cox do
|
||||
# TODO: Write tests
|
||||
|
||||
it "works" do
|
||||
it "works for encrypting" do
|
||||
data = "Hello World!"
|
||||
|
||||
# Alice is the sender
|
||||
|
@ -22,4 +22,18 @@ describe Cox do
|
|||
|
||||
String.new(decrypted).should eq(data)
|
||||
end
|
||||
|
||||
it "works for signing" do
|
||||
message = "test"
|
||||
|
||||
signing_pair = Cox::SignKeyPair.new
|
||||
|
||||
# Create signature using the secret key
|
||||
signature = Cox.sign_detached(message, signing_pair.secret)
|
||||
|
||||
# Verify the signature on the message
|
||||
verified = Cox.verify_detached(signature, message, signing_pair.public)
|
||||
|
||||
verified.should eq(true)
|
||||
end
|
||||
end
|
||||
|
|
18
src/cox.cr
18
src/cox.cr
|
@ -21,6 +21,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)
|
||||
output_buffer
|
||||
end
|
||||
|
||||
def self.sign_detached(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_detached(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
|
||||
|
||||
if Cox::LibSodium.sodium_init() == -1
|
||||
|
|
|
@ -3,15 +3,21 @@ module Cox
|
|||
lib LibSodium
|
||||
fun sodium_init() : LibC::Int
|
||||
|
||||
fun crypto_box_publickeybytes() : LibC::SizeT
|
||||
fun crypto_box_secretkeybytes() : LibC::SizeT
|
||||
fun crypto_box_noncebytes() : LibC::SizeT
|
||||
fun crypto_box_macbytes() : LibC::SizeT
|
||||
fun crypto_box_publickeybytes() : LibC::SizeT
|
||||
fun crypto_box_secretkeybytes() : 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
|
||||
|
||||
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
||||
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
||||
NONCE_BYTES = crypto_box_macbytes()
|
||||
MAC_BYTES = crypto_box_macbytes()
|
||||
PUBLIC_KEY_BYTES = crypto_box_publickeybytes()
|
||||
SECRET_KEY_BYTES = crypto_box_secretkeybytes()
|
||||
NONCE_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(
|
||||
public_key_output : Pointer(LibC::UChar),
|
||||
|
@ -35,5 +41,25 @@ module Cox
|
|||
sender_public_key : Pointer(LibC::UChar),
|
||||
recipient_secret_key : Pointer(LibC::UChar)
|
||||
) : 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
|
||||
|
|
|
@ -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
|
Loading…
Reference in New Issue