mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
lightningd: new internal JSONRPC "decryptencrypteddata"
I'm not sure about interface yet, so don't document. It's ugly. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
e8b959ac77
commit
de0d371d20
@ -156,10 +156,10 @@ bool unblind_onion(const struct pubkey *blinding,
|
||||
hmac.data) == 1;
|
||||
}
|
||||
|
||||
static u8 *decrypt_encmsg_raw(const tal_t *ctx,
|
||||
const struct pubkey *blinding,
|
||||
const struct secret *ss,
|
||||
const u8 *enctlv)
|
||||
u8 *decrypt_encmsg_raw(const tal_t *ctx,
|
||||
const struct pubkey *blinding,
|
||||
const struct secret *ss,
|
||||
const u8 *enctlv)
|
||||
{
|
||||
struct secret rho;
|
||||
u8 *dec;
|
||||
@ -253,7 +253,9 @@ void blindedpath_next_blinding(const struct tlv_encrypted_data_tlv *enc,
|
||||
if (enc->next_blinding_override)
|
||||
*next_blinding = *enc->next_blinding_override;
|
||||
else {
|
||||
/* E_{i-1} = H(E_i || ss_i) * E_i */
|
||||
/* BOLT #4:
|
||||
* $`E_{i+1} = SHA256(E_i || ss_i) * E_i`$
|
||||
*/
|
||||
struct sha256 h;
|
||||
blinding_hash_e_and_ss(blinding, ss, &h);
|
||||
blinding_next_pubkey(blinding, &h, next_blinding);
|
||||
|
@ -76,6 +76,12 @@ struct tlv_encrypted_data_tlv *decrypt_encrypted_data(const tal_t *ctx,
|
||||
const u8 *enctlv)
|
||||
NON_NULL_ARGS(2, 3);
|
||||
|
||||
/* Low-level accessor */
|
||||
u8 *decrypt_encmsg_raw(const tal_t *ctx,
|
||||
const struct pubkey *blinding,
|
||||
const struct secret *ss,
|
||||
const u8 *enctlv);
|
||||
|
||||
/**
|
||||
* blindedpath_next_blinding - Calculate or extract next blinding pubkey
|
||||
*/
|
||||
|
@ -1,7 +1,9 @@
|
||||
#include "config.h"
|
||||
#include <ccan/mem/mem.h>
|
||||
#include <common/blindedpath.h>
|
||||
#include <common/blinding.h>
|
||||
#include <common/configdir.h>
|
||||
#include <common/ecdh.h>
|
||||
#include <common/json_command.h>
|
||||
#include <common/json_param.h>
|
||||
#include <connectd/connectd_wiregen.h>
|
||||
@ -328,3 +330,60 @@ static const struct json_command injectonionmessage_command = {
|
||||
"Unwrap using {blinding}, encoded over {hops} (id, tlv)"
|
||||
};
|
||||
AUTODATA(json_command, &injectonionmessage_command);
|
||||
|
||||
static struct command_result *json_decryptencrypteddata(struct command *cmd,
|
||||
const char *buffer,
|
||||
const jsmntok_t *obj UNNEEDED,
|
||||
const jsmntok_t *params)
|
||||
{
|
||||
u8 *encdata, *decrypted;
|
||||
struct pubkey *blinding, next_blinding;
|
||||
struct secret ss;
|
||||
struct sha256 h;
|
||||
struct json_stream *response;
|
||||
|
||||
if (!param_check(cmd, buffer, params,
|
||||
p_req("encrypted_data", param_bin_from_hex, &encdata),
|
||||
p_req("blinding", param_pubkey, &blinding),
|
||||
NULL))
|
||||
return command_param_failed();
|
||||
|
||||
/* BOLT #4:
|
||||
*
|
||||
* - MUST compute:
|
||||
* - $`ss_i = SHA256(k_i * E_i)`$ (standard ECDH)
|
||||
*...
|
||||
* - MUST decrypt the `encrypted_data` field using $`rho_i`$
|
||||
*/
|
||||
ecdh(blinding, &ss);
|
||||
|
||||
decrypted = decrypt_encmsg_raw(cmd, blinding, &ss, encdata);
|
||||
if (!decrypted)
|
||||
return command_fail(cmd, JSONRPC2_INVALID_PARAMS,
|
||||
"Decryption failed!");
|
||||
|
||||
if (command_check_only(cmd))
|
||||
return command_check_done(cmd);
|
||||
|
||||
/* BOLT #4:
|
||||
*
|
||||
* - $`E_{i+1} = SHA256(E_i || ss_i) * E_i`$
|
||||
*/
|
||||
blinding_hash_e_and_ss(blinding, &ss, &h);
|
||||
blinding_next_pubkey(blinding, &h, &next_blinding);
|
||||
|
||||
response = json_stream_success(cmd);
|
||||
json_object_start(response, "decryptencrypteddata");
|
||||
json_add_hex_talarr(response, "decrypted", decrypted);
|
||||
json_add_pubkey(response, "next_blinding", &next_blinding);
|
||||
json_object_end(response);
|
||||
return command_success(cmd, response);
|
||||
}
|
||||
|
||||
static const struct json_command decryptencrypteddata_command = {
|
||||
"decryptencrypteddata",
|
||||
"utility",
|
||||
json_decryptencrypteddata,
|
||||
"Decrypt {encrypted_data} using {blinding}, return decryption and next blinding"
|
||||
};
|
||||
AUTODATA(json_command, &decryptencrypteddata_command);
|
||||
|
@ -5782,6 +5782,36 @@ def test_onionmessage_ratelimit(node_factory):
|
||||
l1.rpc.fetchinvoice(offer['bolt12'])
|
||||
|
||||
|
||||
def test_decryptencrypteddata(node_factory):
|
||||
l1, l2, l3 = node_factory.line_graph(3, fundchannel=False,
|
||||
opts={'experimental-offers': None})
|
||||
|
||||
# Private channel from l2->l3, makes l3 add a blinded path to invoice
|
||||
# (l1's existence makes sure l3 doesn't see l2 as a dead end!)
|
||||
node_factory.join_nodes([l1, l2], wait_for_announce=True)
|
||||
node_factory.join_nodes([l2, l3], announce_channels=False)
|
||||
wait_for(lambda: ['alias' in n for n in l3.rpc.listnodes()['nodes']] == [True, True])
|
||||
|
||||
offer = l3.rpc.offer(amount='2msat', description='test_offer_path_self')
|
||||
inv = l2.rpc.fetchinvoice(offer['bolt12'])['invoice']
|
||||
|
||||
decode = l2.rpc.decode(inv)
|
||||
path = decode['invoice_paths'][0]
|
||||
assert path['first_node_id'] == l2.info['id']
|
||||
blinding = path['blinding']
|
||||
|
||||
encdata1 = path['path'][0]['encrypted_recipient_data']
|
||||
# BOLT #4:
|
||||
# 1. `tlv_stream`: `encrypted_data_tlv`
|
||||
# 2. types:
|
||||
# ...
|
||||
# 1. type: 4 (`next_node_id`)
|
||||
# 2. data:
|
||||
# * [`point`:`node_id`]
|
||||
dec = l2.rpc.decryptencrypteddata(encrypted_data=encdata1, blinding=blinding)['decryptencrypteddata']
|
||||
assert dec['decrypted'].startswith('0421' + l3.info['id'])
|
||||
|
||||
|
||||
def test_fetch_no_description_offer(node_factory):
|
||||
"""Reproducing the issue: https://github.com/ElementsProject/lightning/issues/7405"""
|
||||
l1, l2 = node_factory.line_graph(2, opts={'experimental-offers': None,
|
||||
|
Loading…
Reference in New Issue
Block a user