hare

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

authenc.ha (4918B)


      1 // SPDX-License-Identifier: MPL-2.0
      2 // (c) Hare authors <https://harelang.org>
      3 
      4 use bytes;
      5 use crypto::chachapoly;
      6 use crypto::math;
      7 use errors;
      8 use io;
      9 use memio;
     10 
     11 // A secret session key.
     12 export type sessionkey = [32]u8;
     13 
     14 // A value which is only used once.
     15 export type nonce = [24]u8;
     16 
     17 // A message authentication code.
     18 export type mac = [16]u8;
     19 
     20 // An encrypted, authenticated message.
     21 export type box = (mac, nonce, []u8);
     22 
     23 // Performs authenticated encryption on a message. The result may be
     24 // authenticated and decrypted with [[decrypt]].
     25 //
     26 // To use this function, you must first establish a session key which is shared
     27 // with both parties. This key must be random and secret. You may derive this
     28 // key with a key exchange (such as [[exchange]] or [[dh]]), or with a key
     29 // derivation function (such as [[derivekey]]), or by sharing it in person, or
     30 // some other, similar means which preserves the traits of randomness and
     31 // secrecy.
     32 //
     33 // You must also establish a unique nonce for each message, which you must not
     34 // reuse for any future messages using the same session key. It is recommended
     35 // to generate this randomly with [[crypto::random::]].
     36 //
     37 // The plaintext parameter provides the message to encrypt. It will be
     38 // overwritten with the ciphertext. The buffer provided in the return value is
     39 // borrowed from this parameter.
     40 //
     41 // The optional 'additional' parameters provide additional data to be
     42 // authenticated with the same MAC. This data is not encrypted, but [[decrypt]]
     43 // will fail if it has been tampered with. The order of these arguments must be
     44 // consistent between [[encrypt]] and [[decrypt]].
     45 //
     46 // The return value contains all of the information which should be transmitted
     47 // to the other party, including the computed MAC, a copy of the nonce, and the
     48 // ciphertext. It is safe to transmit these values over an unsecured connection,
     49 // or to encode them with something like [[encoding::base64::]].
     50 //
     51 // Any 'additional' data, if provided, is not included in the [[box]] type. The
     52 // user must provide for this data to be transmitted to the other party
     53 // themselves.
     54 //
     55 // 	let key: crypto::sessionkey = [0...];
     56 // 	let nonce: crypto::nonce = [0...];
     57 // 	random::buffer(key); // Or some other means of establishing the key
     58 // 	random::buffer(nonce);
     59 //
     60 // 	let buf: [64]u8 = [0...]; // Populate with your message
     61 // 	let box = crypto::encrypt(&key, &nonce, buf[..], buf[..]);
     62 //
     63 //	// To decrypt this message:
     64 // 	let plaintext = match (crypto::decrypt(&key, &box, buf[..])) {
     65 // 	case let buf: []u8 =>
     66 // 		yield buf;
     67 // 	case errors::invalid =>
     68 // 		abort("Message authentication or decryption failed");
     69 // 	};
     70 //
     71 // The current implementation of this algorithm is based on RFC 8439, but uses
     72 // XChaCha20 instead of ChaCha20.
     73 export fn encrypt(
     74 	key: *sessionkey,
     75 	nonce: *nonce,
     76 	plaintext: []u8,
     77 	additional: []u8...
     78 ) box = {
     79 	let s = chachapoly::chachapoly();
     80 	defer io::close(&s)!;
     81 
     82 	let h = memio::fixed(plaintext);
     83 	chachapoly::xinit(&s, &h, key, nonce, additional...);
     84 	io::writeall(&s, plaintext)!;
     85 	let m: mac = [0...];
     86 	chachapoly::seal(&s, m);
     87 	return (m, *nonce, memio::buffer(&h));
     88 };
     89 
     90 // Authenticates and decrypts a message encrypted with [[encrypt]]. If the
     91 // decryption is successful, the plaintext slice is returned, and if not,
     92 // [[errors::invalid]] is returned.
     93 //
     94 // The 'sessionkey' parameter is the shared key. The 'box' parameter is the
     95 // output of [[encrypt]]. If additional data should be authenticated, it may be
     96 // provided in the variadic 'additional' parameters.
     97 //
     98 // Note that the data is decrypted in-place, such that the box's ciphertext
     99 // becomes overwritten with the plaintext. The return value is borrowed from
    100 // this buffer. If decryption fails, this buffer will be zeroed, causing the
    101 // ciphertext to be destroyed as well. It is advised to zero the plaintext
    102 // buffer yourself after you are done using it, see [[bytes::zero]].
    103 //
    104 // See [[decrypt]] for the full details and a usage example.
    105 export fn decrypt(
    106 	key: *sessionkey,
    107 	box: *box,
    108 	additional: []u8...
    109 ) ([]u8 | errors::invalid) = {
    110 	let s = chachapoly::chachapoly();
    111 	defer io::close(&s)!;
    112 
    113 	let ciphertext = box.2;
    114 	let h = memio::fixed(ciphertext);
    115 	chachapoly::xinit(&s, &h, key, box.1, additional...);
    116 
    117 	let plaintext = ciphertext;
    118 	io::readall(&s, plaintext)!;
    119 
    120 	if (chachapoly::verify(&s, box.0) is errors::invalid) {
    121 		bytes::zero(plaintext);
    122 		return errors::invalid;
    123 	};
    124 	return plaintext;
    125 };
    126 
    127 // Compares two slices and returns true if they are equal. Comparison is done
    128 // in constant time, meaning that, if the slices have equal length, the time it
    129 // takes depends only on the length of the slices and not the content.
    130 export fn compare(a: []u8, b: []u8) bool = {
    131 	if (len(a) != len(b)) {
    132 		return false;
    133 	};
    134 
    135 	return math::eqslice(a, b) == 1;
    136 };
    137 
    138 // TODO: Add additional entry-points which provide a finer degree of control
    139 // over buffer usage.