239 lines
6.9 KiB
C
239 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;
|
|
}
|