12 releases
0.5.3 | Aug 27, 2023 |
---|---|
0.4.3 | Feb 9, 2023 |
0.4.2 | Jan 24, 2022 |
0.4.1 | Sep 5, 2021 |
0.4.0 | Mar 14, 2021 |
#752 in Cryptography
127 downloads per month
Used in 3 crates
295KB
5.5K
SLoC
fog-crypto
A simple storage-oriented cryptographic library that offers you freedom from choice. It supports hashing, public key signatures, public key & symmetric key encryption, key export/import, and basic key storage.
Getting cryptography right can be hard. This library attempts to make things easy by only providing a small number of cryptographic primitives, makes strong decisions about the cryptographic algorithms and their implementations, and tries to limit the number of bad things an end user can do. Changing algorithms should be infrequent, and follows a planned process (see Cryptographic Versioning). On the plus side, it's pretty hard to misuse this library in ways that leak secrets and compromise security. On the downside, this library is pretty strongly meant for working with stored data, not communication protocols, and cannot support even remotely unusual cryptographic operations. Forcing use of a single preferred set of algorithms also greatly limits hardware compatibility.
User Guidelines
You probably shouldn't be using this library directly. Portions of it should instead be
exported by an implementor of a Vault, and you should use those. Alternately, you might be
using this through fog-pack
, which also re-exports
portions of this library. You can expect to see these primitives:
General:
Vault
: A structure that can hold onto your cryptographic keys.
Hashing:
Hash
: The cryptographic hash of a sequence of bytes.HashState
: A structure for iteratively feeding in bytes to create aHash
.
Signatures:
Signature
: A validated cryptographic signature of aHash
.UnverifiedSignature
: A cryptographic signature that hasn't been verified yet.IdentityKey
: A private key for signing hashes.Identity
: A public key identity to indicate whichIdentityKey
created a givenSignature
.
Symmetric-Key Encryption:
StreamKey
: A shared symmetric key for encrypting & decrypting data.StreamId
: A public, unique identifier for indicating whatStreamKey
should be used for decrypting encrypted data.
Public-Key Encryption:
LockKey
: A private key for decrypting data.LockId
: A public key to indicate whatLockKey
should be used for decrypting encrypted data.
Encrypted Storage:
IdentityLockbox
: An encrypted container that holds aIdentityKey
.StreamLockbox
: An encrypted container that holds aStreamKey
.LockLockbox
: An encrypted container that holds aLockKey
.DataLockbox
: An encrypted container that holds a byte sequence.
Vault Implementor Guidelines
First, re-export the structs listed in the user guidelines. If your vault is entirely in
software, you probably want to use the various ContainedXXX
structs for holding keys, and
store them by exporting them for some master key. Avoid letting the keys sit around in some
unencrypted form. Your master key can be created by obtaining a 32-byte random byte sequence,
prepending it with a 1 (the version byte), and using ContainedStreamKey
's try_from
implementation to encapsulate the sequence. Make sure to zeroize the master key after doing
this!
If your vault has a hardware or OS component, your hardware vault's capabilities may be limited in its ability to store all types of keys. In this case, you will need to have a software-side implementation to make up for the missing storage. A recommended approach here is to actually accept a reference to a pure-software vault on creation, and let it handle any unsupported operations. Your vault can then capture all operations that it does support.
Alternately, if your hardware / OS component supports an extremely small subset of
functionality, cannot perform any type of key import/export, and is meant for high risk
scenarios, consider not supporting the Vault trait at all. Instead, create your own key store
interface, and provide backer implementations for just the supported interfaces (your options
being SignInterface
, StreamInterface
, and LockInterface
).
Cryptographic Algorithms Used
The currently used algorithms are:
- Hashing: Blake2B with a 32-byte digest
- Signing: Ed25519 with "strict" verification
- Symmetric Encryption: AEAD cipher using XChaCha20 and Poly1305.
- Diffie-Hellman key exchange: X25519
Cryptographic Versioning
This library has 4 core cryptographic algorithms that may be upgraded over time:
- The hash algorithm
- The signing algorithm
- The symmetric encryption algorithm (including bulk encryption, AEAD construction, and HMAC)
- The Diffie-Hellman (DH) key exchange algorithm (used for encrypting data with a public key)
Upgrades should be infrequent, and are done roughly when an existing recommended algorithm is regarded as weak but not yet broken.
The ideal upgrade process is:
- A new algorithm is selected to replace an existing one.
- The new algorithm is implemented. The relevant MAX_VERSION constant is incremented.
- After being deployed for 1 year, the relevant DEFAULT_VERSION constant is incremented. This gives time for library users to support the new algorithm without breaking non-updated deployments.
- After 2 more years, the relevant MIN_VERSION constant is incremented. This gives time for library users to increment the default version on all deployments, then upgrade all existing stored data as required.
This is the best-case upgrade scenario. If an existing algorithm is considered broken, the DEFAULT_VERSION and MIN_VERSION will be incremented as soon as possible. "Broken" here means it is feasible for a well-funded attacker to compromise the algorithm. Breaking compatibility with deployed code is considered an acceptable choice when security is compromised.
We are almost certainly going to upgrade the signing and DH exchange algorithms in the future, as we will need to move to post-quantum algorithms. There's no similar looming threat for the hash & symmetric encryption algorithms.
Dependencies
~2.7–4MB
~82K SLoC