lob_t remote_encrypt(remote_t remote, local_t local, lob_t inner) { uint8_t secret[crypto_box_BEFORENMBYTES], nonce[24], shared[24+crypto_box_BEFORENMBYTES], hash[32], csid = 0x3a; lob_t outer; size_t inner_len; outer = lob_new(); lob_head(outer,&csid,1); inner_len = lob_len(inner); if(!lob_body(outer,NULL,32+24+inner_len+crypto_secretbox_MACBYTES+16)) return lob_free(outer); // copy in the ephemeral public key/nonce memcpy(outer->body, remote->ekey, 32); randombytes(nonce,24); memcpy(outer->body+32, nonce, 24); // get the shared secret to create the nonce+key for the open aes crypto_box_beforenm(secret, remote->key, remote->esecret); // encrypt the inner if(crypto_secretbox_easy(outer->body+32+24, lob_raw(inner), inner_len, nonce, secret) != 0) return lob_free(outer); // generate secret for hmac crypto_box_beforenm(secret, remote->key, local->secret); memcpy(shared,nonce,24); memcpy(shared+24,secret,crypto_box_BEFORENMBYTES); e3x_hash(shared,24+crypto_box_BEFORENMBYTES,hash); crypto_onetimeauth(outer->body+32+24+inner_len+crypto_secretbox_MACBYTES, outer->body, outer->body_len-16, hash); return outer; }
int curvecpr_client_connected (struct curvecpr_client *client) { struct curvecpr_client_cf *cf = &client->cf; struct curvecpr_session *s = &client->session; struct curvecpr_packet_hello p; /* Copy some data into the session. */ curvecpr_bytes_copy(s->their_extension, cf->their_extension, 16); curvecpr_bytes_copy(s->their_global_pk, cf->their_global_pk, 32); /* Generate keys. */ s->my_session_nonce = curvecpr_util_random_mod_n(281474976710656LL); crypto_box_keypair(s->my_session_pk, s->my_session_sk); crypto_box_beforenm(s->my_session_their_global_key, s->their_global_pk, s->my_session_sk); crypto_box_beforenm(s->my_global_their_global_key, s->their_global_pk, cf->my_global_sk); /* Packet identifier. */ curvecpr_bytes_copy(p.id, "QvnQ5XlH", 8); /* Extensions. */ curvecpr_bytes_copy(p.server_extension, s->their_extension, 16); curvecpr_bytes_copy(p.client_extension, cf->my_extension, 16); /* The client's session-specific public key. */ curvecpr_bytes_copy(p.client_session_pk, s->my_session_pk, 32); /* A series of zero bytes for padding. */ curvecpr_bytes_copy(p._, _zeros, 64); /* The encrypted data (again, all zeros). Nonce generation is included. */ { unsigned char nonce[24]; unsigned char data[96] = { 0 }; /* The nonce for the upcoming encrypted data. */ curvecpr_bytes_copy(nonce, "CurveCP-client-H", 16); curvecpr_session_next_nonce(s, nonce + 16); curvecpr_bytes_copy(p.nonce, nonce + 16, 8); /* Actual encryption. */ crypto_box_afternm(data, _zeros, 96, nonce, s->my_session_their_global_key); curvecpr_bytes_copy(p.box, data + 16, 80); } if (cf->ops.send(client, (const unsigned char *)&p, sizeof(struct curvecpr_packet_hello))) return -EAGAIN; return 0; }
int main(void) { unsigned char k[crypto_box_BEFORENMBYTES]; int i; int ret; if (crypto_box_open(m, c, 163, nonce, alicepk, bobsk) == 0) { for (i = 32; i < 163; ++i) { printf(",0x%02x", (unsigned int)m[i]); if (i % 8 == 7) printf("\n"); } printf("\n"); } ret = crypto_box_open(m, c, 163, nonce, small_order_p, bobsk); assert(ret == -1); memset(m, 0, sizeof m); ret = crypto_box_beforenm(k, alicepk, bobsk); assert(ret == 0); if (crypto_box_open_afternm(m, c, 163, nonce, k) == 0) { for (i = 32; i < 163; ++i) { printf(",0x%02x", (unsigned int)m[i]); if (i % 8 == 7) printf("\n"); } printf("\n"); } return 0; }
ephemeral_t ephemeral_new(remote_t remote, lob_t outer) { uint8_t shared[crypto_box_BEFORENMBYTES+(crypto_box_PUBLICKEYBYTES*2)], hash[32]; ephemeral_t ephem; if(!remote) return NULL; if(!outer || outer->body_len < crypto_box_PUBLICKEYBYTES) return LOG("invalid outer"); if(!(ephem = malloc(sizeof(struct ephemeral_struct)))) return NULL; memset(ephem,0,sizeof (struct ephemeral_struct)); // create and copy in the exchange routing token e3x_hash(outer->body,16,hash); memcpy(ephem->token,hash,16); // do the diffie hellman crypto_box_beforenm(shared, outer->body, remote->esecret); // combine inputs to create the digest-derived keys memcpy(shared+crypto_box_BEFORENMBYTES,remote->ekey,crypto_box_PUBLICKEYBYTES); memcpy(shared+crypto_box_BEFORENMBYTES+crypto_box_PUBLICKEYBYTES,outer->body,crypto_box_PUBLICKEYBYTES); e3x_hash(shared,crypto_box_BEFORENMBYTES+(crypto_box_PUBLICKEYBYTES*2),ephem->enckey); memcpy(shared+crypto_box_BEFORENMBYTES,outer->body,crypto_box_PUBLICKEYBYTES); memcpy(shared+crypto_box_BEFORENMBYTES+crypto_box_PUBLICKEYBYTES,remote->ekey,crypto_box_PUBLICKEYBYTES); e3x_hash(shared,crypto_box_BEFORENMBYTES+(crypto_box_PUBLICKEYBYTES*2),ephem->deckey); return ephem; }
lob_t local_decrypt(local_t local, lob_t outer) { uint8_t secret[crypto_box_BEFORENMBYTES]; lob_t inner, tmp; // * `KEY` - 32 bytes, the sending exchange's ephemeral public key // * `NONCE` - 24 bytes, randomly generated // * `CIPHERTEXT` - the inner packet bytes encrypted using secretbox() using the `NONCE` as the nonce and the shared secret (derived from the recipients endpoint key and the included ephemeral key) as the key // * `AUTH` - 16 bytes, the calculated onetimeauth(`KEY` + `INNER`, SHA256(`NONCE` + secret)) using the shared secret derived from both endpoint keys, the hashing is to minimize the chance that the same key input is ever used twice if(outer->body_len <= (32+24+crypto_secretbox_MACBYTES+16)) return NULL; tmp = lob_new(); if(!lob_body(tmp,NULL,outer->body_len-(32+24+crypto_secretbox_MACBYTES+16))) return lob_free(tmp); // get the shared secret crypto_box_beforenm(secret, outer->body, local->secret); // decrypt the inner if(crypto_secretbox_open_easy(tmp->body, outer->body+32+24, tmp->body_len+crypto_secretbox_MACBYTES, outer->body+32, secret) != 0) return lob_free(tmp); // load inner packet inner = lob_parse(tmp->body,tmp->body_len); lob_free(tmp); return inner; }
static nif_term_t salt_box_beforenm(nif_heap_t *hp, int argc, const nif_term_t argv[]) { /* salt_box_beforenm(Public_key, Secret_key) -> Context. */ nif_bin_t pk; nif_bin_t sk; nif_bin_t bn; if (argc != 2) return (BADARG); /* Unpack arguments ensuring they're suitably typed. */ if (! enif_inspect_binary(hp, argv[0], &pk)) return (BADARG); if (! enif_inspect_binary(hp, argv[1], &sk)) return (BADARG); /* Check size constraints. */ if (pk.size != crypto_box_PUBLICKEYBYTES) return (BADARG); if (sk.size != crypto_box_SECRETKEYBYTES) return (BADARG); /* Allocate space for precomputed context. NB: Passing ENOMEM as BADARG. */ if (! enif_alloc_binary(crypto_box_BEFORENMBYTES, &bn)) return (BADARG); (void)crypto_box_beforenm(bn.data, pk.data, sk.data); return (enif_make_binary(hp, &bn)); }
int Secure_GenSharedKey(Secure_SharedKey sharedkey, Secure_PubKey peer, Secure_PrivKey priv) { if(crypto_box_beforenm(sharedkey, peer, priv)) { Error_Print("Unable to generate a shared key.\n"); return -1; } return 0; }
int main(void) { unsigned char k[crypto_box_BEFORENMBYTES]; int i; int ret; ret = crypto_box(c, m, 163, nonce, bobpk, alicesk); assert(ret == 0); for (i = 16; i < 163; ++i) { printf(",0x%02x", (unsigned int)c[i]); if (i % 8 == 7) printf("\n"); } printf("\n"); memset(c, 0, sizeof c); ret = crypto_box_beforenm(k, bobpk, alicesk); assert(ret == 0); crypto_box_afternm(c, m, 163, nonce, k); for (i = 16; i < 163; ++i) { printf(",0x%02x", (unsigned int)c[i]); if (i % 8 == 7) printf("\n"); } printf("\n"); assert(crypto_box_seedbytes() > 0U); assert(crypto_box_publickeybytes() > 0U); assert(crypto_box_secretkeybytes() > 0U); assert(crypto_box_beforenmbytes() > 0U); assert(crypto_box_noncebytes() > 0U); assert(crypto_box_zerobytes() > 0U); assert(crypto_box_boxzerobytes() > 0U); assert(crypto_box_macbytes() > 0U); assert(strcmp(crypto_box_primitive(), "curve25519xsalsa20poly1305") == 0); assert(crypto_box_curve25519xsalsa20poly1305_seedbytes() == crypto_box_seedbytes()); assert(crypto_box_curve25519xsalsa20poly1305_publickeybytes() == crypto_box_publickeybytes()); assert(crypto_box_curve25519xsalsa20poly1305_secretkeybytes() == crypto_box_secretkeybytes()); assert(crypto_box_curve25519xsalsa20poly1305_beforenmbytes() == crypto_box_beforenmbytes()); assert(crypto_box_curve25519xsalsa20poly1305_noncebytes() == crypto_box_noncebytes()); assert(crypto_box_curve25519xsalsa20poly1305_zerobytes() == crypto_box_zerobytes()); assert(crypto_box_curve25519xsalsa20poly1305_boxzerobytes() == crypto_box_boxzerobytes()); assert(crypto_box_curve25519xsalsa20poly1305_macbytes() == crypto_box_macbytes()); return 0; }
int crypto_box( unsigned char *c, const unsigned char *m,unsigned long long mlen, const unsigned char *n, const unsigned char *pk, const unsigned char *sk ) { unsigned char k[crypto_box_BEFORENMBYTES]; crypto_box_beforenm(k,pk,sk); return crypto_box_afternm(c,m,mlen,n,k); }
int crypto_box_open( unsigned char *m, const unsigned char *c,unsigned long long clen, const unsigned char *n, const unsigned char *pk, const unsigned char *sk ) { unsigned char k[crypto_box_BEFORENMBYTES]; crypto_box_beforenm(k,pk,sk); return crypto_box_open_afternm(m,c,clen,n,k); }
static int l_cipher_create(lua_State *l) { void *publickey = lua_touserdata(l, 1), *secretkey = lua_touserdata(l, 2), *cipher = lua_newuserdata(l, crypto_box_BEFORENMBYTES); luaL_argcheck(l, publickey != NULL, 1, "Public key expected"); luaL_argcheck(l, secretkey != NULL, 2, "Secret key expected"); crypto_box_beforenm(cipher, publickey, secretkey); return 1; }
PyObject *pycrypto_box_beforenm(PyObject *self, PyObject *args, PyObject *kw){ PyObject *ret; char *pk, *sk; Py_ssize_t pksize=0, sksize=0; static const char *kwlist[] = {"pk", "sk", 0}; unsigned char rk[crypto_box_SECRETKEYBYTES]; if (!PyArg_ParseTupleAndKeywords(args, kw, "|s#s#:crypto_box_beforenm", (char **) kwlist, &pk, &pksize, &sk, &sksize)){ return (PyObject *)0;} if (pksize != crypto_box_PUBLICKEYBYTES) return Py_BuildValue("i", 0); if (sksize != crypto_box_SECRETKEYBYTES) return Py_BuildValue("i", 0); if (crypto_box_beforenm(rk,(const unsigned char *) pk,(const unsigned char *) sk)<0) return Py_BuildValue("i", 0); ret = PyBytes_FromStringAndSize((char *)rk,crypto_box_SECRETKEYBYTES); return ret;}
int crypto_box_open_detached(unsigned char *m, const unsigned char *c, const unsigned char *mac, unsigned long long clen, const unsigned char *n, const unsigned char *pk, const unsigned char *sk) { unsigned char k[crypto_box_BEFORENMBYTES]; int ret; crypto_box_beforenm(k, pk, sk); ret = crypto_secretbox_open_detached(m, c, mac, clen, n, k); sodium_memzero(k, sizeof k); return ret; }
int crypto_box_detached(unsigned char *c, unsigned char *mac, const unsigned char *m, unsigned long long mlen, const unsigned char *n, const unsigned char *pk, const unsigned char *sk) { unsigned char k[crypto_box_BEFORENMBYTES]; int ret; (void) sizeof(int[crypto_box_BEFORENMBYTES >= crypto_secretbox_KEYBYTES ? 1 : -1]); crypto_box_beforenm(k, pk, sk); ret = crypto_secretbox_detached(c, mac, m, mlen, n, k); sodium_memzero(k, sizeof k); return ret; }
int curve25519_proto_init(struct curve25519_proto *p, unsigned char *pubkey_remote, size_t len, char *home, int server) { int fd; ssize_t ret; char path[PATH_MAX]; unsigned char secretkey_own[crypto_box_curve25519xsalsa20poly1305_SECRETKEYBYTES] = { 0 }; unsigned char publickey_own[crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES] = { 0 }; if (!pubkey_remote || len != crypto_box_curve25519xsalsa20poly1305_PUBLICKEYBYTES) return -EINVAL; memset(path, 0, sizeof(path)); slprintf(path, sizeof(path), "%s/%s", home, FILE_PRIVKEY); fd = open_or_die(path, O_RDONLY); ret = read(fd, secretkey_own, sizeof(secretkey_own)); if (ret != sizeof(secretkey_own)) { xmemset(secretkey_own, 0, sizeof(secretkey_own)); panic("Cannot read private key!\n"); } close(fd); crypto_scalarmult_curve25519_base(publickey_own, secretkey_own); if (!crypto_verify_32(publickey_own, pubkey_remote)) { xmemset(secretkey_own, 0, sizeof(secretkey_own)); xmemset(publickey_own, 0, sizeof(publickey_own)); panic("PANIC: remote end has same public key as you have!!!\n"); } crypto_box_beforenm(p->key, pubkey_remote, secretkey_own); xmemset(p->enonce, 0, sizeof(p->enonce)); xmemset(p->dnonce, 0, sizeof(p->dnonce)); xmemset(secretkey_own, 0, sizeof(secretkey_own)); xmemset(publickey_own, 0, sizeof(publickey_own)); return 0; }
// shared_secret = crypto_box_beforenm(pk_other, sk_self); static int tweetnacl_crypto_box_beforenm( lua_State* L ) { unsigned int pk_len; const char* pk_other = luaL_checklstring(L,1,&pk_len); if(pk_len != crypto_box_PUBLICKEYBYTES) return luaL_error( L, "len(pk)=%d, should be %d", pk_len, crypto_box_PUBLICKEYBYTES); unsigned int sk_len; const char* sk_self = luaL_checklstring(L,2,&sk_len); if(sk_len != crypto_box_SECRETKEYBYTES) return luaL_error( L, "len(sk)=%d, should be %d", sk_len, crypto_box_SECRETKEYBYTES); char secret[crypto_box_BEFORENMBYTES]; crypto_box_beforenm(secret, pk_other, sk_self); lua_pushlstring(L, secret, crypto_box_BEFORENMBYTES); return 1; }
static int process_welcome (const uint8_t *msg_data_, size_t msg_size_, const uint8_t *server_key_, const uint8_t *cn_secret_, uint8_t *cn_server_, uint8_t *cn_cookie_, uint8_t *cn_precom_) { if (msg_size_ != 168) { errno = EPROTO; return -1; } uint8_t welcome_nonce[crypto_box_NONCEBYTES]; uint8_t welcome_plaintext[crypto_box_ZEROBYTES + 128]; uint8_t welcome_box[crypto_box_BOXZEROBYTES + 144]; // Open Box [S' + cookie](C'->S) memset (welcome_box, 0, crypto_box_BOXZEROBYTES); memcpy (welcome_box + crypto_box_BOXZEROBYTES, msg_data_ + 24, 144); memcpy (welcome_nonce, "WELCOME-", 8); memcpy (welcome_nonce + 8, msg_data_ + 8, 16); int rc = crypto_box_open (welcome_plaintext, welcome_box, sizeof welcome_box, welcome_nonce, server_key_, cn_secret_); if (rc != 0) { errno = EPROTO; return -1; } memcpy (cn_server_, welcome_plaintext + crypto_box_ZEROBYTES, 32); memcpy (cn_cookie_, welcome_plaintext + crypto_box_ZEROBYTES + 32, 16 + 80); // Message independent precomputation rc = crypto_box_beforenm (cn_precom_, cn_server_, cn_secret_); zmq_assert (rc == 0); return 0; }
int zmq::curve_client_t::process_welcome (msg_t *msg_) { if (msg_->size () != 168) { errno = EPROTO; return -1; } const uint8_t * welcome = static_cast <uint8_t *> (msg_->data ()); if (memcmp (welcome, "\x07WELCOME", 8)) { errno = EPROTO; return -1; } uint8_t welcome_nonce [crypto_box_NONCEBYTES]; uint8_t welcome_plaintext [crypto_box_ZEROBYTES + 128]; uint8_t welcome_box [crypto_box_BOXZEROBYTES + 144]; // Open Box [S' + cookie](C'->S) memset (welcome_box, 0, crypto_box_BOXZEROBYTES); memcpy (welcome_box + crypto_box_BOXZEROBYTES, welcome + 24, 144); memcpy (welcome_nonce, "WELCOME-", 8); memcpy (welcome_nonce + 8, welcome + 8, 16); int rc = crypto_box_open (welcome_plaintext, welcome_box, sizeof welcome_box, welcome_nonce, server_key, cn_secret); if (rc != 0) { errno = EPROTO; return -1; } memcpy (cn_server, welcome_plaintext + crypto_box_ZEROBYTES, 32); memcpy (cn_cookie, welcome_plaintext + crypto_box_ZEROBYTES + 32, 16 + 80); // Message independent precomputation rc = crypto_box_beforenm (cn_precom, cn_server, cn_secret); zmq_assert (rc == 0); return 0; }
static int proto_init(sigma_proto *instance) { sigma_proto_nacl* inst = ((sigma_proto_nacl*) instance); uint8_t taipublickey[crypto_box_PUBLICKEYBYTES]; crypto_box_beforenm( inst->precomp, inst->publickey, inst->privatekey ); bzero(inst->encnonce, crypto_box_NONCEBYTES); bzero(inst->decnonce, crypto_box_NONCEBYTES); crypto_scalarmult_curve25519_base(taipublickey, inst->privatekey); inst->encnonce[nonceoffset - 1] = memcmp(taipublickey, inst->publickey, crypto_box_PUBLICKEYBYTES) > 0 ? 1 : 0; inst->decnonce[nonceoffset - 1] = inst->encnonce[nonceoffset - 1] ? 0 : 1; return 0; }
QByteArray PublicKeyCrypto::boxBeforeNM(const QByteArray &publicKey, const QByteArray &secretKey) { if(publicKey.length() != boxPublicKeyBytes || secretKey.length() != boxSecretKeyBytes) { return QByteArray(); } QByteArray key; key.resize(boxBeforeNMBytes); if(key.length() != boxBeforeNMBytes) { return QByteArray(); } int result = crypto_box_beforenm( toUnsignedChar(key.data()), toConstUnsignedChar(publicKey.constData()), toConstUnsignedChar(secretKey.constData()) ); return (result == TEARS_SODIUM_SUCCESS)? key : QByteArray(); }
int zmq::curve_client_t::process_welcome ( const uint8_t *msg_data, size_t msg_size) { if (msg_size != 168) { errno = EPROTO; return -1; } uint8_t welcome_nonce [crypto_box_NONCEBYTES]; uint8_t welcome_plaintext [crypto_box_ZEROBYTES + 128]; uint8_t welcome_box [crypto_box_BOXZEROBYTES + 144]; // Open Box [S' + cookie](C'->S) memset (welcome_box, 0, crypto_box_BOXZEROBYTES); memcpy (welcome_box + crypto_box_BOXZEROBYTES, msg_data + 24, 144); memcpy (welcome_nonce, "WELCOME-", 8); memcpy (welcome_nonce + 8, msg_data + 8, 16); int rc = crypto_box_open (welcome_plaintext, welcome_box, sizeof welcome_box, welcome_nonce, server_key, cn_secret); if (rc != 0) { errno = EPROTO; return -1; } memcpy (cn_server, welcome_plaintext + crypto_box_ZEROBYTES, 32); memcpy (cn_cookie, welcome_plaintext + crypto_box_ZEROBYTES + 32, 16 + 80); // Message independent precomputation rc = crypto_box_beforenm (cn_precom, cn_server, cn_secret); zmq_assert (rc == 0); state = send_initiate; return 0; }
uint8_t remote_verify(remote_t remote, local_t local, lob_t outer) { uint8_t secret[crypto_box_BEFORENMBYTES], shared[24+crypto_box_BEFORENMBYTES], hash[32]; if(!remote || !local || !outer) return 1; if(outer->head_len != 1 || outer->head[0] != 0x3a) return 2; // generate secret and verify crypto_box_beforenm(secret, remote->key, local->secret); memcpy(shared,outer->body+32,24); // nonce memcpy(shared+24,secret,crypto_box_BEFORENMBYTES); e3x_hash(shared,24+crypto_box_BEFORENMBYTES,hash); if(crypto_onetimeauth_verify(outer->body+(outer->body_len-crypto_onetimeauth_BYTES), outer->body, outer->body_len-crypto_onetimeauth_BYTES, hash)) { LOG("OTA verify failed"); lob_free(outer); return 1; } return 0; }
int main(void) { unsigned char *alicepk; unsigned char *alicesk; unsigned char *bobpk; unsigned char *bobsk; unsigned char *mac; unsigned char *nonce; unsigned char *k1; unsigned char *k2; unsigned char *m; unsigned char *m2; unsigned char *c; size_t mlen; size_t i; size_t m_size; size_t m2_size; size_t c_size; int ret; m2_size = m_size = 1U + randombytes_uniform(10000); c_size = crypto_box_MACBYTES + m_size; m = (unsigned char *) sodium_malloc(m_size); m2 = (unsigned char *) sodium_malloc(m2_size); c = (unsigned char *) sodium_malloc(c_size); alicepk = (unsigned char *) sodium_malloc(crypto_box_PUBLICKEYBYTES); alicesk = (unsigned char *) sodium_malloc(crypto_box_SECRETKEYBYTES); bobpk = (unsigned char *) sodium_malloc(crypto_box_PUBLICKEYBYTES); bobsk = (unsigned char *) sodium_malloc(crypto_box_SECRETKEYBYTES); mac = (unsigned char *) sodium_malloc(crypto_box_MACBYTES); nonce = (unsigned char *) sodium_malloc(crypto_box_NONCEBYTES); k1 = (unsigned char *) sodium_malloc(crypto_box_BEFORENMBYTES); k2 = (unsigned char *) sodium_malloc(crypto_box_BEFORENMBYTES); crypto_box_keypair(alicepk, alicesk); crypto_box_keypair(bobpk, bobsk); mlen = (size_t) randombytes_uniform((uint32_t) m_size) + 1U; randombytes_buf(m, mlen); randombytes_buf(nonce, crypto_box_NONCEBYTES); ret = crypto_box_easy(c, m, mlen, nonce, bobpk, alicesk); assert(ret == 0); if (crypto_box_open_easy(m2, c, (unsigned long long) mlen + crypto_box_MACBYTES, nonce, alicepk, bobsk) != 0) { printf("open() failed"); return 1; } printf("%d\n", memcmp(m, m2, mlen)); for (i = 0; i < mlen + crypto_box_MACBYTES - 1; i++) { if (crypto_box_open_easy(m2, c, (unsigned long long) i, nonce, alicepk, bobsk) == 0) { printf("short open() should have failed"); return 1; } } memcpy(c, m, mlen); ret = crypto_box_easy(c, c, (unsigned long long) mlen, nonce, bobpk, alicesk); assert(ret == 0); printf("%d\n", memcmp(m, c, mlen) == 0); printf("%d\n", memcmp(m, c + crypto_box_MACBYTES, mlen) == 0); if (crypto_box_open_easy(c, c, (unsigned long long) mlen + crypto_box_MACBYTES, nonce, alicepk, bobsk) != 0) { printf("crypto_box_open_easy() failed\n"); } ret = crypto_box_beforenm(k1, alicepk, bobsk); assert(ret == 0); ret = crypto_box_beforenm(k2, bobpk, alicesk); assert(ret == 0); memset(m2, 0, m2_size); if (crypto_box_easy_afternm(c, m, SIZE_MAX - 1U, nonce, k1) == 0) { printf("crypto_box_easy_afternm() with a short ciphertext should have failed\n"); } crypto_box_easy_afternm(c, m, (unsigned long long) mlen, nonce, k1); if (crypto_box_open_easy_afternm(m2, c, (unsigned long long) mlen + crypto_box_MACBYTES, nonce, k2) != 0) { printf("crypto_box_open_easy_afternm() failed\n"); } printf("%d\n", memcmp(m, m2, mlen)); if (crypto_box_open_easy_afternm(m2, c, crypto_box_MACBYTES - 1U, nonce, k2) == 0) { printf("crypto_box_open_easy_afternm() with a huge ciphertext should have failed\n"); } memset(m2, 0, m2_size); ret = crypto_box_detached(c, mac, m, (unsigned long long) mlen, nonce, alicepk, bobsk); assert(ret == 0); if (crypto_box_open_detached(m2, c, mac, (unsigned long long) mlen, nonce, bobpk, alicesk) != 0) { printf("crypto_box_open_detached() failed\n"); } printf("%d\n", memcmp(m, m2, mlen)); memset(m2, 0, m2_size); crypto_box_detached_afternm(c, mac, m, (unsigned long long) mlen, nonce, k1); if (crypto_box_open_detached_afternm(m2, c, mac, (unsigned long long) mlen, nonce, k2) != 0) { printf("crypto_box_open_detached_afternm() failed\n"); } printf("%d\n", memcmp(m, m2, mlen)); sodium_free(alicepk); sodium_free(alicesk); sodium_free(bobpk); sodium_free(bobsk); sodium_free(mac); sodium_free(nonce); sodium_free(k1); sodium_free(k2); sodium_free(m); sodium_free(m2); sodium_free(c); printf("OK\n"); return 0; }
static int _handle_hello (struct curvecpr_server *server, void *priv, const struct curvecpr_packet_hello *p) { const struct curvecpr_server_cf *cf = &server->cf; struct curvecpr_session s; /* Used only as a temporary store to make what we're doing more clear. */ unsigned char nonce[24]; unsigned char data[96] = { 0 }; /* Dummy initialization. */ curvecpr_session_new(&s); curvecpr_session_set_priv(&s, priv); /* Verify initial connection parameters. */ curvecpr_bytes_copy(s.their_session_pk, p->client_session_pk, 32); crypto_box_beforenm(s.my_global_their_session_key, s.their_session_pk, cf->my_global_sk); curvecpr_bytes_copy(nonce, "CurveCP-client-H", 16); curvecpr_bytes_copy(nonce + 16, p->nonce, 8); curvecpr_bytes_copy(data + 16, p->box, 80); if (crypto_box_open_afternm(data, data, 96, nonce, s.my_global_their_session_key)) return -EINVAL; /* Set up session keys. */ crypto_box_keypair(s.my_session_pk, s.my_session_sk); /* Prepare to send a cookie packet. */ { struct curvecpr_packet_cookie po; struct curvecpr_packet_cookie_box po_box; curvecpr_bytes_zero(po_box._, 32); curvecpr_bytes_copy(po_box.server_session_pk, s.my_session_pk, 32); /* Generate the cookie. */ curvecpr_bytes_zero(po_box.cookie, 32); curvecpr_bytes_copy(po_box.cookie + 32, s.their_session_pk, 32); curvecpr_bytes_copy(po_box.cookie + 64, s.my_session_sk, 32); /* Encrypt the cookie with our global nonce and temporary key. */ curvecpr_bytes_copy(nonce, "minute-k", 8); if (cf->ops.next_nonce(server, nonce + 8, 16)) return -EINVAL; crypto_secretbox(po_box.cookie, po_box.cookie, 96, nonce, server->my_temporal_key); curvecpr_bytes_copy(po_box.cookie, nonce + 8, 16); /* Now encrypt the whole box. */ curvecpr_bytes_copy(nonce, "CurveCPK", 8); crypto_box_afternm((unsigned char *)&po_box, (const unsigned char *)&po_box, sizeof(struct curvecpr_packet_cookie_box), nonce, s.my_global_their_session_key); /* Build the rest of the packet. */ curvecpr_bytes_copy(po.id, "RL3aNMXK", 8); curvecpr_bytes_copy(po.client_extension, p->client_extension, 16); curvecpr_bytes_copy(po.server_extension, cf->my_extension, 16); curvecpr_bytes_copy(po.nonce, nonce + 8, 16); curvecpr_bytes_copy(po.box, (const unsigned char *)&po_box + 16, 144); if (cf->ops.send(server, &s, (const unsigned char *)&po, sizeof(struct curvecpr_packet_cookie))) return -EINVAL; } return 0; }
/* Precomputes the shared key from their public_key and our secret_key. * This way we can avoid an expensive elliptic curve scalar multiply for each * encrypt/decrypt operation. * enc_key has to be crypto_box_BEFORENMBYTES bytes long. */ void encrypt_precompute(uint8_t *public_key, uint8_t *secret_key, uint8_t *enc_key) { crypto_box_beforenm(enc_key, public_key, secret_key); }
int zmq::curve_server_t::process_initiate (msg_t *msg_) { if (msg_->size () < 225) { errno = EPROTO; return -1; } const uint8_t *initiate = static_cast <uint8_t *> (msg_->data ()); if (memcmp (initiate, "INITIATE\0", 9)) { errno = EPROTO; return -1; } uint8_t cookie_nonce [crypto_secretbox_NONCEBYTES]; uint8_t cookie_plaintext [crypto_secretbox_ZEROBYTES + 64]; uint8_t cookie_box [crypto_secretbox_BOXZEROBYTES + 80]; // Open Box [C' + s'](t) memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES); memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80); memcpy (cookie_nonce, "COOKIE--", 8); memcpy (cookie_nonce + 8, initiate + 9, 16); int rc = crypto_secretbox_open (cookie_plaintext, cookie_box, sizeof cookie_box, cookie_nonce, cookie_key); if (rc != 0) { errno = EPROTO; return -1; } // Check cookie plain text is as expected [C' + s'] if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32) || memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) { errno = EAGAIN; return -1; } const size_t clen = (msg_->size () - 113) + crypto_box_BOXZEROBYTES; uint8_t initiate_nonce [crypto_box_NONCEBYTES]; uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 96 + 256]; uint8_t initiate_box [crypto_box_BOXZEROBYTES + 112 + 256]; // Open Box [C + vouch + metadata](C'->S') memset (initiate_box, 0, crypto_box_BOXZEROBYTES); memcpy (initiate_box + crypto_box_BOXZEROBYTES, initiate + 113, clen - crypto_box_BOXZEROBYTES); memcpy (initiate_nonce, "CurveZMQINITIATE", 16); memcpy (initiate_nonce + 16, initiate + 105, 8); rc = crypto_box_open (initiate_plaintext, initiate_box, clen, initiate_nonce, cn_client, cn_secret); if (rc != 0) { errno = EPROTO; return -1; } const uint8_t *client_key = initiate_plaintext + crypto_box_ZEROBYTES; uint8_t vouch_nonce [crypto_box_NONCEBYTES]; uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 32]; uint8_t vouch_box [crypto_box_BOXZEROBYTES + 48]; // Open Box [C'](C->S) and check contents memset (vouch_box, 0, crypto_box_BOXZEROBYTES); memcpy (vouch_box + crypto_box_BOXZEROBYTES, initiate_plaintext + crypto_box_ZEROBYTES + 48, 48); memcpy (vouch_nonce, "VOUCH---", 8); memcpy (vouch_nonce + 8, initiate_plaintext + crypto_box_ZEROBYTES + 32, 16); rc = crypto_box_open (vouch_plaintext, vouch_box, sizeof vouch_box, vouch_nonce, client_key, secret_key); if (rc != 0) { errno = EPROTO; return -1; } // What we decrypted must be the client's short-term public key if (memcmp (vouch_plaintext + crypto_box_ZEROBYTES, cn_client, 32)) { errno = EPROTO; return -1; } // Precompute connection secret from client key rc = crypto_box_beforenm (cn_precom, cn_client, cn_secret); zmq_assert (rc == 0); // Use ZAP protocol (RFC 27) to authenticate the user. rc = session->zap_connect (); if (rc == 0) { send_zap_request (client_key); rc = receive_and_process_zap_reply (); if (rc != 0) { if (errno != EAGAIN) return -1; expecting_zap_reply = true; } } return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 96, clen - crypto_box_ZEROBYTES - 96); }
/* Precomputes the shared key from their public_key and our secret_key. * This way we can avoid an expensive elliptic curve scalar multiply for each * encrypt/decrypt operation. * shared_key has to be crypto_box_BEFORENMBYTES bytes long. */ int32_t encrypt_precompute(const uint8_t *public_key, const uint8_t *secret_key, uint8_t *shared_key) { return crypto_box_beforenm(shared_key, public_key, secret_key); }
int zmq::curve_server_t::process_initiate (msg_t *msg_) { if (msg_->size () < 257) { // Temporary support for security debugging puts ("CURVE I: client INITIATE is not correct size"); errno = EPROTO; return -1; } const uint8_t *initiate = static_cast <uint8_t *> (msg_->data ()); if (memcmp (initiate, "\x08INITIATE", 9)) { // Temporary support for security debugging puts ("CURVE I: client INITIATE has invalid command name"); errno = EPROTO; return -1; } uint8_t cookie_nonce [crypto_secretbox_NONCEBYTES]; uint8_t cookie_plaintext [crypto_secretbox_ZEROBYTES + 64]; uint8_t cookie_box [crypto_secretbox_BOXZEROBYTES + 80]; // Open Box [C' + s'](t) memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES); memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80); memcpy (cookie_nonce, "COOKIE--", 8); memcpy (cookie_nonce + 8, initiate + 9, 16); int rc = crypto_secretbox_open (cookie_plaintext, cookie_box, sizeof cookie_box, cookie_nonce, cookie_key); if (rc != 0) { // Temporary support for security debugging puts ("CURVE I: cannot open client INITIATE cookie"); errno = EPROTO; return -1; } // Check cookie plain text is as expected [C' + s'] if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, cn_client, 32) || memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, cn_secret, 32)) { // Temporary support for security debugging puts ("CURVE I: client INITIATE cookie is not valid"); errno = EPROTO; return -1; } const size_t clen = (msg_->size () - 113) + crypto_box_BOXZEROBYTES; uint8_t initiate_nonce [crypto_box_NONCEBYTES]; uint8_t initiate_plaintext [crypto_box_ZEROBYTES + 128 + 256]; uint8_t initiate_box [crypto_box_BOXZEROBYTES + 144 + 256]; // Open Box [C + vouch + metadata](C'->S') memset (initiate_box, 0, crypto_box_BOXZEROBYTES); memcpy (initiate_box + crypto_box_BOXZEROBYTES, initiate + 113, clen - crypto_box_BOXZEROBYTES); memcpy (initiate_nonce, "CurveZMQINITIATE", 16); memcpy (initiate_nonce + 16, initiate + 105, 8); cn_peer_nonce = get_uint64(initiate + 105); rc = crypto_box_open (initiate_plaintext, initiate_box, clen, initiate_nonce, cn_client, cn_secret); if (rc != 0) { // Temporary support for security debugging puts ("CURVE I: cannot open client INITIATE"); errno = EPROTO; return -1; } const uint8_t *client_key = initiate_plaintext + crypto_box_ZEROBYTES; uint8_t vouch_nonce [crypto_box_NONCEBYTES]; uint8_t vouch_plaintext [crypto_box_ZEROBYTES + 64]; uint8_t vouch_box [crypto_box_BOXZEROBYTES + 80]; // Open Box Box [C',S](C->S') and check contents memset (vouch_box, 0, crypto_box_BOXZEROBYTES); memcpy (vouch_box + crypto_box_BOXZEROBYTES, initiate_plaintext + crypto_box_ZEROBYTES + 48, 80); memcpy (vouch_nonce, "VOUCH---", 8); memcpy (vouch_nonce + 8, initiate_plaintext + crypto_box_ZEROBYTES + 32, 16); rc = crypto_box_open (vouch_plaintext, vouch_box, sizeof vouch_box, vouch_nonce, client_key, cn_secret); if (rc != 0) { // Temporary support for security debugging puts ("CURVE I: cannot open client INITIATE vouch"); errno = EPROTO; return -1; } // What we decrypted must be the client's short-term public key if (memcmp (vouch_plaintext + crypto_box_ZEROBYTES, cn_client, 32)) { // Temporary support for security debugging puts ("CURVE I: invalid handshake from client (public key)"); errno = EPROTO; return -1; } // Precompute connection secret from client key rc = crypto_box_beforenm (cn_precom, cn_client, cn_secret); zmq_assert (rc == 0); // Use ZAP protocol (RFC 27) to authenticate the user. rc = session->zap_connect (); if (rc == 0) { send_zap_request (client_key); rc = receive_and_process_zap_reply (); if (rc == 0) state = status_code == "200" ? send_ready : send_error; else if (errno == EAGAIN) state = expect_zap_reply; else return -1; } else state = send_ready; return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 128, clen - crypto_box_ZEROBYTES - 128); }
static int _handle_initiate (struct curvecpr_server *server, struct curvecpr_session *s, void *priv, const struct curvecpr_packet_initiate *p, const unsigned char *buf, size_t num) { const struct curvecpr_server_cf *cf = &server->cf; unsigned char nonce[24]; unsigned char data[sizeof(struct curvecpr_packet_initiate_box) + 640]; if (s != NULL) { /* Update existing client. */ crypto_uint64 unpacked_nonce = curvecpr_bytes_unpack_uint64(p->nonce); if (unpacked_nonce <= s->their_session_nonce) return -EINVAL; curvecpr_bytes_copy(nonce, "CurveCP-client-I", 16); curvecpr_bytes_copy(nonce + 16, p->nonce, 8); curvecpr_bytes_zero(data, 16); curvecpr_bytes_copy(data + 16, buf, num); if (crypto_box_open_afternm(data, data, num + 16, nonce, s->my_session_their_session_key)) return -EINVAL; s->their_session_nonce = unpacked_nonce; curvecpr_session_set_priv(s, priv); if (cf->ops.recv(server, s, data + sizeof(struct curvecpr_packet_initiate_box), num + 16 - sizeof(struct curvecpr_packet_initiate_box))) return -EINVAL; return 0; } else { struct curvecpr_session s_new, *s_new_stored; const struct curvecpr_packet_initiate_box *p_box; /* Register new client. */ curvecpr_bytes_copy(nonce, "minute-k", 8); curvecpr_bytes_copy(nonce + 8, p->cookie, 16); /* We can reuse data; the cookie will fit into it. */ curvecpr_bytes_zero(data, 16); curvecpr_bytes_copy(data + 16, p->cookie + 16, 80); /* Validate cookie. */ if (crypto_secretbox_open(data, data, 96, nonce, server->my_temporal_key)) { curvecpr_bytes_zero(data, 16); curvecpr_bytes_copy(data + 16, p->cookie + 16, 80); if (crypto_secretbox_open(data, data, 96, nonce, server->my_last_temporal_key)) return -EINVAL; } if (!curvecpr_bytes_equal(p->client_session_pk, data + 32, 32)) return -EINVAL; /* Cookie is valid; set up keys. */ curvecpr_session_new(&s_new); curvecpr_bytes_copy(s_new.their_session_pk, data + 32, 32); curvecpr_bytes_copy(s_new.my_session_sk, data + 64, 32); crypto_box_beforenm(s_new.my_session_their_session_key, s_new.their_session_pk, s_new.my_session_sk); curvecpr_bytes_copy(nonce, "CurveCP-client-I", 16); curvecpr_bytes_copy(nonce + 16, p->nonce, 8); curvecpr_bytes_zero(data, 16); curvecpr_bytes_copy(data + 16, buf, num); if (crypto_box_open_afternm(data, data, num + 16, nonce, s_new.my_session_their_session_key)) return -EINVAL; p_box = (struct curvecpr_packet_initiate_box *)data; /* Attempt to validate this client. */ { unsigned char vouch[64]; curvecpr_bytes_copy(s_new.their_global_pk, p_box->client_global_pk, 32); crypto_box_beforenm(s_new.my_global_their_global_key, s_new.their_global_pk, cf->my_global_sk); curvecpr_bytes_copy(nonce, "CurveCPV", 8); curvecpr_bytes_copy(nonce + 8, p_box->nonce, 16); curvecpr_bytes_zero(vouch, 16); curvecpr_bytes_copy(vouch + 16, p_box->vouch, 48); if (crypto_box_afternm(vouch, vouch, 64, nonce, s_new.my_global_their_global_key)) return -EINVAL; if (!curvecpr_bytes_equal(vouch + 32, s_new.their_session_pk, 32)) return -EINVAL; } /* All good, we can go ahead and submit the client for registration. */ s_new.their_session_nonce = curvecpr_bytes_unpack_uint64(p->nonce); curvecpr_bytes_copy(s_new.my_domain_name, p_box->server_domain_name, 256); curvecpr_session_set_priv(&s_new, priv); if (cf->ops.put_session(server, &s_new, &s_new_stored)) return -EINVAL; /* This can fail for a variety of reasons that are up to the delegate to determine, but two typical ones will be too many connections or an invalid domain name. */ /* Now the session is registered; we can send the encapsulated message. */ if (cf->ops.recv(server, s_new_stored, data + sizeof(struct curvecpr_packet_initiate_box), num + 16 - sizeof(struct curvecpr_packet_initiate_box))) return -EINVAL; return 0; } }
int zmq::curve_server_t::process_initiate (msg_t *msg_) { int rc = check_basic_command_structure (msg_); if (rc == -1) return -1; const size_t size = msg_->size (); const uint8_t *initiate = static_cast<uint8_t *> (msg_->data ()); if (size < 9 || memcmp (initiate, "\x08INITIATE", 9)) { session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); errno = EPROTO; return -1; } if (size < 257) { session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE); errno = EPROTO; return -1; } uint8_t cookie_nonce[crypto_secretbox_NONCEBYTES]; uint8_t cookie_plaintext[crypto_secretbox_ZEROBYTES + 64]; uint8_t cookie_box[crypto_secretbox_BOXZEROBYTES + 80]; // Open Box [C' + s'](t) memset (cookie_box, 0, crypto_secretbox_BOXZEROBYTES); memcpy (cookie_box + crypto_secretbox_BOXZEROBYTES, initiate + 25, 80); memcpy (cookie_nonce, "COOKIE--", 8); memcpy (cookie_nonce + 8, initiate + 9, 16); rc = crypto_secretbox_open (cookie_plaintext, cookie_box, sizeof cookie_box, cookie_nonce, _cookie_key); if (rc != 0) { // CURVE I: cannot open client INITIATE cookie session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); errno = EPROTO; return -1; } // Check cookie plain text is as expected [C' + s'] if (memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES, _cn_client, 32) || memcmp (cookie_plaintext + crypto_secretbox_ZEROBYTES + 32, _cn_secret, 32)) { // TODO this case is very hard to test, as it would require a modified // client that knows the server's secret temporary cookie key // CURVE I: client INITIATE cookie is not valid session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); errno = EPROTO; return -1; } const size_t clen = (size - 113) + crypto_box_BOXZEROBYTES; uint8_t initiate_nonce[crypto_box_NONCEBYTES]; uint8_t initiate_plaintext[crypto_box_ZEROBYTES + 128 + 256]; uint8_t initiate_box[crypto_box_BOXZEROBYTES + 144 + 256]; // Open Box [C + vouch + metadata](C'->S') memset (initiate_box, 0, crypto_box_BOXZEROBYTES); memcpy (initiate_box + crypto_box_BOXZEROBYTES, initiate + 113, clen - crypto_box_BOXZEROBYTES); memcpy (initiate_nonce, "CurveZMQINITIATE", 16); memcpy (initiate_nonce + 16, initiate + 105, 8); cn_peer_nonce = get_uint64 (initiate + 105); rc = crypto_box_open (initiate_plaintext, initiate_box, clen, initiate_nonce, _cn_client, _cn_secret); if (rc != 0) { // CURVE I: cannot open client INITIATE session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); errno = EPROTO; return -1; } const uint8_t *client_key = initiate_plaintext + crypto_box_ZEROBYTES; uint8_t vouch_nonce[crypto_box_NONCEBYTES]; uint8_t vouch_plaintext[crypto_box_ZEROBYTES + 64]; uint8_t vouch_box[crypto_box_BOXZEROBYTES + 80]; // Open Box Box [C',S](C->S') and check contents memset (vouch_box, 0, crypto_box_BOXZEROBYTES); memcpy (vouch_box + crypto_box_BOXZEROBYTES, initiate_plaintext + crypto_box_ZEROBYTES + 48, 80); memcpy (vouch_nonce, "VOUCH---", 8); memcpy (vouch_nonce + 8, initiate_plaintext + crypto_box_ZEROBYTES + 32, 16); rc = crypto_box_open (vouch_plaintext, vouch_box, sizeof vouch_box, vouch_nonce, client_key, _cn_secret); if (rc != 0) { // CURVE I: cannot open client INITIATE vouch session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC); errno = EPROTO; return -1; } // What we decrypted must be the client's short-term public key if (memcmp (vouch_plaintext + crypto_box_ZEROBYTES, _cn_client, 32)) { // TODO this case is very hard to test, as it would require a modified // client that knows the server's secret short-term key // CURVE I: invalid handshake from client (public key) session->get_socket ()->event_handshake_failed_protocol ( session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_KEY_EXCHANGE); errno = EPROTO; return -1; } // Precompute connection secret from client key rc = crypto_box_beforenm (cn_precom, _cn_client, _cn_secret); zmq_assert (rc == 0); // Given this is a backward-incompatible change, it's behind a socket // option disabled by default. if (zap_required () || !options.zap_enforce_domain) { // Use ZAP protocol (RFC 27) to authenticate the user. rc = session->zap_connect (); if (rc == 0) { send_zap_request (client_key); state = waiting_for_zap_reply; // TODO actually, it is quite unlikely that we can read the ZAP // reply already, but removing this has some strange side-effect // (probably because the pipe's in_active flag is true until a read // is attempted) rc = receive_and_process_zap_reply (); if (rc == -1) return -1; } else if (!options.zap_enforce_domain) { // This supports the Stonehouse pattern (encryption without // authentication) in legacy mode (domain set but no handler). state = sending_ready; } else { session->get_socket ()->event_handshake_failed_no_detail ( session->get_endpoint (), EFAULT); return -1; } } else { // This supports the Stonehouse pattern (encryption without authentication). state = sending_ready; } return parse_metadata (initiate_plaintext + crypto_box_ZEROBYTES + 128, clen - crypto_box_ZEROBYTES - 128); }