Add Secret.move_from & Secret.copy_from
This commit is contained in:
parent
46a05f8abd
commit
00274735c3
25
README.md
25
README.md
@ -33,8 +33,9 @@ Secret providers may implement additional protections via:
|
||||
## Usage
|
||||
|
||||
#### Rules:
|
||||
1. Secrets are only available within a readonly or readwrite block
|
||||
2. Secrets are not thread safe except for the provided `Bytes` (only when reading) within a single readonly or readwrite block
|
||||
1. Secrets should be erased (wiped) ASAP
|
||||
2. Secrets are only available within a `readonly` or `readwrite` block
|
||||
3. Secrets are not thread safe except for the provided `Slice` (only when reading) within a single `readonly` or `readwrite` block
|
||||
|
||||
|
||||
```crystal
|
||||
@ -58,11 +59,23 @@ end # secret is erased
|
||||
If you need thread safety :
|
||||
1. Switch to a Stateless Secret
|
||||
2. Or switch the Secret's state to readonly or readwrite after construction and never switch it again. [sodium.cr]() makes use of this technique to provide thread safe encryption/decryption
|
||||
3. Or wrap all access in a Mutex
|
||||
3. Or wrap all access in a Mutex (compatible with all Secret classes)
|
||||
|
||||
If you need more better performance:
|
||||
* Consider 1. or 2.
|
||||
|
||||
If you need compatibility with any `Secret`:
|
||||
* Always use a `Mutex`
|
||||
* Never rely on 1. or 2.
|
||||
|
||||
#### Converting `Bytes` to a `Secret`
|
||||
```crystal
|
||||
slice = method_that_return_bytes()
|
||||
secret = Crypto::Secret::Bidet.move_from slice # erases slice
|
||||
# or
|
||||
secret = Crypto::Secret::Bidet.copy_from slice
|
||||
```
|
||||
|
||||
## What is a Secret?
|
||||
|
||||
<strike>Secrets are Keys</strike>
|
||||
@ -152,10 +165,12 @@ TODO: describe implementations
|
||||
|
||||
```
|
||||
class MySecret
|
||||
include Crypto::Secret
|
||||
# Choose one
|
||||
include Crypto::Secret::Stateless
|
||||
include Crypto::Secret::Stateful
|
||||
|
||||
def initialize(size)
|
||||
# allocate storage
|
||||
# allocate or reference storage
|
||||
# optionally mlock
|
||||
end
|
||||
|
||||
|
@ -7,14 +7,14 @@ describe Crypto::Secret::Not do
|
||||
key = Bytes.new ksize
|
||||
key[1] = 1_u8
|
||||
|
||||
secret1 = Crypto::Secret::Not.new key.dup
|
||||
secret1.to_slice { |s| s.should eq key }
|
||||
secret1 = Crypto::Secret::Not.copy_from key
|
||||
secret1.readonly { |s| s.should eq key }
|
||||
|
||||
secret2 = Crypto::Secret::Not.new key.dup
|
||||
secret2 = Crypto::Secret::Not.copy_from key
|
||||
|
||||
(secret1 == secret2).should be_true
|
||||
secret1.to_slice do |s1|
|
||||
secret2.to_slice do |s2|
|
||||
secret1.readonly do |s1|
|
||||
secret2.readonly do |s2|
|
||||
(s1 == s2).should be_true
|
||||
end
|
||||
end
|
||||
@ -23,9 +23,10 @@ describe Crypto::Secret::Not do
|
||||
it "bytesize" do
|
||||
secret = Crypto::Secret::Not.new 5
|
||||
secret.bytesize.should eq 5
|
||||
secret.readonly { |s| s.bytesize.should eq 5 }
|
||||
end
|
||||
|
||||
it "doesn't leak key material" do
|
||||
it "doesn't leak key material when inspecting" do
|
||||
secret = Crypto::Secret::Not.new 5
|
||||
secret.to_s.should match /\(\*\*\*SECRET\*\*\*\)$/
|
||||
secret.inspect.should match /\(\*\*\*SECRET\*\*\*\)$/
|
||||
|
@ -1,4 +1,22 @@
|
||||
module Crypto::Secret::ClassMethods
|
||||
# Copies `data` to the new Secret and **erases data**
|
||||
# Returns a **readonly** Secret
|
||||
def move_from(data : Bytes)
|
||||
copy_from data
|
||||
ensure
|
||||
data.wipe
|
||||
end
|
||||
|
||||
# Copies `data` to the new Secret
|
||||
# Returns a **readonly** Secret
|
||||
def copy_from(data : Bytes)
|
||||
new(data.bytesize).tap do |obj|
|
||||
obj.readwrite do |slice|
|
||||
data.copy_to slice
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# Returns a **readonly** random Secret
|
||||
def random(size)
|
||||
buf = new(size)
|
||||
|
@ -11,11 +11,13 @@ module Crypto::Secret
|
||||
struct Not
|
||||
include Stateless
|
||||
|
||||
def self.new(size)
|
||||
new Bytes.new(size)
|
||||
def self.new(size : Int32)
|
||||
bytes = Bytes.new size
|
||||
new(references: bytes)
|
||||
end
|
||||
|
||||
def initialize(@bytes : Bytes)
|
||||
def initialize(*, references : Bytes)
|
||||
@bytes = references
|
||||
end
|
||||
|
||||
delegate_to_slice @bytes
|
||||
|
Loading…
Reference in New Issue
Block a user