Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
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;
}
Exemple #4
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;
}
Exemple #5
0
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;
}
Exemple #6
0
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;
}
Exemple #8
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);
}
Exemple #11
0
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;
}
Exemple #12
0
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;}
Exemple #13
0
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;
}
Exemple #14
0
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;
}
Exemple #15
0
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;
}
Exemple #16
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;
    }
Exemple #18
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;
}
Exemple #19
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;
}
Exemple #20
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();
}
Exemple #21
0
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;
}
Exemple #22
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;
}
Exemple #23
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;
}
Exemple #24
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);
}
Exemple #26
0
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);
}
Exemple #27
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.
 * 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);
}
Exemple #28
0
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);
}
Exemple #29
0
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);
}