Skip to content
This repository has been archived by the owner on Mar 16, 2022. It is now read-only.

Add support for Sodium::OneTimeAuth #3

Merged
merged 5 commits into from Mar 22, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 18 additions & 1 deletion config/nacl_ffi.yml
Expand Up @@ -68,4 +68,21 @@
:implementation: ref
:constants : [ -, 32 ]

:default: *default_hash
:default: *default_hash

- :class : Sodium::OneTimeAuth
:family : crypto_onetimeauth
:constants: [ VERSION, BYTES, KEYBYTES ]

:functions:
~ : [ pointer, pointer, ulong_long, pointer, int ]
:verify: [ pointer, pointer, ulong_long, pointer, int ]

:implementations:
- &default_onetimeauth
:name : Poly1305
:primitive : :poly1305
:implementation: ref
:constants : [ -, 16, 32 ]

:default: *default_onetimeauth
1 change: 1 addition & 0 deletions lib/sodium.rb
Expand Up @@ -10,5 +10,6 @@ class CryptoError < Error; end
require 'sodium/auth'
require 'sodium/box'
require 'sodium/hash'
require 'sodium/one_time_auth'

require 'sodium/na_cl'
44 changes: 44 additions & 0 deletions lib/sodium/one_time_auth.rb
@@ -0,0 +1,44 @@
require 'sodium'

class Sodium::OneTimeAuth
include Sodium::Delegate

def self.key
Sodium::Util.key self.implementation[:KEYBYTES]
end

def initialize(key)
@key = self.class._key(key)
end

def one_time_auth(message)
message = self.class._message(message)
authenticator = Sodium::Util.buffer self.implementation[:BYTES]

self.implementation.nacl(authenticator, message, message.length, @key) or
raise Sodium::CryptoError, 'failed to generate an authenticator'

authenticator
end

def verify(message, authenticator)
message = self.class._message(message)
authenticator = self.class._authenticator(authenticator)

self.implementation.nacl_verify(authenticator, message, message.length, @key)
end

private

def self._key(k)
Sodium::Util.assert_length k.to_str, self.implementation[:KEYBYTES], 'key'
end

def self._authenticator(a)
Sodium::Util.assert_length a.to_str, self.implementation[:BYTES], 'authenticator'
end

def self._message(m)
m.to_str
end
end
2 changes: 1 addition & 1 deletion test/sodium/auth_test.rb
Expand Up @@ -33,7 +33,7 @@
must_raise Sodium::LengthError
end

it 'must raise when verifying an invalid authenticators' do
it 'must raise when verifying an invalid authenticator' do
lambda { self.subject.verify('message', 'blaaah') }.
must_raise Sodium::LengthError
end
Expand Down
52 changes: 52 additions & 0 deletions test/sodium/one_time_auth/poly1305_test.rb
@@ -0,0 +1,52 @@
require 'test_helper'

describe Sodium::OneTimeAuth::Poly1305 do
subject { self.klass.new(self.key) }

let(:klass) { Sodium::OneTimeAuth::Poly1305 }
let(:primitive) { :poly1305 }

let :constants do
{ :BYTES => 16,
:KEYBYTES => 32, }
end

let(:key) { Base64.decode64 'tZUeTVtSHOfgOei4DUwCt10xqrIYhALpO08NIDMWFB0=' }
let(:authenticator) { Base64.decode64 'n+6StqC6SLRuLT8YZoQoFw==' }
let(:plaintext) { 'message' }

it '::primitive must be correct' do
self.klass.primitive.must_equal self.primitive
end

it 'must have correct values for its constants' do
self.constants.each_pair do |name, value|
self.klass[name].must_equal value
end
end

it 'must mint keys' do
self.klass.key.length.
must_equal self.klass::KEYBYTES
end

it 'must generate authenticators' do
self.subject.one_time_auth(
self.plaintext
).must_equal self.authenticator
end

it 'must verify authenticators' do
self.subject.verify(
self.plaintext,
self.authenticator
).must_equal true
end

it 'must not verify forged authenticators' do
self.subject.verify(
self.plaintext,
self.authenticator.succ
).must_equal false
end
end
47 changes: 47 additions & 0 deletions test/sodium/one_time_auth_test.rb
@@ -0,0 +1,47 @@
require 'test_helper'

describe Sodium::OneTimeAuth do
subject { self.klass.new(self.key) }
let(:klass) { Sodium::OneTimeAuth }
let(:key) { self.klass.key }

it 'must default to the Poly1305 implementation' do
self.klass.implementation.
must_equal Sodium::OneTimeAuth::Poly1305
end

it 'must allow access to alternate implementations' do
self.klass.implementation(:foo).
must_equal nil
end

it 'must instantiate the default implementation' do
self.subject.
must_be_kind_of Sodium::OneTimeAuth::Poly1305
end

it 'must mint keys from the default implementation' do
sodium_mock_default(self.klass) do |klass, mock|
mock.expect :[], 0, [:KEYBYTES]

klass.key.length.must_equal 0
end
end

it 'must raise when instantiating with an invalid key' do
lambda { self.klass.new(self.key[0..-2]) }.
must_raise Sodium::LengthError
end

it 'must raise when verifying an invalid authenticator' do
lambda { self.subject.verify('message', 'blaah') }.
must_raise Sodium::LengthError
end

it 'must raise when failing to generate an authenticator' do
sodium_stub_failure(self.klass, :nacl) do
lambda { self.subject.one_time_auth('message') }.
must_raise Sodium::CryptoError
end
end
end