diff --git a/spec/crypto_secret_spec.cr b/spec/crypto_secret_spec.cr index 72f5072..ee47810 100644 --- a/spec/crypto_secret_spec.cr +++ b/spec/crypto_secret_spec.cr @@ -1,7 +1,8 @@ require "./spec_helper" +require "../src/crypto-secret/test" +require "../src/crypto-secret/not" +require "../src/crypto-secret/bidet" + +test_secret_class Crypto::Secret::Not +test_secret_class Crypto::Secret::Bidet -describe Crypto::Secret do - pending "works" do - false.should eq(true) - end -end diff --git a/src/crypto-secret/secret.cr b/src/crypto-secret/secret.cr index fc48a23..f6b21c1 100644 --- a/src/crypto-secret/secret.cr +++ b/src/crypto-secret/secret.cr @@ -75,6 +75,17 @@ module Crypto::Secret io << self.class.to_s << "(***SECRET***)" end + def dup + readonly do |sslice| + obj = self.class.new sslice.bytesize + obj.readwrite do |dslice| + sslice.copy_to dslice + end + # TODO: copy state if possible + obj + end + end + abstract def readwrite abstract def readonly abstract def noaccess diff --git a/src/crypto-secret/test.cr b/src/crypto-secret/test.cr new file mode 100644 index 0000000..6582319 --- /dev/null +++ b/src/crypto-secret/test.cr @@ -0,0 +1,78 @@ +macro test_secret_class(to sclass) + describe {{sclass}} do + sclass = {{sclass}} + + it "returns a random secret" do + secret1 = sclass.new 8 + secret2 = sclass.random 8 + secret1.should_not eq secret2 + end + + it "copies & wipes on .move" do + ksize = 4 + key1 = Bytes.new ksize + key1[1] = 1_u8 + key2 = key1.dup + secret = sclass.move_from key2 + + secret.readonly { |s| s.should eq key1 } + key2.should eq Bytes.new(ksize) + end + + it "copies & preserves on .copy" do + ksize = 2 + key1 = Bytes.new ksize + key1[1] = 1_u8 + key2 = key1.dup + secret = sclass.copy_from key2 + + secret.readonly { |s| s.should eq key1 } + key2.should eq key1 + end + + it "compares with ==" do + ksize = 32 + key = Bytes.new ksize + key[1] = 1_u8 + + secret1 = sclass.copy_from key + secret1.readonly { |s| s.should eq key } + + secret2 = sclass.copy_from key + + (secret1 == secret2).should be_true + secret1.readonly do |s1| + secret2.readonly do |s2| + (s1 == s2).should be_true + end + end + end + + it "dups" do + ksize = 2 + key = Bytes.new ksize + key[1] = 1_u8 + + secret1 = sclass.copy_from key + secret2 = secret1.dup + (secret1 == secret2).should be_true + end + + pending "check dup state" { } + + it "bytesize" do + secret = sclass.new 5 + secret.bytesize.should eq 5 + secret.readonly { |s| s.bytesize.should eq 5 } + end + + it "doesn't leak key material when inspecting" do + secret = sclass.new 5 + + secret.to_s.should_not match /Bytes|Slice|StaticArray/ + secret.inspect.should_not match /Bytes|Slice|StaticArray/ + + secret.inspect.should match /\(\*\*\*SECRET\*\*\*\)$/ + end + end +end