The Hare programming language
git clone https://git.torresjrjr.com/hare.git
Log | Files | Refs | README | LICENSE

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>

Mcrypto/README | 51++++++++++++++++++++++++++++++++++++++++++++++++---
Acrypto/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.