README.md: How? When?
parent
fd26f11489
commit
f13bd8de9c
77
README.md
77
README.md
|
@ -6,7 +6,7 @@
|
|||
|
||||
Secrets hold sensitive information
|
||||
|
||||
The Secret interface manages limited time access to the secret and securely erasing the secret when no longer needed.
|
||||
The Secret interface manages limited time access to a secret and securely erases the secret when no longer needed.
|
||||
|
||||
Secret providers may implement additional protections via:
|
||||
* `#noaccess`, `#readonly` or `readwrite`.
|
||||
|
@ -35,15 +35,17 @@ Secret providers may implement additional protections via:
|
|||
```crystal
|
||||
require "crypto-secret/not"
|
||||
|
||||
not_secret = Crypto::Secret::Not.new 32
|
||||
not_secret.wipe do
|
||||
not_secret.readonly do |slice|
|
||||
# `Not` isn't actually a secret and does none of what the comments say
|
||||
# Replace `Not` with a secure implementation like [Sodium::SecureBuffer](https://didactic-drunk.github.io/sodium.cr/master/Sodium/SecureBuffer.html)
|
||||
secret = Crypto::Secret::Not.new 32
|
||||
secret.wipe do
|
||||
secret.readonly do |slice|
|
||||
# May only read slice
|
||||
end
|
||||
not_secret.readwrite do |slice|
|
||||
secret.readwrite do |slice|
|
||||
# May read or write to slice
|
||||
end
|
||||
end # Secret is erased
|
||||
end # secret is erased
|
||||
```
|
||||
|
||||
## What is a Secret?
|
||||
|
@ -58,7 +60,7 @@ That's complicated and specific to the application. Some examples:
|
|||
Not secrets:
|
||||
|
||||
* Digest output. Except when used for key derivation, then it's a Secret, including the Digest state
|
||||
* IO::Memory or writing a file. Except when the file is a password vault, cryptocurrency wallet, encrypted mail/messages, goat porn, maybe normal porn, sometimes scat porn, occassionally furry, not vanilla porn
|
||||
* IO::Memory or writing a file. Except when the file is a password vault, cryptocurrency wallet, encrypted mail/messages, goat porn, maybe "normal" porn, sometimes scat porn, occassionally furry, not vanilla porn
|
||||
|
||||
## Why?
|
||||
|
||||
|
@ -67,10 +69,62 @@ The Secret interface is designed to handle varied levels of confidentiality with
|
|||
There is no one size fits all solution. Different applications have different security requirements. Sometimes for the same algorithm.
|
||||
|
||||
A master key (kgk) may reside on a HSM and generate subkeys on demand.
|
||||
Or for most applications the master key may use best effort protection using a combination of [guard pages, mlock, mprotect].
|
||||
Or for most applications the master key may use a best effort approach using a combination of [guard pages, mlock, mprotect].
|
||||
Other keys in the same application may handle a high volume of messages where [guard pages, mlock, mprotect] overhead is too high.
|
||||
A key verifying a public key signature may not be Secret.
|
||||
A key verifying a public key signature may not be Secret (but is a Secret::Not).
|
||||
|
||||
## How do I use a Secret returned by a shard?
|
||||
|
||||
That depends on what you use it for.
|
||||
|
||||
#### Using a Secret key
|
||||
|
||||
TODO
|
||||
|
||||
#### Using a Secret to hold decrypted file contents:
|
||||
```
|
||||
key = ...another Secret...
|
||||
encrypted_str = File.read("filename")
|
||||
decrypted_size = encrypted_str.bytesize - mac_size
|
||||
file_secret = Crypto::Secret::Default.new decrypted_size
|
||||
file_secret.wipe do
|
||||
file_secrets.readwrite do |slice|
|
||||
decrypt(key: key, src: encrypted_str, dst: slice)
|
||||
|
||||
# Do something with file contents in slice
|
||||
end
|
||||
end # Decrypted data is erased
|
||||
```
|
||||
|
||||
## When should I use a Secret?
|
||||
|
||||
When implementing an encryption class return `Secret` keys with a sane default implementation that suits the average use for your class. Several default implementations will be provided.
|
||||
Allow overriding the default returned key and/or allow users of your class to provide their own `Secret` for cases where they need more or less protection.
|
||||
|
||||
Example:
|
||||
|
||||
```
|
||||
class SimplifiedEncryption
|
||||
# Allow users of your library to provide their own Secret key. Also provide a sane default.
|
||||
def encrypt(data : Bytes | String, key : Secret? = nil) : {Secret, Bytes}
|
||||
key ||= Crypto::Secret::Default.random
|
||||
...
|
||||
{key, encrypted_slice}
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## What attacks does a Secret protect against?
|
||||
|
||||
TODO: describe implementations
|
||||
|
||||
## Other languages/libraries
|
||||
|
||||
* rust: [secrets](https://github.com/stouset/secrets/)
|
||||
* c: [libsodium](https://github.com/jedisct1/libsodium-doc/blob/master/helpers/memory_management.md#guarded_heap_allocations)
|
||||
* go: [memguard](https://github.com/awnumar/memguard)
|
||||
* haskell: [securemem](https://hackage.haskell.org/package/securemem)
|
||||
* c#: [SecureString](https://docs.microsoft.com/en-us/dotnet/api/system.security.securestring)
|
||||
|
||||
## Implementing a new Secret holding class
|
||||
|
||||
|
@ -86,6 +140,7 @@ class MySecret
|
|||
end
|
||||
|
||||
def to_slice(& : Bytes -> Nil)
|
||||
# The yielded Slice only needs to be valid within the block
|
||||
# yield Slice.new(pointer, size)
|
||||
ensure
|
||||
# optionally reencrypt or signal HSM
|
||||
|
@ -96,14 +151,14 @@ class MySecret
|
|||
end
|
||||
|
||||
# optionally override [noaccess, readonly, readwrite]
|
||||
# optionally override (almost) any other method with implementation specific version
|
||||
# optionally override (almost) any other method with an implementation specific version
|
||||
end
|
||||
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
**Open a discussion before creating PR's**
|
||||
**Open a discussion or issue before creating PR's**
|
||||
|
||||
1. Fork it (<https://github.com/your-github-user/crypto-secret/fork>)
|
||||
2. Create your feature branch (`git checkout -b my-new-feature`)
|
||||
|
|
Loading…
Reference in New Issue