BCW_API hd_private_key::hd_private_key(const data_chunk& seed, bool testnet) : hd_public_key() { std::string key("Bitcoin seed"); split_long_hash I = split(hmac_sha512_hash(seed, to_data_chunk(key))); // The key is invalid if parse256(IL) >= n or 0: if (!verify_private_key(I.L)) return; auto lineage = hd_key_lineage{testnet, 0, 0, 0}; *this = hd_private_key(I.L, I.R, lineage); }
data_chunk sign(ec_secret secret, hash_digest hash, ec_secret nonce) { std::reverse(hash.begin(), hash.end()); init.init(); int out_size = 72; data_chunk signature(out_size); if (!verify_private_key(nonce)) // Needed because of upstream bug return data_chunk(); bool valid = secp256k1_ecdsa_sign(hash.data(), hash.size(), signature.data(), &out_size, secret.data(), nonce.data()) == 1; if (!valid) return data_chunk(); signature.resize(out_size); return signature; }
BC_API ec_secret create_nonce(ec_secret secret, hash_digest hash) { std::reverse(hash.begin(), hash.end()); init.init(); hash_digest K {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }}; hash_digest V {{ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 }}; K = hmac_sha256_hash(V + byte_array<1>{{0x00}} + secret + hash, K); V = hmac_sha256_hash(V, K); K = hmac_sha256_hash(V + byte_array<1>{{0x01}} + secret + hash, K); V = hmac_sha256_hash(V, K); while (true) { V = hmac_sha256_hash(V, K); if (verify_private_key(V)) return V; K = hmac_sha256_hash(V + byte_array<1>{{0x00}}, K); V = hmac_sha256_hash(V, K); } }
/* parse_cryptserv_args() * * inputs - parv parameters * - parc count * - info string (to be filled in by this routine) * - key (to be filled in by this routine) * output - NULL if invalid params, server name otherwise * side effects - parv[2] is trimmed to HOSTLEN size if needed. */ static char * parse_cryptserv_args(struct Client *client_p, char *parv[], int parc, char *info, char *key) { char *name; unsigned char *tmp, *out; int len; int decoded_len; info[0] = '\0'; name = parv[2]; /* parv[2] contains encrypted auth data */ if (!(decoded_len = unbase64_block(&tmp, parv[3], strlen(parv[3])))) { cryptlink_error(client_p, "SERV", "Couldn't base64 decode data", NULL); return(NULL); } if (verify_private_key() == -1) { sendto_realops_flags(UMODE_ALL, L_ADMIN, "verify_private_key() returned -1. Check log for information."); } if (ServerInfo.rsa_private_key == NULL) { cryptlink_error(client_p, "SERV", "No local private key found", NULL); return(NULL); } out = MyMalloc(RSA_size(ServerInfo.rsa_private_key)); len = RSA_private_decrypt(decoded_len, tmp, out, ServerInfo.rsa_private_key, RSA_PKCS1_PADDING); MyFree(tmp); if (len < CIPHERKEYLEN) { report_crypto_errors(); if (len < 0) { cryptlink_error(client_p, "AUTH", "Decryption failed", NULL); } else { cryptlink_error(client_p, "AUTH", "Not enough random data sent", NULL); } MyFree(out); return(NULL); } memcpy(key, out, CIPHERKEYLEN); MyFree(out); strlcpy(info, parv[4], REALLEN + 1); if (strlen(name) > HOSTLEN) name[HOSTLEN] = '\0'; return(name); }
/* * cryptlink_auth - CRYPTLINK AUTH message handler * parv[1] = secret key */ static void cryptlink_auth(struct Client *client_p, struct Client *source_p, int parc, char *parv[]) { struct EncCapability *ecap; struct ConfItem *conf; struct AccessItem *aconf; int enc_len; int len; unsigned char *enc; unsigned char *key; if (parc < 4) { cryptlink_error(client_p, "AUTH", "Invalid params", "CRYPTLINK AUTH - Invalid params"); return; } if (!IsWaitAuth(client_p)) return; for (ecap = CipherTable; ecap->name; ecap++) { if ((!irccmp(ecap->name, parv[2])) && (IsCapableEnc(client_p, ecap->cap))) { client_p->localClient->in_cipher = ecap; break; } } if (client_p->localClient->in_cipher == NULL) { cryptlink_error(client_p, "AUTH", "Invalid cipher", "Invalid cipher"); return; } if (!(enc_len = unbase64_block(&enc, parv[3], strlen(parv[3])))) { cryptlink_error(client_p, "AUTH", "Could not base64 decode response", "Malformed CRYPTLINK AUTH reply"); return; } if (verify_private_key() == -1) { sendto_realops_flags(UMODE_ALL, L_ADMIN, "verify_private_key() returned -1. Check log for information."); } key = MyMalloc(RSA_size(ServerInfo.rsa_private_key)); len = RSA_private_decrypt(enc_len, (unsigned char *)enc,(unsigned char *)key, ServerInfo.rsa_private_key, RSA_PKCS1_PADDING); if (len < client_p->localClient->in_cipher->keylen) { report_crypto_errors(); if (len < 0) { cryptlink_error(client_p, "AUTH", "Decryption failed", "Malformed CRYPTLINK AUTH reply"); } else { cryptlink_error(client_p, "AUTH", "Not enough random data sent", "Malformed CRYPTLINK AUTH reply"); } MyFree(enc); MyFree(key); return; } if (memcmp(key, client_p->localClient->in_key, client_p->localClient->in_cipher->keylen) != 0) { cryptlink_error(client_p, "AUTH", "Unauthorized server connection attempt", "Malformed CRYPTLINK AUTH reply"); return; } conf = find_conf_name(&client_p->localClient->confs, client_p->name, SERVER_TYPE); if (conf == NULL) { cryptlink_error(client_p, "AUTH", "Lost C-line for server", "Lost C-line"); return; } aconf = (struct AccessItem *)map_to_conf(conf); if (!(client_p->localClient->out_cipher || (client_p->localClient->out_cipher = check_cipher(client_p, aconf)))) { cryptlink_error(client_p, "AUTH", "Couldn't find compatible cipher", "Couldn't find compatible cipher"); return; } /* set hopcount */ client_p->hopcount = 1; SetCryptIn(client_p); ClearWaitAuth(client_p); server_estab(client_p); }