return crypto_unlock_aead(plain_text, key, nonce, mac, 0, 0,
cipher_text, text_size);
}
+
+///////////////////////
+/// Secure channels ///
+///////////////////////
+static void copy32(u8 out[32], const u8 in[32]){FOR (i, 0, 32){out[i] = in[i];}}
+static void xor32 (u8 out[32], const u8 in[32]){FOR (i, 0, 32){out[i]^= in[i];}}
+
+static void kex_update_key(crypto_kex_ctx *ctx,
+ const u8 secret_key[32],
+ const u8 public_key[32])
+{
+ static const u8 one[16] = {1};
+
+ // Extract
+ u8 shared_secret[32];
+ crypto_x25519(shared_secret, secret_key, public_key);
+ crypto_chacha20_H(shared_secret , shared_secret , zero);
+ crypto_chacha20_H(ctx->chaining_key, ctx->chaining_key, one );
+ xor32(ctx->chaining_key, shared_secret);
+
+ // Expand (directly from chaining key)
+ crypto_chacha_ctx chacha_ctx;
+ crypto_chacha20_init (&chacha_ctx, ctx->chaining_key, one);
+ crypto_chacha20_stream(&chacha_ctx, ctx->derived_keys, 64);
+
+ // Clean up
+ WIPE_BUFFER(shared_secret);
+ WIPE_CTX(&chacha_ctx);
+}
+
+static void kex_auth(crypto_kex_ctx *ctx, u8 mac[16])
+{
+ crypto_poly1305(mac, ctx->transcript, ctx->transcript_size,
+ ctx->derived_keys);
+}
+
+static int kex_verify(crypto_kex_ctx *ctx, const u8 mac[16])
+{
+ u8 real_mac[16];
+ kex_auth(ctx, real_mac);
+ int mismatch = crypto_verify16(real_mac, mac);
+ if (mismatch) { WIPE_CTX(ctx); }
+ WIPE_BUFFER(real_mac);
+ return mismatch;
+}
+
+static void kex_send(crypto_kex_ctx *ctx, u8 msg[32], const u8 src[32])
+{
+ // Send message, encrypted if we have a key
+ copy32(msg, src);
+ xor32(msg, ctx->derived_keys + 32);
+ // Record sent message
+ copy32(ctx->transcript + ctx->transcript_size, msg);
+ ctx->transcript_size += 32;
+}
+
+static void kex_receive(crypto_kex_ctx *ctx, u8 dest[32], const u8 msg[32])
+{
+ // Record incoming message
+ copy32(ctx->transcript + ctx->transcript_size, msg);
+ ctx->transcript_size += 32;
+ // Receive message, decrypted it if we have a key
+ copy32(dest, msg);
+ xor32(dest, ctx->derived_keys + 32);
+}
+
+static void kex_init(crypto_kex_ctx *ctx,
+ const u8 local_sk[32],
+ const u8 local_pk[32])
+{
+ if (local_pk == 0) crypto_x25519_public_key(ctx->local_pk, local_sk);
+ else copy32 (ctx->local_pk, local_pk);
+ copy32(ctx->chaining_key , zero );
+ copy32(ctx->derived_keys + 32, zero ); // first encryption key is zero
+ copy32(ctx->local_sk , local_sk);
+ ctx->transcript_size = 0;
+}
+
+static void kex_seed(crypto_kex_ctx *ctx, u8 random_seed[32])
+{
+ copy32(ctx->local_ske , random_seed);
+ crypto_wipe(random_seed, 32); // auto wipe seed to avoid reuse
+ crypto_x25519_public_key(ctx->local_pke, ctx->local_ske);
+}
+
+
+///////////
+/// XK1 ///
+///////////
+static const u8 xk1_ck0[32] = "Monokex XK1";
+void crypto_kex_xk1_init_client(crypto_kex_ctx *ctx,
+ u8 random_seed[32],
+ const u8 local_sk [32],
+ const u8 local_pk [32],
+ const u8 remote_pk [32])
+{
+ kex_init (ctx, local_sk, local_pk);
+ kex_seed (ctx, random_seed);
+ kex_receive(ctx, ctx->remote_pk, remote_pk);
+ copy32(ctx->chaining_key, xk1_ck0);
+}
+
+void crypto_kex_xk1_init_server(crypto_kex_ctx *ctx,
+ u8 random_seed[32],
+ const u8 local_sk [32],
+ const u8 local_pk [32])
+{
+ kex_init (ctx, local_sk, local_pk);
+ kex_seed (ctx, random_seed);
+ kex_receive(ctx, ctx->local_pk, ctx->local_pk);
+ copy32(ctx->chaining_key, xk1_ck0);
+}
+
+void crypto_kex_xk1_1(crypto_kex_ctx *ctx, u8 msg1[32])
+{
+ kex_send (ctx, msg1 , ctx->local_pke ); // -> IE
+}
+
+void crypto_kex_xk1_2(crypto_kex_ctx *ctx, u8 msg2[48], const u8 msg1[32])
+{
+ kex_receive (ctx, ctx->remote_pke, msg1 ); // -> IE
+ kex_send (ctx, msg2 , ctx->local_pke ); // <- RE
+ kex_update_key(ctx, ctx->local_ske , ctx->remote_pke); // ee
+ kex_update_key(ctx, ctx->local_sk , ctx->remote_pke); // es
+ kex_auth (ctx, msg2 + 32); // auth
+}
+
+int crypto_kex_xk1_3(crypto_kex_ctx *ctx,
+ u8 session_key[32],
+ u8 msg3[48],
+ const u8 msg2[48])
+{
+ kex_receive (ctx, ctx->remote_pke, msg2 ); // <- RE
+ kex_update_key(ctx, ctx->local_ske , ctx->remote_pke); // ee
+ kex_update_key(ctx, ctx->local_ske , ctx->remote_pk ); // es
+ if (kex_verify(ctx, msg2 + 32)) { return -1; } // verify
+ kex_send (ctx, msg3 , ctx->local_pk ); // -> IS
+ kex_update_key(ctx, ctx->local_sk , ctx->remote_pke); // se
+ kex_auth (ctx, msg3 + 32); // auth
+ copy32(session_key, ctx->derived_keys + 32);
+ WIPE_CTX(ctx);
+ return 0;
+}
+
+int crypto_kex_xk1_4(crypto_kex_ctx *ctx,
+ u8 session_key[32],
+ u8 remote_pk[32],
+ const u8 msg3[48])
+{
+ kex_receive (ctx, ctx->remote_pk , msg3 ); // -> IS
+ kex_update_key(ctx, ctx->local_ske , ctx->remote_pk ); // se
+ if (kex_verify(ctx, msg3 + 32)) { return -1; } // verify
+ copy32(remote_pk , ctx->remote_pk);
+ copy32(session_key, ctx->derived_keys + 32);
+ WIPE_CTX(ctx);
+ return 0;
+}
+
+/////////
+/// X ///
+/////////
+static const u8 x_ck0[32] = "Monokex X";
+void crypto_kex_x_init_client(crypto_kex_ctx *ctx,
+ u8 random_seed[32],
+ const u8 local_sk [32],
+ const u8 local_pk [32],
+ const u8 remote_pk [32])
+{
+ kex_init (ctx, local_sk, local_pk);
+ kex_seed (ctx, random_seed);
+ kex_receive(ctx, ctx->remote_pk, remote_pk);
+ copy32(ctx->chaining_key, x_ck0);
+}
+
+void crypto_kex_x_init_server(crypto_kex_ctx *ctx,
+ const u8 local_sk[32],
+ const u8 local_pk[32])
+{
+ kex_init (ctx, local_sk, local_pk);
+ kex_receive(ctx, ctx->local_pk, ctx->local_pk);
+ copy32(ctx->chaining_key, x_ck0);
+}
+
+void crypto_kex_x_1(crypto_kex_ctx *ctx, u8 session_key[32], u8 msg1[80])
+{
+ kex_send (ctx, msg1 , ctx->local_pke ); // -> IE
+ kex_update_key(ctx, ctx->local_ske , ctx->remote_pk ); // es
+ kex_send (ctx, msg1 + 32 , ctx->local_pk ); // -> IS
+ kex_update_key(ctx, ctx->local_sk , ctx->remote_pk ); // ss
+ kex_auth (ctx, msg1 + 64); // auth
+ copy32(session_key, ctx->derived_keys + 32);
+ WIPE_CTX(ctx);
+}
+
+int crypto_kex_x_2(crypto_kex_ctx *ctx,
+ u8 session_key[32],
+ u8 remote_pk [32],
+ const u8 msg1 [80])
+{
+ kex_receive (ctx, ctx->remote_pke, msg1 ); // -> IE
+ kex_update_key(ctx, ctx->local_sk , ctx->remote_pke); // es
+ kex_receive (ctx, ctx->remote_pk , msg1 + 32 ); // -> IS
+ kex_update_key(ctx, ctx->local_sk , ctx->remote_pk ); // ss
+ if (kex_verify(ctx, msg1 + 64)) { return -1; } // verify
+ copy32(remote_pk , ctx->remote_pk);
+ copy32(session_key, ctx->derived_keys + 32);
+ WIPE_CTX(ctx);
+ return 0;
+}
+
uint8_t pk [32];
} crypto_check_ctx;
+// Secure channels (Monokex)
+typedef struct {
+ uint8_t transcript [128];
+ uint8_t chaining_key[32];
+ uint8_t derived_keys[64];
+ uint8_t local_sk [32];
+ uint8_t local_pk [32];
+ uint8_t local_ske [32];
+ uint8_t local_pke [32];
+ uint8_t remote_pk [32];
+ uint8_t remote_pke [32];
+ size_t transcript_size;
+} crypto_kex_ctx;
////////////////////////////
/// High level interface ///
int crypto_check_final (crypto_check_ctx *ctx);
+// Secure channel (interactive)
+// ----------------------------
+void crypto_kex_xk1_init_client(crypto_kex_ctx *ctx,
+ uint8_t random_seed[32],
+ const uint8_t local_sk [32],
+ const uint8_t local_pk [32],
+ const uint8_t remote_pk [32]);
+void crypto_kex_xk1_init_server(crypto_kex_ctx *ctx,
+ uint8_t random_seed[32],
+ const uint8_t local_sk [32],
+ const uint8_t local_pk [32]);
+
+void crypto_kex_xk1_1(crypto_kex_ctx *ctx,
+ uint8_t msg1[32]);
+void crypto_kex_xk1_2(crypto_kex_ctx *ctx,
+ uint8_t msg2[48],
+ const uint8_t msg1[32]);
+int crypto_kex_xk1_3(crypto_kex_ctx *ctx,
+ uint8_t session_key[32],
+ uint8_t msg3 [48],
+ const uint8_t msg2 [48]);
+int crypto_kex_xk1_4(crypto_kex_ctx *ctx,
+ uint8_t session_key[32],
+ uint8_t remote_pk [32],
+ const uint8_t msg3 [48]);
+
+// Secure channel (one way)
+// ------------------------
+void crypto_kex_x_init_client(crypto_kex_ctx *ctx,
+ uint8_t random_seed[32],
+ const uint8_t local_sk [32],
+ const uint8_t local_pk [32],
+ const uint8_t remote_pk [32]);
+void crypto_kex_x_init_server(crypto_kex_ctx *ctx,
+ const uint8_t local_sk [32],
+ const uint8_t local_pk [32]);
+void crypto_kex_x_1(crypto_kex_ctx *ctx,
+ uint8_t session_key[32],
+ uint8_t msg1 [80]);
+int crypto_kex_x_2(crypto_kex_ctx *ctx,
+ uint8_t session_key[32],
+ uint8_t remote_pk [32],
+ const uint8_t msg1 [80]);
+
+
////////////////////////////
/// Low level primitives ///
////////////////////////////
.PHONY: all clean
-VEC = chacha20.vec hchacha20.vec xchacha20.vec aead_ietf.vec poly1305.vec \
- blake2b.vec sha512.vec argon2i.vec \
- edDSA.vec edDSA_pk.vec ed_25519.vec ed_25519_check.vec \
- x25519.vec x25519_pk.vec
-VEC2 = $(patsubst %.vec, %.all.vec, $(VEC)) key_exchange.all.vec
-HEADERS = $(patsubst %.all.vec, %.h.vec, $(VEC2))
+VEC = chacha20 hchacha20 xchacha20 aead_ietf poly1305 \
+ blake2b sha512 argon2i \
+ edDSA edDSA_pk ed_25519 ed_25519_check \
+ x25519 x25519_pk key_exchange \
+ monokex_xk1 monokex_x
+VEC2 = $(patsubst %, %.all.vec, $(VEC))
+HEADERS = $(patsubst %, %.h.vec , $(VEC))
VECTORS = ../vectors.h
all: $(VECTORS)
vector_to_header.out: ../vector_to_header.c
$(CC) $(CFLAGS) $< -o $@
-chacha20.all.vec : chacha20.vec ../vectors/chacha20
-poly1305.all.vec : poly1305.vec ../vectors/poly1305
-x25519.all.vec : x25519.vec ../vectors/x25519
+chacha20.all.vec : chacha20.vec ../vectors/chacha20
+poly1305.all.vec : poly1305.vec ../vectors/poly1305
+x25519.all.vec : x25519.vec ../vectors/x25519
x25519_pk.all.vec : x25519_pk.vec
hchacha20.all.vec : hchacha20.vec
xchacha20.all.vec : xchacha20.vec
aead_ietf.all.vec : aead_ietf.vec
blake2b.all.vec : blake2b.vec
sha512.all.vec : sha512.vec
-argon2i.all.vec : argon2i.vec ../vectors/argon2i
+argon2i.all.vec : argon2i.vec ../vectors/argon2i
edDSA.all.vec : edDSA.vec
edDSA_pk.all.vec : edDSA_pk.vec
ed_25519.all.vec : ed_25519.vec
-ed_25519_check.all.vec: ../vectors/ed_25519_check
-key_exchange.all.vec : ../vectors/key_exchange
+ed_25519_check.all.vec: ../vectors/ed_25519_check
+key_exchange.all.vec : ../vectors/key_exchange
+monokex_xk1.all.vec : monokex_xk1.vec
+monokex_x.all.vec : monokex_x.vec
$(VEC2):
mkdir -p $(@D)
cat $^ > $@
--- /dev/null
+#include <sodium.h>
+#include "utils.h"
+
+static const uint8_t zero[32] = {0};
+static const uint8_t one [16] = {1};
+
+static void crypto_chacha20_H(uint8_t out[32],
+ const uint8_t key[32],
+ const uint8_t in [16])
+{
+ crypto_core_hchacha20(out, in, key, 0);
+}
+int crypto_x25519(uint8_t shared[32],
+ const uint8_t sk [32],
+ const uint8_t pk [32])
+{
+ return crypto_scalarmult(shared, sk, pk);
+}
+#define crypto_x25519_public_key crypto_scalarmult_base
+#define crypto_poly1305_ctx crypto_onetimeauth_state
+#define crypto_poly1305_init crypto_onetimeauth_init
+#define crypto_poly1305_update crypto_onetimeauth_update
+#define crypto_poly1305_final crypto_onetimeauth_final
+
+static void xor(uint8_t out[32], const uint8_t a[32], const uint8_t b[32])
+{
+ for (unsigned i = 0; i < 32; i++) {
+ out[i] = a[i] ^ b[i];
+ }
+}
+
+static void copy(uint8_t out[32], const uint8_t in[32])
+{
+ for (unsigned i = 0; i < 32; i++) {
+ out[i] = in[i];
+ }
+}
+
+static void chacha_block(uint8_t out[64],
+ const uint8_t key[32],
+ const uint8_t nonce[16])
+{
+ static const uint8_t in[64] = {0};
+ crypto_stream_chacha20_xor_ic(out, in, 64, nonce, 0, key);
+}
+
+typedef struct {
+ // Key pairs
+ uint8_t is[32]; uint8_t IS[32];
+ uint8_t ie[32]; uint8_t IE[32];
+ uint8_t rs[32]; uint8_t RS[32];
+
+ // Shared secrets
+ uint8_t es[32];
+ uint8_t ss[32];
+
+ // Symmetric Keys
+ uint8_t CK1[32];
+ uint8_t CK2[32];
+ uint8_t AK2[32];
+ uint8_t EK1[32];
+ uint8_t EK2[32];
+
+ // Messages
+ uint8_t msg1[80];
+} test_vectors_x;
+
+static void vectors_x_fill(test_vectors_x *v,
+ const uint8_t client_sk [32],
+ const uint8_t server_sk [32],
+ const uint8_t client_seed[32])
+{
+ // Private keys
+ copy(v->is, client_sk );
+ copy(v->ie, client_seed);
+ copy(v->rs, server_sk );
+
+ // Public keys
+ crypto_x25519_public_key(v->IS, v->is);
+ crypto_x25519_public_key(v->IE, v->ie);
+ crypto_x25519_public_key(v->RS, v->rs);
+
+ // Exchanges
+ crypto_x25519(v->es, v->ie, v->RS);
+ crypto_x25519(v->ss, v->is, v->RS);
+
+ // Keys
+ uint8_t tmp1[32];
+ uint8_t tmp2[32];
+ uint8_t CK0 [32] = "Monokex X";
+ crypto_chacha20_H(tmp1, v->es , zero);
+ crypto_chacha20_H(tmp2, CK0 , one );
+ xor(v->CK1, tmp1, tmp2);
+ crypto_chacha20_H(tmp1, v->ss , zero);
+ crypto_chacha20_H(tmp2, v->CK1, one );
+ xor(v->CK2, tmp1, tmp2);
+ uint8_t tmp[64];
+ chacha_block(tmp, v->CK1, one);
+ copy(v->EK1, tmp + 32);
+ chacha_block(tmp, v->CK2, one);
+ copy(v->AK2, tmp );
+ copy(v->EK2, tmp + 32);
+
+ // Messages
+ crypto_poly1305_ctx ctx;
+ uint8_t XIS[32];
+ xor(XIS, v->IS, v->EK1);
+ copy(v->msg1 , v->IE);
+ copy(v->msg1 + 32, XIS );
+ crypto_poly1305_init (&ctx, v->AK2);
+ crypto_poly1305_update(&ctx, v->RS, 32);
+ crypto_poly1305_update(&ctx, v->IE, 32);
+ crypto_poly1305_update(&ctx, XIS , 32);
+ crypto_poly1305_final (&ctx, v->msg1 + 64);
+}
+
+int main(void)
+{
+ FOR(i, 0, 5) {
+ RANDOM_INPUT(client_sk , 32);
+ RANDOM_INPUT(server_sk , 32);
+ RANDOM_INPUT(client_seed, 32);
+ RANDOM_INPUT(server_seed, 32);
+ test_vectors_x v;
+ vectors_x_fill(&v, client_sk, server_sk, client_seed);
+
+ print_vector(v.is , 32);
+ print_vector(v.ie , 32);
+ print_vector(v.rs , 32);
+ print_vector(v.IS , 32);
+ print_vector(v.RS , 32);
+ print_vector(v.msg1, 80);
+ print_vector(v.EK2 , 32);
+ }
+ return 0;
+}
--- /dev/null
+#include <sodium.h>
+#include "utils.h"
+
+static const uint8_t zero[32] = {0};
+static const uint8_t one [16] = {1};
+
+static void crypto_chacha20_H(uint8_t out[32],
+ const uint8_t key[32],
+ const uint8_t in [16])
+{
+ crypto_core_hchacha20(out, in, key, 0);
+}
+int crypto_x25519(uint8_t shared[32],
+ const uint8_t sk [32],
+ const uint8_t pk [32])
+{
+ return crypto_scalarmult(shared, sk, pk);
+}
+#define crypto_x25519_public_key crypto_scalarmult_base
+#define crypto_poly1305_ctx crypto_onetimeauth_state
+#define crypto_poly1305_init crypto_onetimeauth_init
+#define crypto_poly1305_update crypto_onetimeauth_update
+#define crypto_poly1305_final crypto_onetimeauth_final
+
+static void xor(uint8_t out[32], const uint8_t a[32], const uint8_t b[32])
+{
+ for (unsigned i = 0; i < 32; i++) {
+ out[i] = a[i] ^ b[i];
+ }
+}
+
+static void copy(uint8_t out[32], const uint8_t in[32])
+{
+ for (unsigned i = 0; i < 32; i++) {
+ out[i] = in[i];
+ }
+}
+
+static void chacha_block(uint8_t out[64],
+ const uint8_t key[32],
+ const uint8_t nonce[16])
+{
+ static const uint8_t in[64] = {0};
+ crypto_stream_chacha20_xor_ic(out, in, 64, nonce, 0, key);
+}
+
+typedef struct {
+ // Key pairs
+ uint8_t is[32]; uint8_t IS[32];
+ uint8_t ie[32]; uint8_t IE[32];
+ uint8_t rs[32]; uint8_t RS[32];
+ uint8_t re[32]; uint8_t RE[32];
+
+ // Shared secrets
+ uint8_t ee[32];
+ uint8_t es[32];
+ uint8_t se[32];
+
+ // Symmetric keys
+ uint8_t CK1[32];
+ uint8_t CK2[32];
+ uint8_t CK3[32];
+ uint8_t AK2[32];
+ uint8_t AK3[32];
+ uint8_t EK2[32];
+ uint8_t EK3[32];
+
+ // Messages
+ uint8_t msg1[32];
+ uint8_t msg2[48];
+ uint8_t msg3[48];
+} test_vectors_xk1;
+
+static void vectors_xk1_fill(test_vectors_xk1 *v,
+ const uint8_t client_sk [32],
+ const uint8_t server_sk [32],
+ const uint8_t client_seed[32],
+ const uint8_t server_seed[32])
+{
+ // Private keys
+ copy(v->is, client_sk );
+ copy(v->ie, client_seed);
+ copy(v->rs, server_sk );
+ copy(v->re, server_seed);
+
+ // Public keys
+ crypto_x25519_public_key(v->IS, v->is);
+ crypto_x25519_public_key(v->IE, v->ie);
+ crypto_x25519_public_key(v->RS, v->rs);
+ crypto_x25519_public_key(v->RE, v->re);
+
+ // Shared secrets
+ crypto_x25519(v->ee, v->ie, v->RE);
+ crypto_x25519(v->es, v->ie, v->RS);
+ crypto_x25519(v->se, v->is, v->RE);
+
+ // Keys
+ uint8_t tmp1[32];
+ uint8_t tmp2[32];
+ uint8_t CK0 [32] = "Monokex XK1";
+ crypto_chacha20_H(tmp1, v->ee , zero);
+ crypto_chacha20_H(tmp2, CK0 , one );
+ xor(v->CK1, tmp1, tmp2);
+ crypto_chacha20_H(tmp1, v->es , zero);
+ crypto_chacha20_H(tmp2, v->CK1, one );
+ xor(v->CK2, tmp1, tmp2);
+ crypto_chacha20_H(tmp1, v->se , zero);
+ crypto_chacha20_H(tmp2, v->CK2, one );
+ xor(v->CK3, tmp1, tmp2);
+ uint8_t tmp[64];
+ chacha_block(tmp, v->CK2, one);
+ copy(v->AK2, tmp );
+ copy(v->EK2, tmp + 32);
+ chacha_block(tmp, v->CK3, one);
+ copy(v->AK3, tmp );
+ copy(v->EK3, tmp + 32);
+
+ // Messages
+ crypto_poly1305_ctx ctx;
+ uint8_t XIS[32];
+ xor(XIS, v->IS, v->EK2);
+ copy(v->msg1, v->IE);
+ copy(v->msg2, v->RE);
+ crypto_poly1305_init (&ctx, v->AK2);
+ crypto_poly1305_update(&ctx, v->RS, 32);
+ crypto_poly1305_update(&ctx, v->IE, 32);
+ crypto_poly1305_update(&ctx, v->RE, 32);
+ crypto_poly1305_final (&ctx, v->msg2 + 32);
+ copy(v->msg3, XIS);
+ crypto_poly1305_init (&ctx, v->AK3);
+ crypto_poly1305_update(&ctx, v->RS, 32);
+ crypto_poly1305_update(&ctx, v->IE, 32);
+ crypto_poly1305_update(&ctx, v->RE, 32);
+ crypto_poly1305_update(&ctx, XIS , 32);
+ crypto_poly1305_final (&ctx, v->msg3 + 32);
+}
+
+int main(void)
+{
+ FOR(i, 0, 5) {
+ RANDOM_INPUT(client_sk , 32);
+ RANDOM_INPUT(server_sk , 32);
+ RANDOM_INPUT(client_seed, 32);
+ RANDOM_INPUT(server_seed, 32);
+ test_vectors_xk1 v;
+ vectors_xk1_fill(&v, client_sk, server_sk, client_seed, server_seed);
+
+ print_vector(v.is , 32);
+ print_vector(v.ie , 32);
+ print_vector(v.rs , 32);
+ print_vector(v.re , 32);
+ print_vector(v.IS , 32);
+ print_vector(v.RS , 32);
+ print_vector(v.msg1, 32);
+ print_vector(v.msg2, 48);
+ print_vector(v.msg3, 48);
+ print_vector(v.EK3 , 32);
+ }
+ return 0;
+}
TIMING_END;
}
+static void get_interactive_session(u8 msg1[32], u8 msg2[48], u8 msg3[48],
+ u8 client_pk[32], u8 server_pk[32],
+ const u8 client_sk [32],
+ const u8 server_sk [32],
+ const u8 client_seed[32],
+ const u8 server_seed[32])
+{
+ crypto_key_exchange_public_key(client_pk, client_sk);
+ crypto_key_exchange_public_key(server_pk, server_sk);
+
+ u8 c_seed[32];
+ u8 s_seed[32];
+ FOR (i, 0, 32) {
+ c_seed[i] = client_seed[i];
+ s_seed[i] = server_seed[i];
+ }
+ crypto_kex_ctx client_ctx;
+ crypto_kex_xk1_init_client(&client_ctx, c_seed, client_sk, client_pk,
+ server_pk);
+ crypto_kex_ctx server_ctx;
+ crypto_kex_xk1_init_server(&server_ctx, s_seed, server_sk, server_pk);
+
+ crypto_kex_xk1_1(&client_ctx, msg1);
+ crypto_kex_xk1_2(&server_ctx, msg2, msg1);
+
+ u8 client_session_key[32];
+ if (crypto_kex_xk1_3(&client_ctx, client_session_key,
+ msg3, msg2)) {
+ fprintf(stderr, "Cannot confirm\n");
+ return;
+ }
+
+ u8 server_session_key[32];
+ u8 remote_pk [32]; // same as client_pk
+ if (crypto_kex_xk1_4(&server_ctx, server_session_key, remote_pk,
+ msg3)) {
+ fprintf(stderr, "Cannot accept\n");
+ return;
+ }
+
+ if (crypto_verify32(client_session_key, server_session_key)) {
+ fprintf(stderr, "Different session keys\n");
+ return;
+ }
+ if (crypto_verify32(remote_pk, client_pk)) {
+ fprintf(stderr, "Server got the wrong client public key\n");
+ return;
+ }
+}
+
+
+static u64 interactive_client(void)
+{
+ RANDOM_INPUT(client_sk, 32);
+ RANDOM_INPUT(server_sk, 32);
+ RANDOM_INPUT(client_seed, 32);
+ RANDOM_INPUT(server_seed, 32);
+ u8 msg1[32]; u8 msg2[48]; u8 msg3[48];
+ u8 client_pk[32]; u8 server_pk[32];
+ get_interactive_session(msg1, msg2, msg3,
+ client_pk , server_pk,
+ client_sk , server_sk,
+ client_seed, server_seed);
+ TIMING_START {
+ u8 session_key[32];
+ crypto_kex_ctx client_ctx;
+ u8 seed[32];
+ FOR (i, 0, 32) {
+ seed[i] = client_seed[i];
+ }
+ crypto_kex_xk1_init_client(&client_ctx, seed, client_sk, client_pk,
+ server_pk);
+ crypto_kex_xk1_1(&client_ctx, msg1);
+ if (crypto_kex_xk1_3(&client_ctx, session_key,
+ msg3, msg2)) {
+ fprintf(stderr, "Cannot confirm\n");
+ return 1;
+ }
+ }
+ TIMING_END;
+}
+
+static u64 interactive_server(void)
+{
+ RANDOM_INPUT(client_sk, 32);
+ RANDOM_INPUT(server_sk, 32);
+ RANDOM_INPUT(client_seed, 32);
+ RANDOM_INPUT(server_seed, 32);
+ u8 msg1[32]; u8 msg2[48]; u8 msg3[48];
+ u8 client_pk[32]; u8 server_pk[32];
+ get_interactive_session(msg1, msg2, msg3,
+ client_pk , server_pk,
+ client_sk , server_sk,
+ client_seed, server_seed);
+ TIMING_START {
+ u8 session_key[32];
+ u8 remote_pk [32]; // same as client_pk
+ crypto_kex_ctx server_ctx;
+ u8 seed[32];
+ FOR (i, 0, 32) {
+ seed[i] = server_seed[i];
+ }
+ crypto_kex_xk1_init_server(&server_ctx, seed, server_sk, server_pk);
+ crypto_kex_xk1_2(&server_ctx, msg2, msg1);
+ if (crypto_kex_xk1_4(&server_ctx, session_key, remote_pk,
+ msg3)) {
+ fprintf(stderr, "Cannot accept\n");
+ return 1;
+ }
+ }
+ TIMING_END;
+}
+
+static void get_one_way_session(u8 msg[80], u8 client_pk[32], u8 server_pk[32],
+ const u8 client_sk [32],
+ const u8 server_sk [32],
+ const u8 client_seed[32])
+{
+ crypto_key_exchange_public_key(client_pk, client_sk);
+ crypto_key_exchange_public_key(server_pk, server_sk);
+
+ u8 c_seed[32];
+ FOR (i, 0, 32) {
+ c_seed[i] = client_seed[i];
+ }
+
+ crypto_kex_ctx client_ctx;
+ crypto_kex_x_init_client(&client_ctx, c_seed, client_sk, client_pk,
+ server_pk);
+ crypto_kex_ctx server_ctx;
+ crypto_kex_x_init_server(&server_ctx, server_sk, server_pk);
+
+ u8 client_session_key[32];
+ crypto_kex_x_1(&client_ctx, client_session_key, msg);
+
+ u8 server_session_key[32];
+ u8 remote_pk [32]; // same as client_pk
+ if (crypto_kex_x_2(&server_ctx, server_session_key, remote_pk, msg)) {
+ fprintf(stderr, "Cannot receive\n");
+ return;
+ }
+
+ if (crypto_verify32(client_session_key, server_session_key)) {
+ fprintf(stderr, "Different session keys\n");
+ return;
+ }
+ if (crypto_verify32(remote_pk, client_pk)) {
+ fprintf(stderr, "Server got the wrong client public key\n");
+ return;
+ }
+}
+
+static u64 one_way_client(void)
+{
+ RANDOM_INPUT(client_sk, 32);
+ RANDOM_INPUT(server_sk, 32);
+ RANDOM_INPUT(client_seed, 32);
+ u8 msg[80]; u8 client_pk[32]; u8 server_pk[32];
+ get_one_way_session(msg,
+ client_pk, server_pk,
+ client_sk, server_sk,
+ client_seed);
+ TIMING_START {
+ u8 session_key[32];
+ u8 seed[32];
+ FOR (i, 0, 32) {
+ seed[i] = client_seed[i];
+ }
+ crypto_kex_ctx client_ctx;
+ crypto_kex_x_init_client(&client_ctx, seed, client_sk, client_pk,
+ server_pk);
+ crypto_kex_x_1(&client_ctx, session_key, msg);
+ }
+ TIMING_END;
+}
+
+static u64 one_way_server(void)
+{
+ RANDOM_INPUT(client_sk, 32);
+ RANDOM_INPUT(server_sk, 32);
+ RANDOM_INPUT(client_seed, 32);
+ u8 msg[80]; u8 client_pk[32]; u8 server_pk[32];
+ get_one_way_session(msg,
+ client_pk, server_pk,
+ client_sk, server_sk,
+ client_seed);
+ TIMING_START {
+ u8 session_key[32];
+ u8 remote_pk [32]; // same as client_pk
+ crypto_kex_ctx server_ctx;
+ crypto_kex_x_init_server(&server_ctx, server_sk, server_pk);
+ if (crypto_kex_x_2(&server_ctx, session_key, remote_pk, msg)) {
+ fprintf(stderr, "Cannot receive\n");
+ return 1;
+ }
+ }
+ TIMING_END;
+}
+
int main()
{
- print("Chacha20 ",chacha20() *MUL,"megabytes per second");
- print("Poly1305 ",poly1305() *MUL,"megabytes per second");
- print("Auth'd encryption",authenticated()*MUL,"megabytes per second");
- print("Blake2b ",blake2b() *MUL,"megabytes per second");
- print("Sha512 ",sha512() *MUL,"megabytes per second");
- print("Argon2i, 3 passes",argon2i() *MUL,"megabytes per second");
- print("x25519 ",x25519() ,"exchanges per second");
- print("EdDSA(sign) ",edDSA_sign() ,"signatures per second");
- print("EdDSA(check) ",edDSA_check() ,"checks per second");
+ print("Chacha20 ",chacha20() *MUL ,"megabytes per second");
+ print("Poly1305 ",poly1305() *MUL ,"megabytes per second");
+ print("Auth'd encryption ",authenticated()*MUL ,"megabytes per second");
+ print("Blake2b ",blake2b() *MUL ,"megabytes per second");
+ print("Sha512 ",sha512() *MUL ,"megabytes per second");
+ print("Argon2i, 3 passes ",argon2i() *MUL ,"megabytes per second");
+ print("x25519 ",x25519() ,"exchanges per second");
+ print("EdDSA(sign) ",edDSA_sign() ,"signatures per second");
+ print("EdDSA(check) ",edDSA_check() ,"checks per second");
+ print("Monokex XK1 (client)",interactive_client(),"handshakes per second");
+ print("Monokex XK1 (server)",interactive_server(),"handshakes per second");
+ print("Monokex X (client)",one_way_client() ,"handshakes per second");
+ print("Monokex X (server)",one_way_server() ,"handshakes per second");
printf("\n");
return 0;
}
}
#endif
+static void monokex_xk1(const vector in[], vector *out)
+{
+ const vector *is = in;
+ const vector *ie = in + 1;
+ const vector *rs = in + 2;
+ const vector *re = in + 3;
+ const vector *IS = in + 4;
+ const vector *RS = in + 5;
+ const vector *msg1 = in + 6;
+ const vector *msg2 = in + 7;
+ const vector *msg3 = in + 8;
+ crypto_kex_ctx client;
+ crypto_kex_ctx server;
+ u8 client_seed[32]; memcpy(client_seed, ie->buf, ie->size);
+ u8 server_seed[32]; memcpy(server_seed, re->buf, re->size);
+ crypto_kex_xk1_init_client(&client, client_seed, is->buf, IS->buf, RS->buf);
+ crypto_kex_xk1_init_server(&server, server_seed, rs->buf, RS->buf);
+ u8 m1 [32];
+ u8 m2 [48];
+ u8 m3 [48];
+ u8 client_key[32];
+ u8 remote_pk [32];
+ crypto_kex_xk1_1(&client, m1);
+ crypto_kex_xk1_2(&server, m2, m1);
+ if (crypto_kex_xk1_3(&client, client_key, m3, m2)) {
+ fprintf(stderr, "FAILURE: crypto_kex_xk1_3\n");
+ return;
+ }
+ if (crypto_kex_xk1_4(&server, out->buf, remote_pk, m3)) {
+ fprintf(stderr, "FAILURE: crypto_kex_xk1_4\n");
+ return;
+ }
+#define COMPARE(local, vector) \
+ if (memcmp(local, vector->buf, vector->size)) { \
+ fprintf(stderr, "FAILURE: "#vector"\n"); \
+ return; \
+ }
+ COMPARE(m1 , msg1);
+ COMPARE(m2 , msg2);
+ COMPARE(m3 , msg3);
+ COMPARE(remote_pk , IS );
+ COMPARE(client_key, out );
+}
+
+static void monokex_x(const vector in[], vector *out)
+{
+ const vector *is = in;
+ const vector *ie = in + 1;
+ const vector *rs = in + 2;
+ const vector *IS = in + 3;
+ const vector *RS = in + 4;
+ const vector *msg1 = in + 5;
+ crypto_kex_ctx client;
+ crypto_kex_ctx server;
+ u8 seed[32]; memcpy(seed, ie->buf, ie->size);
+ crypto_kex_x_init_client(&client, seed, is->buf, IS->buf, RS->buf);
+ crypto_kex_x_init_server(&server, rs->buf, RS->buf);
+ u8 m1 [80];
+ u8 client_key[32];
+ u8 remote_pk [32];
+ crypto_kex_x_1(&client, client_key, m1);
+ if (crypto_kex_x_2(&server, out->buf, remote_pk, m1)) {
+ fprintf(stderr, "FAILURE: crypto_kex_x_2\n");
+ return;
+ }
+ COMPARE(m1 , msg1);
+ COMPARE(remote_pk , IS );
+ COMPARE(client_key, out );
+}
static void iterate_x25519(u8 k[32], u8 u[32])
{
u8 tmp[32];
return status;
}
+static int p_monokex_xk1()
+{
+ int status = 0;
+ RANDOM_INPUT(is, 32);
+ RANDOM_INPUT(ie, 32);
+ RANDOM_INPUT(rs, 32);
+ RANDOM_INPUT(re, 32);
+ u8 IS[32]; crypto_x25519_public_key(IS, is);
+ u8 RS[32]; crypto_x25519_public_key(RS, rs);
+
+ crypto_kex_ctx client1, client2;
+ crypto_kex_ctx server1, server2;
+ u8 client_seed1[32]; memcpy(client_seed1, ie, 32);
+ u8 client_seed2[32]; memcpy(client_seed2, ie, 32);
+ u8 server_seed1[32]; memcpy(server_seed1, re, 32);
+ u8 server_seed2[32]; memcpy(server_seed2, re, 32);
+
+ // Test the same thing, with and without the local pk
+ // (the API is supposed to reconstruct it)
+ crypto_kex_xk1_init_client(&client1, client_seed1, is, IS, RS);
+ crypto_kex_xk1_init_client(&client2, client_seed2, is, 0, RS);
+ crypto_kex_xk1_init_server(&server1, server_seed1, rs, RS);
+ crypto_kex_xk1_init_server(&server2, server_seed2, rs, 0);
+ u8 msg11 [32]; u8 msg12 [32];
+ u8 msg21 [48]; u8 msg22 [48];
+ u8 msg31 [48]; u8 msg32 [48];
+ u8 client_key1[32]; u8 client_key2[32];
+ u8 server_key1[32]; u8 server_key2[32];
+ u8 remote_pk1 [32]; u8 remote_pk2 [32];
+ crypto_kex_xk1_1(&client1, msg11);
+ crypto_kex_xk1_1(&client2, msg12);
+ crypto_kex_xk1_2(&server1, msg21, msg11);
+ crypto_kex_xk1_2(&server2, msg22, msg12);
+ // make sure everything is accepted as it should be
+ status |= crypto_kex_xk1_3(&client1, client_key1, msg31, msg21);
+ status |= crypto_kex_xk1_3(&client2, client_key2, msg32, msg22);
+ status |= crypto_kex_xk1_4(&server1, server_key1, remote_pk1, msg31);
+ status |= crypto_kex_xk1_4(&server2, server_key2, remote_pk2, msg32);
+ // Make sure we get the same result whether we gave the local pk or not
+ status |= memcmp(msg11 , msg12 , 32);
+ status |= memcmp(msg21 , msg22 , 48);
+ status |= memcmp(msg31 , msg32 , 48);
+ status |= memcmp(client_key1, client_key2, 32);
+ status |= memcmp(remote_pk1 , remote_pk2 , 32);
+ // make sure wrong messages are rejected as they should be.
+ msg21[1]++;
+ status |= !crypto_kex_xk1_3(&client1, client_key1, msg31, msg21);
+ msg32[1]++;
+ status |= !crypto_kex_xk1_4(&server2, server_key2, remote_pk2, msg32);
+
+ printf("%s: monokex_xk1\n", status != 0 ? "FAILED" : "OK");
+ return status;
+}
+
+static int p_monokex_x()
+{
+ int status = 0;
+ RANDOM_INPUT(is, 32);
+ RANDOM_INPUT(ie, 32);
+ RANDOM_INPUT(rs, 32);
+ u8 IS[32]; crypto_x25519_public_key(IS, is);
+ u8 RS[32]; crypto_x25519_public_key(RS, rs);
+
+ crypto_kex_ctx client1, client2;
+ crypto_kex_ctx server1, server2;
+ u8 seed1[32]; memcpy(seed1, ie, 32);
+ u8 seed2[32]; memcpy(seed2, ie, 32);
+ crypto_kex_x_init_client(&client1, seed1, is, IS, RS);
+ crypto_kex_x_init_client(&client2, seed2, is, 0, RS);
+ crypto_kex_x_init_server(&server1, rs, RS);
+ crypto_kex_x_init_server(&server2, rs, 0);
+ u8 msg11 [80]; u8 msg12 [80];
+ u8 client_key1[32]; u8 client_key2[32];
+ u8 server_key1[32]; u8 server_key2[32];
+ u8 remote_pk1 [32]; u8 remote_pk2 [32];
+ crypto_kex_x_1(&client1, client_key1, msg11);
+ crypto_kex_x_1(&client2, client_key2, msg12);
+ // make sure everything is accepted as it should be
+ status |= crypto_kex_x_2(&server1, server_key1, remote_pk1, msg11);
+ status |= crypto_kex_x_2(&server2, server_key2, remote_pk2, msg12);
+ // Make sure we get the same result whether we gave the local pk or not
+ status |= memcmp(msg11 , msg12 , 80);
+ status |= memcmp(client_key1, client_key2, 32);
+ status |= memcmp(remote_pk1 , remote_pk2 , 32);
+ // make sure wrong messages are rejected as they should be.
+ msg11[1]++;
+ status |= !crypto_kex_x_2(&server1, server_key1, remote_pk1, msg11);
+
+ printf("%s: monokex_x\n", status != 0 ? "FAILED" : "OK");
+ return status;
+}
+
int main(int argc, char *argv[])
{
if (argc > 1) {
status |= TEST(edDSA , 3);
status |= TEST(edDSA_pk , 1);
#endif
+ status |= TEST(monokex_xk1 , 9);
+ status |= TEST(monokex_x , 6);
status |= test_x25519();
printf("\nProperty based tests");
status |= p_aead();
status |= p_lock_incremental();
status |= p_auth();
-
+ status |= p_monokex_xk1();
+ status |= p_monokex_x();
printf("\n%s\n\n", status != 0 ? "SOME TESTS FAILED" : "All tests OK!");
return status;
}