SODIUM_EXPORT int crypto_sign_ed25519_ref_open(unsigned char *m, unsigned long long *mlen, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { return crypto_sign_ed25519_open(m, mlen, sm, smlen, pk); }
int crypto_sign_open(unsigned char *m, unsigned long long *mlen_p, const unsigned char *sm, unsigned long long smlen, const unsigned char *pk) { return crypto_sign_ed25519_open(m, mlen_p, sm, smlen, pk); }
int Sign_verifyMsg(uint8_t publicSigningKey[32], struct Message* msg) { if (msg->length < 64) { return -1; } struct Allocator* alloc = Allocator_child(msg->alloc); uint8_t* buff = Allocator_malloc(alloc, msg->length); unsigned long long ml = msg->length; int ret = crypto_sign_ed25519_open(buff, &ml, msg->bytes, msg->length, publicSigningKey); Allocator_free(alloc); if (ret) { return -1; } Message_pop(msg, NULL, 64, NULL); return 0; }
static int cert_open_bincert(ProxyContext * const proxy_context, const SignedBincert * const signed_bincert, const size_t signed_bincert_len, Bincert ** const bincert_p) { Bincert *bincert; unsigned long long bincert_data_len_ul; size_t bincert_size; size_t signed_data_len; if (cert_parse_version(proxy_context, signed_bincert, signed_bincert_len) != 0) { DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION(); return -1; } bincert_size = signed_bincert_len; if ((bincert = malloc(bincert_size)) == NULL) { DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_COMMUNICATION(); return -1; } assert(signed_bincert_len >= (size_t) (signed_bincert->signed_data - signed_bincert->magic_cert)); signed_data_len = signed_bincert_len - (size_t) (signed_bincert->signed_data - signed_bincert->magic_cert); assert(bincert_size - (size_t) (bincert->server_publickey - bincert->magic_cert) == signed_data_len); if (crypto_sign_ed25519_open(bincert->server_publickey, &bincert_data_len_ul, signed_bincert->signed_data, signed_data_len, proxy_context->provider_publickey) != 0) { free(bincert); logger_noformat(proxy_context, LOG_ERR, "Suspicious certificate received"); DNSCRYPT_PROXY_CERTS_UPDATE_ERROR_SECURITY(); return -1; } if (cert_parse_bincert(proxy_context, bincert, *bincert_p) != 0) { memset(bincert, 0, sizeof *bincert); free(bincert); return -1; } if (*bincert_p != NULL) { memset(*bincert_p, 0, sizeof **bincert_p); free(*bincert_p); } *bincert_p = bincert; return 0; }
int pki_ed25519_verify(const ssh_key pubkey, ssh_signature sig, const unsigned char *hash, size_t hlen) { unsigned long long mlen = 0; uint8_t *buffer; uint8_t *buffer2; int rc; if (pubkey == NULL || sig == NULL || hash == NULL || sig->ed25519_sig == NULL) { return SSH_ERROR; } buffer = malloc(hlen + ED25519_SIG_LEN); if (buffer == NULL) { return SSH_ERROR; } buffer2 = malloc(hlen + ED25519_SIG_LEN); if (buffer2 == NULL) { goto error; } memcpy(buffer, sig->ed25519_sig, ED25519_SIG_LEN); memcpy(buffer + ED25519_SIG_LEN, hash, hlen); rc = crypto_sign_ed25519_open(buffer2, &mlen, buffer, hlen + ED25519_SIG_LEN, *pubkey->ed25519_pubkey); BURN_BUFFER(buffer, hlen + ED25519_SIG_LEN); BURN_BUFFER(buffer2, hlen); SAFE_FREE(buffer); SAFE_FREE(buffer2); if (rc == 0) { return SSH_OK; } else { return SSH_ERROR; } error: SAFE_FREE(buffer); SAFE_FREE(buffer2); return SSH_ERROR; }
/* * wrapper around crypto_sign_open supporting detached signatures */ static void verifymsg(struct pubkey *pubkey, uint8_t *msg, unsigned long long msglen, struct sig *sig, int quiet) { uint8_t *sigbuf, *dummybuf; unsigned long long siglen, dummylen; if (memcmp(pubkey->fingerprint, sig->fingerprint, FPLEN) != 0) errx(1, "verification failed: checked against wrong key"); siglen = SIGBYTES + msglen; sigbuf = xmalloc(siglen); dummybuf = xmalloc(siglen); memcpy(sigbuf, sig->sig, SIGBYTES); memcpy(sigbuf + SIGBYTES, msg, msglen); if (crypto_sign_ed25519_open(dummybuf, &dummylen, sigbuf, siglen, pubkey->sigkey) == -1) errx(1, "signature verification failed"); if (!quiet) printf("Signature Verified\n"); free(sigbuf); free(dummybuf); }
static int ssh_ed25519_verify(Key *key, unsigned char *signature, unsigned int signaturelen, unsigned char *data, unsigned int datalen) { buffer_t *b; char *ktype = NULL; unsigned char *sigblob = NULL, *sm = NULL, *m = NULL; unsigned int len; unsigned long long smlen, mlen; int rlen, ret; char *bptr; ret = -1; b = buffer_init(); if (b == NULL) goto error; buffer_append(b, signature, signaturelen); bptr = buffer_ptr(b); ktype = buffer_get_string(&bptr, NULL); if (strcmp("ssh-ed25519", ktype) != 0) { goto error; } sigblob = buffer_get_string(&bptr, &len); rlen = buffer_remain_len(b); if (rlen != 0) { goto error; } if (len > crypto_sign_ed25519_BYTES) { goto error; } smlen = len + datalen; sm = malloc((size_t)smlen); memcpy(sm, sigblob, len); memcpy(sm+len, data, datalen); mlen = smlen; m = malloc((size_t)mlen); if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, key->ed25519_pk)) != 0) { //debug2("%s: crypto_sign_ed25519_open failed: %d", // __func__, ret); } if (ret == 0 && mlen != datalen) { //debug2("%s: crypto_sign_ed25519_open " // "mlen != datalen (%llu != %u)", __func__, mlen, datalen); ret = -1; } /* XXX compare 'm' and 'data' ? */ error: buffer_free(b); free(ktype); if (sigblob) { memset(sigblob, 's', len); free(sigblob); } if (sm) { memset(sm, 'S', (size_t)smlen); free(sm); } if (m) { memset(m, 'm', (size_t)smlen); /* NB. mlen may be invalid if ret != 0 */ free(m); } /* translate return code carefully */ return (ret == 0) ? 1 : -1; }
int main(int argc, char *argv[]) { unsigned char pk[crypto_sign_ed25519_PUBLICKEYBYTES]; unsigned char sk[crypto_sign_ed25519_SECRETKEYBYTES]; if (argc == 2 && argv[1][0] == 'g') { crypto_sign_ed25519_keypair(pk, sk); printf("Public key:\n"); int i; for (i = 0; i < crypto_sign_ed25519_PUBLICKEYBYTES; i++) { printf("%02hhX", pk[i]); } printf("\nSecret key:\n"); for (i = 0; i < crypto_sign_ed25519_SECRETKEYBYTES; i++) { printf("%02hhX", sk[i]); } printf("\n"); } if (argc == 5 && argv[1][0] == 's') { unsigned char *secret_key = hex_string_to_bin(argv[2]); char *data; int size = load_file(argv[3], &data); if (size < 0) goto fail; unsigned long long smlen; char *sm = malloc(size + crypto_sign_ed25519_BYTES * 2); crypto_sign_ed25519(sm, &smlen, data, size, secret_key); if (smlen - size != crypto_sign_ed25519_BYTES) goto fail; FILE *f = fopen(argv[4], "wb"); if (f == NULL) goto fail; memcpy(sm + smlen, sm, crypto_sign_ed25519_BYTES); // Move signature from beginning to end of file. if (fwrite(sm + (smlen - size), 1, smlen, f) != smlen) goto fail; fclose(f); printf("Signed successfully.\n"); } if (argc == 4 && argv[1][0] == 'c') { unsigned char *public_key = hex_string_to_bin(argv[2]); char *data; int size = load_file(argv[3], &data); if (size < 0) goto fail; char *signe = malloc(size + crypto_sign_ed25519_BYTES); memcpy(signe, data + size - crypto_sign_ed25519_BYTES, crypto_sign_ed25519_BYTES); // Move signature from end to beginning of file. memcpy(signe + crypto_sign_ed25519_BYTES, data, size - crypto_sign_ed25519_BYTES); unsigned long long smlen; char *m = malloc(size); unsigned long long mlen; if (crypto_sign_ed25519_open(m, &mlen, signe, size, public_key) == -1) { printf("Failed checking sig.\n"); goto fail; } printf("Checked successfully.\n"); } return 0; fail: printf("FAIL\n"); return 1; }
int ssh_ed25519_verify(const struct sshkey *key, const u_char *signature, size_t signaturelen, const u_char *data, size_t datalen, u_int compat) { struct sshbuf *b = NULL; char *ktype = NULL; const u_char *sigblob; u_char *sm = NULL, *m = NULL; size_t len; unsigned long long smlen = 0, mlen = 0; int r, ret; if (key == NULL || sshkey_type_plain(key->type) != KEY_ED25519 || key->ed25519_pk == NULL || datalen >= INT_MAX - crypto_sign_ed25519_BYTES) return SSH_ERR_INVALID_ARGUMENT; if ((b = sshbuf_from(signature, signaturelen)) == NULL) return SSH_ERR_ALLOC_FAIL; if ((r = sshbuf_get_cstring(b, &ktype, NULL)) != 0 || (r = sshbuf_get_string_direct(b, &sigblob, &len)) != 0) goto out; if (strcmp("ssh-ed25519", ktype) != 0) { r = SSH_ERR_KEY_TYPE_MISMATCH; goto out; } if (sshbuf_len(b) != 0) { r = SSH_ERR_UNEXPECTED_TRAILING_DATA; goto out; } if (len > crypto_sign_ed25519_BYTES) { r = SSH_ERR_INVALID_FORMAT; goto out; } if (datalen >= SIZE_MAX - len) { r = SSH_ERR_INVALID_ARGUMENT; goto out; } smlen = len + datalen; mlen = smlen; if ((sm = malloc(smlen)) == NULL || (m = malloc(mlen)) == NULL) { r = SSH_ERR_ALLOC_FAIL; goto out; } memcpy(sm, sigblob, len); memcpy(sm+len, data, datalen); if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, key->ed25519_pk)) != 0) { debug2("%s: crypto_sign_ed25519_open failed: %d", __func__, ret); } if (ret != 0 || mlen != datalen) { r = SSH_ERR_SIGNATURE_INVALID; goto out; } /* XXX compare 'm' and 'data' ? */ /* success */ r = 0; out: if (sm != NULL) { explicit_bzero(sm, smlen); free(sm); } if (m != NULL) { explicit_bzero(m, smlen); /* NB mlen may be invalid if r != 0 */ free(m); } sshbuf_free(b); free(ktype); return r; }
int ssh_ed25519_verify(const Key *key, const u_char *signature, u_int signaturelen, const u_char *data, u_int datalen) { Buffer b; char *ktype; u_char *sigblob, *sm, *m; u_int len; unsigned long long smlen, mlen; int rlen, ret; if (key == NULL || key_type_plain(key->type) != KEY_ED25519 || key->ed25519_pk == NULL) { error("%s: no ED25519 key", __func__); return -1; } buffer_init(&b); buffer_append(&b, signature, signaturelen); ktype = buffer_get_cstring(&b, NULL); if (strcmp("ssh-ed25519", ktype) != 0) { error("%s: cannot handle type %s", __func__, ktype); buffer_free(&b); free(ktype); return -1; } free(ktype); sigblob = buffer_get_string(&b, &len); rlen = buffer_len(&b); buffer_free(&b); if (rlen != 0) { error("%s: remaining bytes in signature %d", __func__, rlen); free(sigblob); return -1; } if (len > crypto_sign_ed25519_BYTES) { error("%s: len %u > crypto_sign_ed25519_BYTES %u", __func__, len, crypto_sign_ed25519_BYTES); free(sigblob); return -1; } smlen = len + datalen; sm = xmalloc(smlen); memcpy(sm, sigblob, len); memcpy(sm+len, data, datalen); mlen = smlen; m = xmalloc(mlen); if ((ret = crypto_sign_ed25519_open(m, &mlen, sm, smlen, key->ed25519_pk)) != 0) { debug2("%s: crypto_sign_ed25519_open failed: %d", __func__, ret); } if (ret == 0 && mlen != datalen) { debug2("%s: crypto_sign_ed25519_open " "mlen != datalen (%llu != %u)", __func__, mlen, datalen); ret = -1; } /* XXX compare 'm' and 'data' ? */ explicit_bzero(sigblob, len); explicit_bzero(sm, smlen); explicit_bzero(m, smlen); /* NB. mlen may be invalid if ret != 0 */ free(sigblob); free(sm); free(m); debug("%s: signature %scorrect", __func__, (ret != 0) ? "in" : ""); /* translate return code carefully */ return (ret == 0) ? 1 : -1; }
int kex_ecdh(struct per_session_data__sshd *pss, uint8_t *reply, uint32_t *plen) { uint8_t pri_key[64], temp[64], payload_sig[64 + 32], a, *lp, kbi[64]; struct lws_kex *kex = pss->kex; struct lws_genhash_ctx ctx; unsigned long long smlen; uint8_t *p = reply + 5; uint32_t be, kbi_len; uint8_t servkey[256]; char keyt[33]; int r, c; r = get_gen_server_key_25519(pss, servkey, sizeof(servkey)); if (!r) { lwsl_err("%s: Failed to get or gen server key\n", __func__); return 1; } r = ed25519_key_parse(servkey, r, keyt, sizeof(keyt), pss->K_S /* public key */, pri_key); if (r) { lwsl_notice("%s: server key parse failed: %d\n", __func__, r); return 1; } keyt[32] = '\0'; lwsl_info("Server key type: %s\n", keyt); /* * 1) Generate ephemeral key pair [ eph_pri_key | kex->Q_S ] * 2) Compute shared secret. * 3) Generate and sign exchange hash. * * 1) A 32 bytes private key should be generated for each new * connection, using a secure PRNG. The following actions * must be done on the private key: * * mysecret[0] &= 248; * mysecret[31] &= 127; * mysecret[31] |= 64; */ lws_get_random(pss->vhd->context, kex->eph_pri_key, LWS_SIZE_EC25519); kex->eph_pri_key[0] &= 248; kex->eph_pri_key[31] &= 127; kex->eph_pri_key[31] |= 64; /* * 2) The public key is calculated using the cryptographic scalar * multiplication: * * const unsigned char privkey[32]; * unsigned char pubkey[32]; * * crypto_scalarmult (pubkey, privkey, basepoint); */ crypto_scalarmult_curve25519(kex->Q_S, kex->eph_pri_key, basepoint); a = 0; for (r = 0; r < sizeof(kex->Q_S); r++) a |= kex->Q_S[r]; if (!a) { lwsl_notice("all zero pubkey\n"); return SSH_DISCONNECT_KEY_EXCHANGE_FAILED; } /* * The shared secret, k, is defined in SSH specifications to be a big * integer. This number is calculated using the following procedure: * * X is the 32 bytes point obtained by the scalar multiplication of * the other side's public key and the local private key scalar. */ crypto_scalarmult_curve25519(pss->K, kex->eph_pri_key, kex->Q_C); /* * The whole 32 bytes of the number X are then converted into a big * integer k. This conversion follows the network byte order. This * step differs from RFC5656. */ kbi_len = lws_mpint_rfc4251(kbi, pss->K, LWS_SIZE_EC25519, 1); /* * The exchange hash H is computed as the hash of the concatenation of * the following: * * string V_C, the client's identification string (CR and LF * excluded) * string V_S, the server's identification string (CR and LF * excluded) * string I_C, the payload of the client's SSH_MSG_KEXINIT * string I_S, the payload of the server's SSH_MSG_KEXINIT * string K_S, the host key * mpint Q_C, exchange value sent by the client * mpint Q_S, exchange value sent by the server * mpint K, the shared secret * * However there are a lot of unwritten details in the hash * definition... */ if (lws_genhash_init(&ctx, LWS_GENHASH_TYPE_SHA256)) { lwsl_notice("genhash init failed\n"); return 1; } if (_genhash_update_len(&ctx, pss->V_C, strlen(pss->V_C))) goto hash_probs; if (_genhash_update_len(&ctx, pss->vhd->ops->server_string, /* aka V_S */ strlen(pss->vhd->ops->server_string))) goto hash_probs; if (_genhash_update_len(&ctx, kex->I_C, kex->I_C_payload_len)) goto hash_probs; if (_genhash_update_len(&ctx, kex->I_S, kex->I_S_payload_len)) goto hash_probs; /* * K_S (host public key) * * sum of name + key lengths and headers * name length: name * key length: key * ---> */ lws_p32((uint8_t *)&be, 8 + strlen(keyt) + LWS_SIZE_EC25519); if (lws_genhash_update(&ctx, (void *)&be, 4)) goto hash_probs; if (_genhash_update_len(&ctx, keyt, strlen(keyt))) goto hash_probs; if (_genhash_update_len(&ctx, pss->K_S, LWS_SIZE_EC25519)) goto hash_probs; /* <---- */ if (_genhash_update_len(&ctx, kex->Q_C, LWS_SIZE_EC25519)) goto hash_probs; if (_genhash_update_len(&ctx, kex->Q_S, LWS_SIZE_EC25519)) goto hash_probs; if (lws_genhash_update(&ctx, kbi, kbi_len)) goto hash_probs; if (lws_genhash_destroy(&ctx, temp)) goto hash_probs; /* * Sign the 32-byte SHA256 "exchange hash" in temp * The signature is itself 64 bytes */ smlen = LWS_SIZE_EC25519 + 64; if (crypto_sign_ed25519(payload_sig, &smlen, temp, LWS_SIZE_EC25519, pri_key)) return 1; #if 0 l = LWS_SIZE_EC25519; n = crypto_sign_ed25519_open(temp, &l, payload_sig, smlen, pss->K_S); lwsl_notice("own sig sanity check says %d\n", n); #endif /* sig [64] and payload [32] concatenated in payload_sig * * The server then responds with the following * * uint32 packet length (exl self + mac) * byte padding len * byte SSH_MSG_KEX_ECDH_REPLY * string server public host key and certificates (K_S) * string Q_S (exchange value sent by the server) * string signature of H * padding */ *p++ = SSH_MSG_KEX_ECDH_REPLY; /* server public host key and certificates (K_S) */ lp = p; p +=4; lws_sized_blob(&p, keyt, strlen(keyt)); lws_sized_blob(&p, pss->K_S, LWS_SIZE_EC25519); lws_p32(lp, p - lp - 4); /* Q_S (exchange value sent by the server) */ lws_sized_blob(&p, kex->Q_S, LWS_SIZE_EC25519); /* signature of H */ lp = p; p +=4; lws_sized_blob(&p, keyt, strlen(keyt)); lws_sized_blob(&p, payload_sig, 64); lws_p32(lp, p - lp - 4); /* end of message */ lws_pad_set_length(pss, reply, &p, &pss->active_keys_stc); *plen = p - reply; if (!pss->active_keys_stc.valid) memcpy(pss->session_id, temp, LWS_SIZE_EC25519); /* RFC4253 7.2: * * The key exchange produces two values: a shared secret K, * and an exchange hash H. Encryption and authentication * keys are derived from these. The exchange hash H from the * first key exchange is additionally used as the session * identifier, which is a unique identifier for this connection. * It is used by authentication methods as a part of the data * that is signed as a proof of possession of a private key. * Once computed, the session identifier is not changed, * even if keys are later re-exchanged. * * The hash alg used in the KEX must be used for key derivation. * * 1) Initial IV client to server: * * HASH(K || H || "A" || session_id) * * (Here K is encoded as mpint and "A" as byte and session_id * as raw data. "A" means the single character A, ASCII 65). * * */ for (c = 0; c < 3; c++) { kex_ecdh_dv(kex->keys_next_cts.key[c], LWS_SIZE_CHACHA256_KEY, kbi, kbi_len, temp, 'A' + (c * 2), pss->session_id); kex_ecdh_dv(kex->keys_next_stc.key[c], LWS_SIZE_CHACHA256_KEY, kbi, kbi_len, temp, 'B' + (c * 2), pss->session_id); } explicit_bzero(temp, sizeof(temp)); return 0; hash_probs: lws_genhash_destroy(&ctx, NULL); return 1; }