commando.html5/node_modules/lnsocket/crypto.c

240 lines
6.9 KiB
C

/* Copyright Rusty Russell (Blockstream) 2015.
William Casarin 2022
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include "config.h"
#include "crypto.h"
#include "endian.h"
#include "typedefs.h"
#include "compiler.h"
#include "hkdf.h"
#include <assert.h>
#include <sodium/crypto_aead_chacha20poly1305.h>
void le64_nonce(unsigned char *npub, u64 nonce)
{
/* BOLT #8:
*
* ...with nonce `n` encoded as 32 zero bits, followed by a
* *little-endian* 64-bit value. Note: this follows the Noise Protocol
* convention, rather than our normal endian
*/
le64 le_nonce = cpu_to_le64(nonce);
const size_t zerolen = crypto_aead_chacha20poly1305_ietf_NPUBBYTES - sizeof(le_nonce);
BUILD_ASSERT(crypto_aead_chacha20poly1305_ietf_NPUBBYTES >= sizeof(le_nonce));
/* First part is 0, followed by nonce. */
memset(npub, 0, zerolen);
memcpy(npub + zerolen, &le_nonce, sizeof(le_nonce));
}
/* out1, out2 = HKDF(in1, in2)` */
void hkdf_two_keys(struct secret *out1, struct secret *out2,
const struct secret *in1,
const struct secret *in2)
{
/* BOLT #8:
*
* * `HKDF(salt,ikm)`: a function defined in `RFC 5869`<sup>[3](#reference-3)</sup>,
* evaluated with a zero-length `info` field
* * All invocations of `HKDF` implicitly return 64 bytes
* of cryptographic randomness using the extract-and-expand
* component of the `HKDF`.
*/
struct secret okm[2];
size_t in2_size = in2 == NULL ? 0 : sizeof(*in2);
hkdf_sha256(okm, sizeof(okm), in1, sizeof(*in1), in2, in2_size,
NULL, 0);
*out1 = okm[0];
*out2 = okm[1];
}
static void maybe_rotate_key(u64 *n, struct secret *k, struct secret *ck)
{
struct secret new_k, new_ck;
/* BOLT #8:
*
* A key is to be rotated after a party encrypts or decrypts 1000 times
* with it (i.e. every 500 messages). This can be properly accounted
* for by rotating the key once the nonce dedicated to it
* exceeds 1000.
*/
if (*n != 1000)
return;
/* BOLT #8:
*
* Key rotation for a key `k` is performed according to the following
* steps:
*
* 1. Let `ck` be the chaining key obtained at the end of Act Three.
* 2. `ck', k' = HKDF(ck, k)`
* 3. Reset the nonce for the key to `n = 0`.
* 4. `k = k'`
* 5. `ck = ck'`
*/
hkdf_two_keys(&new_ck, &new_k, ck, k);
*ck = new_ck;
*k = new_k;
*n = 0;
}
int cryptomsg_decrypt_body(struct crypto_state *cs, const u8 *in, size_t inlen, u8 *out, size_t outcap)
{
unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
unsigned long long mlen;
if (inlen < 16 || outcap < cryptomsg_decrypt_size(inlen))
return 0;
le64_nonce(npub, cs->rn++);
/* BOLT #8:
*
* 5. Decrypt `c` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to
* obtain decrypted plaintext packet `p`.
* * The nonce `rn` MUST be incremented after this step.
*/
if (crypto_aead_chacha20poly1305_ietf_decrypt(out,
&mlen, NULL,
memcheck(in, inlen),
inlen,
NULL, 0,
npub, cs->rk.data) != 0) {
/* FIXME: Report error! */
return 0;
}
assert(mlen == cryptomsg_decrypt_size(inlen));
maybe_rotate_key(&cs->rn, &cs->rk, &cs->r_ck);
return 1;
}
int cryptomsg_decrypt_header(struct crypto_state *cs, u8 hdr[18], u16 *lenp)
{
unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
unsigned long long mlen;
be16 len;
le64_nonce(npub, cs->rn++);
/* BOLT #8:
*
* 2. Let the encrypted length prefix be known as `lc`.
* 3. Decrypt `lc` (using `ChaCha20-Poly1305`, `rn`, and `rk`), to
* obtain the size of the encrypted packet `l`.
* * A zero-length byte slice is to be passed as the AD
* (associated data).
* * The nonce `rn` MUST be incremented after this step.
*/
if (crypto_aead_chacha20poly1305_ietf_decrypt((unsigned char *)&len,
&mlen, NULL,
memcheck(hdr, 18), 18,
NULL, 0,
npub, cs->rk.data) != 0) {
return 0;
}
assert(mlen == sizeof(len));
*lenp = be16_to_cpu(len);
return 1;
}
u8 *cryptomsg_encrypt_msg(struct crypto_state *cs, const u8 *msg, unsigned long long mlen, u8 *out, size_t *outlen, size_t outcap)
{
unsigned char npub[crypto_aead_chacha20poly1305_ietf_NPUBBYTES];
unsigned long long clen;
be16 l;
int ret;
*outlen = sizeof(l) + 16 + mlen + 16;
if (outcap < mlen) {
*outlen = 0;
return NULL;
}
/* BOLT #8:
*
* In order to encrypt and send a Lightning message (`m`) to the
* network stream, given a sending key (`sk`) and a nonce (`sn`), the
* following steps are completed:
*
* 1. Let `l = len(m)`.
* * where `len` obtains the length in bytes of the Lightning
* message
*
* 2. Serialize `l` into 2 bytes encoded as a big-endian integer.
*/
l = cpu_to_be16(mlen);
/* BOLT #8:
*
* 3. Encrypt `l` (using `ChaChaPoly-1305`, `sn`, and `sk`), to obtain
* `lc` (18 bytes)
* * The nonce `sn` is encoded as a 96-bit little-endian number. As
* the decoded nonce is 64 bits, the 96-bit nonce is encoded as:
* 32 bits of leading 0s followed by a 64-bit value.
* * The nonce `sn` MUST be incremented after this step.
* * A zero-length byte slice is to be passed as the AD (associated
data).
*/
le64_nonce(npub, cs->sn++);
ret = crypto_aead_chacha20poly1305_ietf_encrypt(out, &clen,
(unsigned char *)
memcheck(&l, sizeof(l)),
sizeof(l),
NULL, 0,
NULL, npub,
cs->sk.data);
assert(ret == 0);
assert(clen == sizeof(l) + 16);
/* BOLT #8:
*
* 4. Finally, encrypt the message itself (`m`) using the same
* procedure used to encrypt the length prefix. Let
* encrypted ciphertext be known as `c`.
*
* * The nonce `sn` MUST be incremented after this step.
*/
le64_nonce(npub, cs->sn++);
ret = crypto_aead_chacha20poly1305_ietf_encrypt(out + clen, &clen,
memcheck(msg, mlen),
mlen,
NULL, 0,
NULL, npub,
cs->sk.data);
assert(ret == 0);
assert(clen == mlen + 16);
maybe_rotate_key(&cs->sn, &cs->sk, &cs->s_ck);
return out;
}