bool key_from_base58(secp256k1_context *secpctx, const char *base58, size_t base58_len, bool *test_net, struct privkey *priv, struct pubkey *key) { // 1 byte version, 32 byte private key, 1 byte compressed, 4 byte checksum u8 keybuf[1 + 32 + 1 + 4]; size_t keybuflen = sizeof(keybuf); b58tobin(keybuf, &keybuflen, base58, base58_len); if (b58check(keybuf, sizeof(keybuf), base58, base58_len) < 0) return false; /* Byte after key should be 1 to represent a compressed key. */ if (keybuf[1 + 32] != 1) return false; if (keybuf[0] == 128) *test_net = false; else if (keybuf[0] == 239) *test_net = true; else return false; /* Copy out secret. */ memcpy(priv->secret, keybuf + 1, sizeof(priv->secret)); if (!secp256k1_ec_seckey_verify(secpctx, priv->secret)) return false; /* Get public key, too. */ if (!pubkey_from_privkey(secpctx, priv, key)) return false; return true; }
bool derive_basepoints(const struct secret *seed, struct pubkey *funding_pubkey, struct basepoints *basepoints, struct secrets *secrets, struct sha256 *shaseed) { struct keys { struct privkey f, r, h, p, d; struct sha256 shaseed; } keys; hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), "c-lightning", strlen("c-lightning")); if (secrets) { secrets->funding_privkey = keys.f; secrets->revocation_basepoint_secret = keys.r.secret; secrets->payment_basepoint_secret = keys.p.secret; secrets->htlc_basepoint_secret = keys.h.secret; secrets->delayed_payment_basepoint_secret = keys.d.secret; } if (funding_pubkey) { if (!pubkey_from_privkey(&keys.f, funding_pubkey)) return false; } if (basepoints) { if (!pubkey_from_privkey(&keys.r, &basepoints->revocation) || !pubkey_from_privkey(&keys.p, &basepoints->payment) || !pubkey_from_privkey(&keys.h, &basepoints->htlc) || !pubkey_from_privkey(&keys.d, &basepoints->delayed_payment)) return false; } /* BOLT #3: * * A node: * - MUST select an unguessable 256-bit seed for each connection, * - MUST NOT reveal the seed. */ if (shaseed) *shaseed = keys.shaseed; return true; }
bool key_from_base58(secp256k1_context *secpctx, const char *base58, size_t base58_len, bool *test_net, struct privkey *priv, struct pubkey *key) { u8 keybuf[1 + 32 + 1 + 4]; u8 csum[4]; BIGNUM bn; bool compressed; size_t keylen; BN_init(&bn); if (!raw_decode_base58(&bn, base58, base58_len)) return false; keylen = BN_num_bytes(&bn); if (keylen == 1 + 32 + 4) compressed = false; else if (keylen == 1 + 32 + 1 + 4) compressed = true; else goto fail_free_bn; BN_bn2bin(&bn, keybuf); base58_get_checksum(csum, keybuf, keylen - sizeof(csum)); if (memcmp(csum, keybuf + keylen - sizeof(csum), sizeof(csum)) != 0) goto fail_free_bn; /* Byte after key should be 1 to represent a compressed key. */ if (compressed && keybuf[1 + 32] != 1) goto fail_free_bn; if (keybuf[0] == 128) *test_net = false; else if (keybuf[0] == 239) *test_net = true; else goto fail_free_bn; /* Copy out secret. */ memcpy(priv->secret, keybuf + 1, sizeof(priv->secret)); if (!secp256k1_ec_seckey_verify(secpctx, priv->secret)) goto fail_free_bn; /* Get public key, too, since we know if it's compressed. */ if (!pubkey_from_privkey(secpctx, priv, key, compressed ? SECP256K1_EC_COMPRESSED : 0)) goto fail_free_bn; BN_free(&bn); return true; fail_free_bn: BN_free(&bn); return false; }
bool derive_funding_key(const struct secret *seed, struct pubkey *funding_pubkey, struct privkey *funding_privkey) { struct privkey f; hkdf_sha256(&f, sizeof(f), NULL, 0, seed, sizeof(*seed), "c-lightning", strlen("c-lightning")); if (funding_pubkey) { if (!pubkey_from_privkey(&f, funding_pubkey)) return false; } if (funding_privkey) *funding_privkey = f; return true; }
bool derive_payment_basepoint(const struct secret *seed, struct pubkey *payment_basepoint, struct secret *payment_secret) { struct keys { struct privkey f, r, h, p, d; struct sha256 shaseed; } keys; hkdf_sha256(&keys, sizeof(keys), NULL, 0, seed, sizeof(*seed), "c-lightning", strlen("c-lightning")); if (payment_basepoint) { if (!pubkey_from_privkey(&keys.p, payment_basepoint)) return false; } if (payment_secret) *payment_secret = keys.p.secret; return true; }
int sign_repo(struct xbps_handle *xhp, const char *repodir, const char *privkey, const char *signedby) { struct stat st; struct xbps_repo *repo; xbps_dictionary_t pkgd, meta = NULL; xbps_data_t data = NULL, rpubkey = NULL; xbps_object_iterator_t iter = NULL; xbps_object_t obj; RSA *rsa = NULL; unsigned char *sig; unsigned int siglen; uint16_t rpubkeysize, pubkeysize; const char *arch, *pkgver, *rsignedby = NULL; char *binpkg = NULL, *binpkg_sig = NULL, *buf = NULL, *defprivkey = NULL; int binpkg_fd, binpkg_sig_fd, rv = 0; bool flush = false; if (signedby == NULL) { fprintf(stderr, "--signedby unset! cannot sign repository\n"); return -1; } /* * Check that repository index exists and not empty, otherwise bail out. */ repo = xbps_repo_open(xhp, repodir, true); if (repo == NULL) { rv = errno; fprintf(stderr, "%s: cannot read repository data: %s\n", _XBPS_RINDEX, strerror(errno)); goto out; } if (xbps_dictionary_count(repo->idx) == 0) { fprintf(stderr, "%s: invalid repository, existing!\n", _XBPS_RINDEX); rv = EINVAL; goto out; } /* * If privkey not set, default to ~/.ssh/id_rsa. */ if (privkey == NULL) defprivkey = xbps_xasprintf("%s/.ssh/id_rsa", getenv("HOME")); else defprivkey = strdup(privkey); ERR_load_crypto_strings(); OpenSSL_add_all_algorithms(); OpenSSL_add_all_ciphers(); OpenSSL_add_all_digests(); if ((rsa = load_rsa_privkey(defprivkey)) == NULL) { fprintf(stderr, "%s: failed to read the RSA privkey\n", _XBPS_RINDEX); rv = EINVAL; goto out; } /* * Iterate over the idx dictionary and then sign all binary * packages in this repository. */ iter = xbps_dictionary_iterator(repo->idx); assert(iter); while ((obj = xbps_object_iterator_next(iter))) { pkgd = xbps_dictionary_get_keysym(repo->idx, obj); xbps_dictionary_get_cstring_nocopy(pkgd, "architecture", &arch); xbps_dictionary_get_cstring_nocopy(pkgd, "pkgver", &pkgver); binpkg = xbps_xasprintf("%s/%s.%s.xbps", repodir, pkgver, arch); binpkg_sig = xbps_xasprintf("%s.sig", binpkg); /* * Skip pkg if file signature exists */ if ((binpkg_sig_fd = access(binpkg_sig, R_OK)) == 0) { if (xhp->flags & XBPS_FLAG_VERBOSE) fprintf(stderr, "skipping %s, file signature found.\n", pkgver); free(binpkg); free(binpkg_sig); close(binpkg_sig_fd); continue; } /* * Generate pkg file signature. */ if ((binpkg_fd = open(binpkg, O_RDONLY)) == -1) { fprintf(stderr, "cannot read %s: %s\n", binpkg, strerror(errno)); free(binpkg); free(binpkg_sig); continue; } fstat(binpkg_fd, &st); buf = malloc(st.st_size); assert(buf); if (read(binpkg_fd, buf, st.st_size) != st.st_size) { fprintf(stderr, "failed to read %s: %s\n", binpkg, strerror(errno)); close(binpkg_fd); free(buf); free(binpkg); free(binpkg_sig); continue; } close(binpkg_fd); if (!rsa_sign_buf(rsa, buf, st.st_size, &sig, &siglen)) { fprintf(stderr, "failed to sign %s: %s\n", binpkg, strerror(errno)); free(buf); free(binpkg); free(binpkg_sig); continue; } free(buf); free(binpkg); /* * Write pkg file signature. */ binpkg_sig_fd = creat(binpkg_sig, 0644); if (binpkg_sig_fd == -1) { fprintf(stderr, "failed to create %s: %s\n", binpkg_sig, strerror(errno)); free(sig); free(binpkg_sig); continue; } if (write(binpkg_sig_fd, sig, siglen) != (ssize_t)siglen) { fprintf(stderr, "failed to write %s: %s\n", binpkg_sig, strerror(errno)); free(sig); free(binpkg_sig); close(binpkg_sig_fd); continue; } free(sig); free(binpkg_sig); close(binpkg_sig_fd); printf("signed successfully %s\n", pkgver); } xbps_object_iterator_release(iter); /* * Check if repository index-meta contains changes compared to its * current state. */ if ((buf = pubkey_from_privkey(rsa)) == NULL) { rv = EINVAL; goto out; } meta = xbps_dictionary_create(); data = xbps_data_create_data(buf, strlen(buf)); rpubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); if (!xbps_data_equals(rpubkey, data)) flush = true; free(buf); pubkeysize = RSA_size(rsa) * 8; xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &rpubkeysize); if (rpubkeysize != pubkeysize) flush = true; xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &rsignedby); if (rsignedby == NULL || strcmp(rsignedby, signedby)) flush = true; if (!flush) goto out; xbps_dictionary_set(meta, "public-key", data); xbps_dictionary_set_uint16(meta, "public-key-size", pubkeysize); xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby); xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa"); xbps_object_release(data); data = NULL; if (!repodata_flush(xhp, repodir, repo->idx, meta)) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); goto out; } printf("Signed repository (%u package%s)\n", xbps_dictionary_count(repo->idx), xbps_dictionary_count(repo->idx) == 1 ? "" : "s"); out: if (defprivkey) { free(defprivkey); } if (rsa) { RSA_free(rsa); rsa = NULL; } if (repo) { xbps_repo_close(repo); } return rv ? -1 : 0; }
int sign_repo(struct xbps_handle *xhp, const char *repodir, const char *privkey, const char *signedby) { struct xbps_repo *repo = NULL; xbps_dictionary_t meta = NULL; xbps_data_t data = NULL, rpubkey = NULL; RSA *rsa = NULL; uint16_t rpubkeysize, pubkeysize; const char *rsignedby = NULL; char *buf = NULL, *rlockfname = NULL; int rlockfd = -1, rv = 0; bool flush_failed = false, flush = false; if (signedby == NULL) { fprintf(stderr, "--signedby unset! cannot initialize signed repository\n"); return -1; } /* * Check that repository index exists and not empty, otherwise bail out. */ repo = xbps_repo_open(xhp, repodir); if (repo == NULL) { rv = errno; fprintf(stderr, "%s: cannot read repository data: %s\n", _XBPS_RINDEX, strerror(errno)); goto out; } if (xbps_dictionary_count(repo->idx) == 0) { fprintf(stderr, "%s: invalid repository, existing!\n", _XBPS_RINDEX); rv = EINVAL; goto out; } rsa = load_rsa_key(privkey); /* * Check if repository index-meta contains changes compared to its * current state. */ if ((buf = pubkey_from_privkey(rsa)) == NULL) { rv = EINVAL; goto out; } meta = xbps_dictionary_create(); data = xbps_data_create_data(buf, strlen(buf)); rpubkey = xbps_dictionary_get(repo->idxmeta, "public-key"); if (!xbps_data_equals(rpubkey, data)) flush = true; free(buf); pubkeysize = RSA_size(rsa) * 8; xbps_dictionary_get_uint16(repo->idxmeta, "public-key-size", &rpubkeysize); if (rpubkeysize != pubkeysize) flush = true; xbps_dictionary_get_cstring_nocopy(repo->idxmeta, "signature-by", &rsignedby); if (rsignedby == NULL || strcmp(rsignedby, signedby)) flush = true; if (!flush) goto out; xbps_dictionary_set(meta, "public-key", data); xbps_dictionary_set_uint16(meta, "public-key-size", pubkeysize); xbps_dictionary_set_cstring_nocopy(meta, "signature-by", signedby); xbps_dictionary_set_cstring_nocopy(meta, "signature-type", "rsa"); xbps_object_release(data); data = NULL; /* lock repository to write repodata file */ if (!xbps_repo_lock(xhp, repodir, &rlockfd, &rlockfname)) { rv = errno; fprintf(stderr, "%s: cannot lock repository: %s\n", _XBPS_RINDEX, strerror(errno)); goto out; } flush_failed = repodata_flush(xhp, repodir, repo->idx, meta); xbps_repo_unlock(rlockfd, rlockfname); if (!flush_failed) { fprintf(stderr, "failed to write repodata: %s\n", strerror(errno)); goto out; } printf("Initialized signed repository (%u package%s)\n", xbps_dictionary_count(repo->idx), xbps_dictionary_count(repo->idx) == 1 ? "" : "s"); out: if (rsa) { RSA_free(rsa); rsa = NULL; } if (repo) xbps_repo_close(repo); return rv ? -1 : 0; }
int main(void) { setup_locale(); struct privkey privkey; struct secret base_secret, per_commitment_secret; struct pubkey base_point, per_commitment_point, pubkey, pubkey2; setup_tmpctx(); secp256k1_ctx = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY | SECP256K1_CONTEXT_SIGN); base_secret = secret_from_hex("0x000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"); per_commitment_secret = secret_from_hex("0x1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100"); printf("base_secret: 0x%s\n", tal_hexstr(tmpctx, &base_secret, sizeof(base_secret))); printf("per_commitment_secret: 0x%s\n", tal_hexstr(tmpctx, &per_commitment_secret, sizeof(per_commitment_secret))); if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &per_commitment_point.pubkey, per_commitment_secret.data)) abort(); if (!secp256k1_ec_pubkey_create(secp256k1_ctx, &base_point.pubkey, base_secret.data)) abort(); printf("base_point: 0x%s\n", type_to_string(tmpctx, struct pubkey, &base_point)); printf("per_commitment_point: 0x%s\n", type_to_string(tmpctx, struct pubkey, &per_commitment_point)); /* FIXME: Annotate internal steps. */ if (!derive_simple_key(&base_point, &per_commitment_point, &pubkey)) abort(); printf("localkey: 0x%s\n", type_to_string(tmpctx, struct pubkey, &pubkey)); if (!derive_simple_privkey(&base_secret, &base_point, &per_commitment_point, &privkey)) abort(); printf("localprivkey: 0x%s\n", tal_hexstr(tmpctx, &privkey, sizeof(privkey))); pubkey_from_privkey(&privkey, &pubkey2); assert(pubkey_eq(&pubkey, &pubkey2)); /* FIXME: Annotate internal steps. */ if (!derive_revocation_key(&base_point, &per_commitment_point, &pubkey)) abort(); printf("revocationkey: 0x%s\n", type_to_string(tmpctx, struct pubkey, &pubkey)); if (!derive_revocation_privkey(&base_secret, &per_commitment_secret, &base_point, &per_commitment_point, &privkey)) abort(); printf("revocationprivkey: 0x%s\n", tal_hexstr(tmpctx, &privkey, sizeof(privkey))); pubkey_from_privkey(&privkey, &pubkey2); assert(pubkey_eq(&pubkey, &pubkey2)); /* No memory leaks please */ secp256k1_context_destroy(secp256k1_ctx); tal_free(tmpctx); return 0; }