commit 7bfe6247347e0635d93700d9491b78ccaee44f1b
parent 098a92e7045d05fcae87f4245244a986cc833a0a
Author: Drew DeVault <sir@cmpwn.com>
Date: Mon, 10 Jan 2022 10:27:09 +0100
crypto: stub out authenc.ha
Signed-off-by: Drew DeVault <sir@cmpwn.com>
Diffstat:
M | crypto/README | | | 51 | ++++++++++++++++++++++++++++++++++++++++++++++++--- |
A | crypto/authenc.ha | | | 92 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
2 files changed, 140 insertions(+), 3 deletions(-)
diff --git a/crypto/README b/crypto/README
@@ -1,4 +1,49 @@
-The crypto module provides implementations of various cryptography-related
-standards.
+Important notice: Hare's cryptography implementations have not been audited. You
+can contribute to the funding of an independent audit of our cryptography
+implementation on OpenCollective:
-Be advised that Hare's cryptography implementations have not been audited.
+TODO: Add link
+
+The "crypto" module provides easy-to-use and hard-to-misuse functions for doing
+various high-level cryptographic operations. This is the recommended approach
+for most cryptographic applications. For applications which need them, direct
+access to supported cryptographic primitives is provided in submodules.
+
+Cryptography is a difficult, high-risk domain of programming. The life and
+well-being of your users may depend on your ability to implement cryptographic
+applications with due care. Please carefully read all of the documentation,
+double-check your work, and seek second opinions and independent review of your
+code. Our documentation and API design aims to prevent easy mistakes from being
+made, but it is no substitute for a good backround in applied cryptography. We
+recommend the "Crypto 101" course as a good general introduction to
+cryptography:
+
+https://www.crypto101.io
+
+There are a few additional modules and functions which are of interest to users
+of the crypto module. Access to secure random data is provided by the
+[[crypto::random]] module. The ability to securely erase sensitive data in RAM
+is provided by [[bytes::zero]]. Note also that [[bytes::equal]] is not suitable
+for constant-time comparisons; equality comparisons in a cryptographic context
+should utilize [[compare]] instead.
+
+TODO: Add something based on mlock to deal with storing sensitive information,
+and add a note here about it.
+
+We reserve the right to make breaking changes to this module in the future,
+which may prevent data prepared by old versions from being readable by new
+versions. Such changes will be accompanied with an increment of the major
+version of the standard library, as well as a changelog explaining what changes
+are required of downstream users, and a migration procedure will be prepared.
+The hare-announce mailing list is the appropriate way to be notified of these
+changes:
+
+https://lists.sr.ht/~sircmpwn/hare-announce
+
+The following features are offered in this module:
+
+- [[encrypt]] and [[decrypt]] provide authenticated encryption.
+- [[sign]] and [[verify]] provide public key message signing and verification.
+- [[exchange]] provides a secure key exchange function.
+- [[derivekey]] implements key derivation, which is also recommended for hashing passwords.
+- [[hash]] provides a [[hash::hash]] algorithm suitable for cryptographic use.
diff --git a/crypto/authenc.ha b/crypto/authenc.ha
@@ -0,0 +1,92 @@
+// A secret session key.
+export type sessionkey = [32]u8;
+
+// A value which is only used once.
+export type nonce = [24]u8;
+
+// A message authentication code.
+export type mac = [24]u8;
+
+// An encrypted, authenticated message.
+export type box = (mac, nonce, []u8);
+
+// Performs authenticated encryption on a message. The result may be
+// authenticated and decrypted with [[decrypt]].
+//
+// To use this function, you must first establish a session key which is shared
+// with both parties. This key must be random and secret. You may derive this
+// key with a key exchange (such as [[exchange]] or [[crypto::dh]]), or with a
+// key derivation function (such as [[derivekey]]), or by sharing it in person,
+// or some other, similar means which preserves the traits of randomness and
+// secrecy.
+//
+// You must also establish a unique nonce for each message, which you must not
+// reuse for any future messages using the same session key. It is recommended
+// to generate this randomly with [[crypto::random]].
+//
+// The plaintext parameter provides the message to encrypt. It will be
+// overwritten with the ciphertext. The buffer provided in the return value is
+// borrowed from this parameter.
+//
+// The optional 'additional' parameters provide additional data to be
+// authenticated with the same MAC. This data is not encrypted, but [[decrypt]]
+// will fail if it has been tampered with. The order of these arguments must be
+// consistent between [[encrypt]] and [[decrypt]].
+//
+// The return value contains all of the information which should be transmitted
+// to the other party, including the computed MAC, a copy of the nonce, and the
+// ciphertext. It is safe to transmit these values over an unsecured connection,
+// or to encode them with something like [[encoding::base64]].
+//
+// Any 'additional' data, if provided, is not included in the [[box]] type. The
+// user must provide for this data to be transmitted to the other party
+// themselves.
+//
+// let key: crypto::sessionkey = [0...];
+// let nonce: crypto::nonce = [0...];
+// random::buffer(key); // Or some other means of establishing the key
+// random::buffer(nonce);
+//
+// let buf: [64]u8 = [0...]; // Populate with your message
+// let box = crypto::encrypt(&key, &nonce, buf[..], buf[..]);
+//
+// // To decrypt this message:
+// let plaintext = match (crypto::decrypt(&key, &box, buf[..])) {
+// case let buf: []u8 =>
+// yield buf;
+// case errors::invalid =>
+// abort("Message authentication or decryption failed");
+// };
+//
+// The current implementation of this algorithm is based on RFC 8439, but uses
+// XChaCha20 instead of ChaCha20.
+export fn encrypt(
+ key: *sessionkey,
+ nonce: *nonce,
+ plaintext: []u8,
+ additional: []u8...
+) box;
+
+// Authenticates and decrypts a message encrypted with [[encrypt]]. If the
+// decryption is successful, the plaintext slice is returned, and if not,
+// [[errors::invalid]] is returned.
+//
+// The 'sessionkey' parameter is the shared key. The 'box' parameter is the
+// output of [[encrypt]]. If additional data should be authenticated, it may be
+// provided in the variadic 'additional' parameters.
+//
+// Note that the data is decrypted in-place, such that the box's ciphertext
+// becomes overwritten with the plaintext. The return value is borrowed from
+// this buffer. If decryption fails, this buffer will be zeroed, causing the
+// ciphertext to be destroyed as well. It is advised to zero the plaintext
+// buffer yourself after you are done using it, see [[bytes::zero]].
+//
+// See [[decrypt]] for the full details and a usage example.
+export fn decrypt(
+ key: *sessionkey,
+ box: *box,
+ additional: []u8...
+) ([]u8 | errors::invalid);
+
+// TODO: Add additional entry-points which provide a finer degree of control
+// over buffer usage.