]> git.codecow.com Git - Monocypher.git/commitdiff
added x25519 and crypto_lock
authorLoup Vaillant <loup@loup-vaillant.fr>
Thu, 19 Jan 2017 15:33:12 +0000 (16:33 +0100)
committerLoup Vaillant <loup@loup-vaillant.fr>
Thu, 19 Jan 2017 15:33:12 +0000 (16:33 +0100)
build.sh
lock.c [new file with mode: 0644]
lock.h [new file with mode: 0644]
test.c
vectors_x25519.txt [new file with mode: 0644]
x25519.c [new file with mode: 0644]
x25519.h [new file with mode: 0644]

index 6d4096ab024d04dbad5fd8870c2a3b094ca51982..c2db67d73f38e22627d87167ec80ec29d53ad460 100755 (executable)
--- a/build.sh
+++ b/build.sh
@@ -1,14 +1,16 @@
 #! /bin/bash
 
 CC="gcc"
-CFLAGS="-O2 -Wall -Wextra -std=c11 -g"
+CFLAGS="-O2 -Wall -Wextra -std=c11"
 
 $CC $CFLAGS -c chacha20.c
 $CC $CFLAGS -c blake2b.c
 $CC $CFLAGS -c poly1305.c
 $CC $CFLAGS -c argon2i.c
 $CC $CFLAGS -c ae.c
+$CC $CFLAGS -c x25519.c
+$CC $CFLAGS -c lock.c
 $CC $CFLAGS -c test.c
 
-$CC $CFLAGS -o test test.o chacha20.o argon2i.o blake2b.o poly1305.o ae.o
+$CC $CFLAGS -o test test.o chacha20.o argon2i.o blake2b.o poly1305.o x25519.o ae.o lock.o
 $CC $CFLAGS -o speed_blake2b speed_blake2b.c blake2b.o
diff --git a/lock.c b/lock.c
new file mode 100644 (file)
index 0000000..64220ae
--- /dev/null
+++ b/lock.c
@@ -0,0 +1,64 @@
+#include "lock.h"
+#include "x25519.h"
+#include "chacha20.h"
+#include "ae.h"
+
+void crypto_lock_key(uint8_t       shared_key[32],
+                     const uint8_t your_secret_key [32],
+                     const uint8_t their_public_key[32])
+{
+    static const uint8_t _0[16];
+    uint8_t shared_secret[32];
+    crypto_x25519(shared_secret, your_secret_key, their_public_key);
+    crypto_chacha20_H(shared_key, shared_secret, _0);
+}
+
+void crypto_lock_detached(const uint8_t  your_secret_key [32],
+                          const uint8_t  their_public_key[32],
+                          const uint8_t  nonce[24],
+                          const uint8_t *plaintext,
+                          uint8_t       *ciphertext,
+                          size_t         text_size,
+                          uint8_t        mac[16])
+{
+    uint8_t shared_key[32];
+    crypto_lock_key(shared_key, your_secret_key, their_public_key);
+    crypto_ae_lock_detached(shared_key, nonce, plaintext, ciphertext,
+                            text_size, mac);
+}
+
+int crypto_unlock_detached(const uint8_t  your_secret_key [32],
+                           const uint8_t  their_public_key[32],
+                           const uint8_t  nonce[24],
+                           const uint8_t *ciphertext,
+                           uint8_t       *plaintext,
+                           size_t         text_size,
+                           const uint8_t  mac[16])
+{
+    uint8_t shared_key[32];
+    crypto_lock_key(shared_key, your_secret_key, their_public_key);
+    return crypto_ae_unlock_detached(shared_key, nonce, ciphertext, plaintext,
+                                     text_size, mac);
+}
+
+void crypto_lock(const uint8_t  your_secret_key [32],
+                 const uint8_t  their_public_key[32],
+                 const uint8_t  nonce[24],
+                 const uint8_t *plaintext,
+                 size_t         text_size,
+                 uint8_t       *box)
+{
+    crypto_lock_detached(your_secret_key, their_public_key, nonce,
+                         plaintext, box + 16, text_size, box);
+}
+
+int crypto_unlock(const uint8_t  your_secret_key [32],
+                  const uint8_t  their_public_key[32],
+                  const uint8_t  nonce[24],
+                  const uint8_t *box,
+                  size_t         text_size,
+                  uint8_t       *plaintext)
+{
+    return crypto_unlock_detached(your_secret_key, their_public_key, nonce,
+                                  box + 16, plaintext, text_size, box);
+}
diff --git a/lock.h b/lock.h
new file mode 100644 (file)
index 0000000..ae47eca
--- /dev/null
+++ b/lock.h
@@ -0,0 +1,50 @@
+#ifndef LOCK_H
+#define LOCK_H
+
+#include <inttypes.h>
+#include <stddef.h>
+
+// Computes a shared key with your secret key and their public key,
+// suitable for crypto_ae* functions.
+void crypto_lock_key(uint8_t       shared_key      [32],
+                     const uint8_t your_secret_key [32],
+                     const uint8_t their_public_key[32]);
+
+// Authenticated encryption with the sender's secret key and the recipient's
+// publick key.  The message leaks if one of the secret key gets compromised.
+void crypto_lock_detached(const uint8_t  your_secret_key [32],
+                          const uint8_t  their_public_key[32],
+                          const uint8_t  nonce[24],
+                          const uint8_t *plaintext,
+                          uint8_t       *ciphertext,
+                          size_t         text_size,
+                          uint8_t        mac[16]);
+
+// Authenticated decryption with the recipient's secret key, and the sender's
+// public key.  Has no effect if the message is forged.
+int crypto_unlock_detached(const uint8_t  your_secret_key [32],
+                           const uint8_t  their_public_key[32],
+                           const uint8_t  nonce[24],
+                           const uint8_t *ciphertext,
+                           uint8_t       *plaintext,
+                           size_t         text_size,
+                           const uint8_t  mac[16]);
+
+// Like the above, only puts the mac and the ciphertext together
+// in a "box", mac first
+void crypto_lock(const uint8_t  your_secret_key [32],
+                 const uint8_t  their_public_key[32],
+                 const uint8_t  nonce[24],
+                 const uint8_t *plaintext,
+                 size_t         text_size,
+                 uint8_t       *box);
+
+// Unlocks a box locked by crypto_lock()
+int crypto_unlock(const uint8_t  your_secret_key [32],
+                  const uint8_t  their_public_key[32],
+                  const uint8_t  nonce[24],
+                  const uint8_t *box,
+                  size_t         text_size,
+                  uint8_t       *plaintext);
+
+#endif // LOCK_H
diff --git a/test.c b/test.c
index ff961c1e500f47ed11cf00739f8338bf77703092..8dcea70ccb3913ba549d564e44e2d16f3339ae98 100644 (file)
--- a/test.c
+++ b/test.c
@@ -8,6 +8,7 @@
 #include "poly1305.h"
 #include "argon2i.h"
 #include "ae.h"
+#include "x25519.h"
 
 /////////////////////////
 /// General utilities ///
@@ -68,6 +69,14 @@ static vector vec_uninitialized(size_t size)
     return v;
 }
 
+/* static vector vec_copy(const vector *v) */
+/* { */
+/*     vector w = *v; */
+/*     w.buffer = alloc(w.buf_size); */
+/*     memcpy(w.buffer, v->buffer, w.buf_size); */
+/*     return w; */
+/* } */
+
 static void vec_del(vector *v)
 {
     free(v->buffer);
@@ -209,6 +218,54 @@ static void argon2i(const vector in[], vector *out)
         free(work_area);
 }
 
+static void x25519(const vector in[], vector *out)
+{
+    const vector *scalar = in;
+    const vector *point  = in + 1;
+    crypto_x25519(out->buffer, scalar->buffer, point->buffer);
+}
+
+// Disabling the following test, because it takes too damn long
+// I suggest you run it once, though.
+/*
+static void iterate_x25519(uint8_t k[32], uint8_t u[32])
+{
+    uint8_t tmp[32];
+    crypto_x25519(tmp , k, u);
+    memcpy(u, k  , 32);
+    memcpy(k, tmp, 32);
+}
+
+static int test_x25519()
+{
+    uint8_t _1   [32] = {0x42, 0x2c, 0x8e, 0x7a, 0x62, 0x27, 0xd7, 0xbc,
+                         0xa1, 0x35, 0x0b, 0x3e, 0x2b, 0xb7, 0x27, 0x9f,
+                         0x78, 0x97, 0xb8, 0x7b, 0xb6, 0x85, 0x4b, 0x78,
+                         0x3c, 0x60, 0xe8, 0x03, 0x11, 0xae, 0x30, 0x79};
+    uint8_t _1k  [32] = {0x68, 0x4c, 0xf5, 0x9b, 0xa8, 0x33, 0x09, 0x55,
+                         0x28, 0x00, 0xef, 0x56, 0x6f, 0x2f, 0x4d, 0x3c,
+                         0x1c, 0x38, 0x87, 0xc4, 0x93, 0x60, 0xe3, 0x87,
+                         0x5f, 0x2e, 0xb9, 0x4d, 0x99, 0x53, 0x2c, 0x51};
+    uint8_t _100k[32] = {0x7c, 0x39, 0x11, 0xe0, 0xab, 0x25, 0x86, 0xfd,
+                         0x86, 0x44, 0x97, 0x29, 0x7e, 0x57, 0x5e, 0x6f,
+                         0x3b, 0xc6, 0x01, 0xc0, 0x88, 0x3c, 0x30, 0xdf,
+                         0x5f, 0x4d, 0xd2, 0xd2, 0x4f, 0x66, 0x54, 0x24};
+    uint8_t k[32] = {9};
+    uint8_t u[32] = {9};
+
+    iterate_x25519(k, u);
+    int status = memcmp(k, _1, 32);
+    for (int i = 1; i < 1000; i++)
+        iterate_x25519(k, u);
+    status |= memcmp(k, _1k, 32);
+    for (int i = 1000; i < 1000000; i++)
+        iterate_x25519(k, u);
+    status |= memcmp(k, _100k, 32);
+
+    printf("%s: x25519\n", status != 0 ? "FAILED" : "OK");
+    return status;
+}
+*/
 static int test_ae()
 {
     uint8_t key[32]      = { 0, 1, 2, 3, 4, 5, 6, 7, 0, 1, 2, 3, 4, 5, 6, 7,
@@ -237,6 +294,8 @@ int main(void)
     status |= test(blake2b ,  "vectors_blake2b.txt" , 2);
     status |= test(poly1305,  "vectors_poly1305.txt", 2);
     status |= test(argon2i ,  "vectors_argon2i.txt" , 6);
+    status |= test(x25519  ,  "vectors_x25519.txt"  , 2);
+//    status |= test_x25519(); // Too Long; Didn't Run
     status |= test_ae();
     printf(status ? "TESTS FAILED\n" : "ALL TESTS OK\n");
     return status;
diff --git a/vectors_x25519.txt b/vectors_x25519.txt
new file mode 100644 (file)
index 0000000..eb5b79d
--- /dev/null
@@ -0,0 +1,15 @@
+scalar:        a546e36bf0527c9d3b16154b82465edd62144c0ac1fc5a18506a2244ba449ac4
+point: e6db6867583030db3594c1a424b15f7c726624ec26b3353b10a903a6d0ab1c4c
+out:   c3da55379de9c6908e94ea4df28d084f32eccf03491c71f754b4075577a28552
+
+scalar:        4b66e9d4d1b4673c5ad22691957d6af5c11b6421e0ea01d42ca4169e7918ba0d
+point: e5210f12786811d3f4b7959d0538ae2c31dbe7106fc03c3efc4cd549c715a493
+out:   95cbde9476e8907d7aade45cb4b873f88b595a68799fa152e6f8f7647aac7957
+
+scalar:        77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a
+point: de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f
+out:   4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742
+
+scalar:        5dab087e624a8a4b79e17f8b83800ee66f3bb1292618b6fd1c2f8b27ff88e0eb
+point: 8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a
+out:   4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742
diff --git a/x25519.c b/x25519.c
new file mode 100644 (file)
index 0000000..d4421a7
--- /dev/null
+++ b/x25519.c
@@ -0,0 +1,195 @@
+#include "x25519.h"
+
+#define FOR(i, start, end) for (size_t i = start; i < end; i++)
+#define sv static void
+typedef int64_t gf[16];
+
+static const uint8_t _0[16];
+static const uint8_t _9[32] = { 9 };
+static const gf _121665 = { 0xDB41, 1 };
+
+/* static int vn(const uint8_t *x, const uint8_t *y, size_t n) */
+/* { */
+/*   uint32_t d = 0; */
+/*   FOR(i, 0, n) d |= x[i] ^ y[i]; */
+/*   return (1 & ((d - 1) >> 8)) - 1; */
+/* } */
+
+
+// needed for signatures (not here)
+/* sv set_25519(gf r, const gf a) */
+/* { */
+/*     FOR(i, 0, 16) r[i] = a[i]; */
+/* } */
+
+sv car_25519(gf o)
+{
+    FOR(i, 0, 16) {
+        o[i]              += 1LL  << 16;
+        int64_t c          = o[i] >> 16;
+        o[(i+1) * (i<15)] += c - 1 + (37 * (c-1) * (i==15));
+        o[i]              -= c << 16;
+    }
+}
+
+sv sel_25519(gf p, gf q, int b)
+{
+    int64_t c = ~(b-1);
+    FOR(i, 0, 16) {
+        int64_t t = c & (p[i] ^ q[i]);
+        p[i]     ^= t;
+        q[i]     ^= t;
+    }
+}
+
+sv pack_25519(uint8_t *o, const gf n)
+{
+    gf t;
+    FOR(i, 0, 16) t[i] = n[i];
+    car_25519(t);
+    car_25519(t);
+    car_25519(t);
+    FOR(j, 0, 2) {
+        gf m;
+        m[0] = t[0] - 0xffed;
+        FOR(i, 1, 15) {
+            m[i  ]  = t[i] - 0xffff - ((m[i-1] >> 16) & 1);
+            m[i-1] &= 0xffff;
+        }
+        m[15]  = t[15] - 0x7fff - ((m[14] >> 16) & 1);
+        int b  = (m[15] >> 16) & 1;
+        m[14] &= 0xffff;
+        sel_25519(t, m, 1-b);
+    }
+    FOR(i, 0, 16) {
+        o[2*i    ] = t[i] & 0xff;
+        o[2*i + 1] = t[i] >> 8;
+    }
+}
+
+// needed for signatures (not here)
+/* static int neq_25519(const gf a, const gf b) */
+/* { */
+/*     uint8_t c[32],d[32]; */
+/*     pack_25519(c, a); */
+/*     pack_25519(d, b); */
+/*     return vn(c, d, 32); */
+/* } */
+// needed for signatures (not here)
+/* static uint8_t par_25519(const gf a) */
+/* { */
+/*     uint8_t d[32]; */
+/*     pack_25519(d, a); */
+/*     return d[0] & 1; */
+/* } */
+
+sv unpack_25519(gf o, const uint8_t *n)
+{
+    FOR(i, 0, 16) o[i] = n[2*i] + ((int64_t)n[2*i + 1] << 8);
+    o[15] &= 0x7fff;
+}
+
+sv A(gf o, const gf a, const gf b)
+{
+    FOR(i, 0, 16) o[i] = a[i] + b[i];
+}
+
+sv Z(gf o, const gf a, const gf b)
+{
+    FOR(i, 0, 16) o[i] = a[i] - b[i];
+}
+
+sv M(gf o, const gf a, const gf b)
+{
+    int64_t t[31];
+    FOR(i, 0, 31) t[i] = 0;
+    FOR(i, 0, 16) FOR(j, 0, 16) t[i+j] += a[i] * b[j];
+    FOR(i, 0, 15) t[i] += 38 * t[i+16];
+    FOR(i, 0, 16) o[i] = t[i];
+    car_25519(o);
+    car_25519(o);
+}
+
+sv S(gf o,const gf a)
+{
+    M(o, a, a);
+}
+
+sv inv_25519(gf o,const gf i)
+{
+    gf c;
+    FOR(a, 0, 16) c[a] = i[a];
+    for(int a = 253; a >= 0; a--) {
+        S(c, c);
+        if(a != 2 && a != 4)
+            M(c, c, i);
+    }
+    FOR(a, 0, 16) o[a] = c[a];
+}
+// needed for signatures (not here)
+/* sv pow2523(gf o,const gf i) */
+/* { */
+/*     gf c; */
+/*     FOR(a, 0, 16) c[a] = i[a]; */
+/*     for(int a = 250; a >= 0; a--) { */
+/*         S(c, c); */
+/*         if(a != 1) M(c, c, i); */
+/*     } */
+/*     FOR(a, 0, 16) o[a] = c[a]; */
+/* } */
+
+void crypto_x25519(uint8_t q[32], const uint8_t n[32], const uint8_t p[32])
+{
+    uint8_t z[32];
+    int64_t x[80];
+    int64_t r;
+    gf a, b, c, d, e, f;
+    FOR(i, 0, 31) z[i] = n[i];
+    z[31]  = (n[31] & 127) | 64;
+    z[0 ] &= 248;
+    unpack_25519(x, p);
+    FOR(i, 0, 16) {
+        b[i] = x[i];
+        d[i] = a[i] = c[i] = 0;
+    }
+    a[0] = d[0] = 1;
+    for(int i = 254; i>=0; i--) {
+        r = (z[i>>3] >> (i & 7)) & 1;
+        sel_25519(a, b, r);
+        sel_25519(c, d, r);
+        A(e, a, c);
+        Z(a, a, c);
+        A(c, b, d);
+        Z(b, b, d);
+        S(d, e);
+        S(f, a);
+        M(a, c, a);
+        M(c, b, e);
+        A(e, a, c);
+        Z(a, a, c);
+        S(b, a);
+        Z(c, d, f);
+        M(a, c, _121665);
+        A(a, a, d);
+        M(c, c, a);
+        M(a, d, f);
+        M(d, b, x);
+        S(b, e);
+        sel_25519(a, b, r);
+        sel_25519(c, d, r);
+    }
+    FOR(i, 0, 16) {
+        x[i+16] = a[i];
+        x[i+32] = c[i];
+        x[i+48] = b[i];
+        x[i+64] = d[i];
+    }
+    inv_25519(x+32, x+32);
+    M(x+16, x+16, x+32);
+    pack_25519(q, x+16);
+}
+
+void crypto_x25519_base(uint8_t q[32], const uint8_t n[32])
+{
+    crypto_x25519(q, n, _9);
+}
diff --git a/x25519.h b/x25519.h
new file mode 100644 (file)
index 0000000..1c5d2ac
--- /dev/null
+++ b/x25519.h
@@ -0,0 +1,34 @@
+#ifndef X25519_H
+#define X25519_H
+
+#include <inttypes.h>
+#include <stddef.h>
+
+// Computes a shared secret from your private key and their public key.
+// WARNING: DO NOT USE THE SHARED SECRET DIRECTLY.
+// The shared secret is not pseudo-random.  You need to hash it to derive
+// an acceptable secret key.  Any cryptographic hash can work, as well as
+// HChacha20.
+//
+// Implementation details: this is an elliptic curve.  The public key is
+// a point on this curve, and your private key is a scalar.  The shared
+// secret is another point on this curve, obtained by scalar multiplication.
+// Basically:
+//     shared_secret == your_sk * their_pk == your_sk * (their_sk * base_point)
+//                   == their_sk * your_pk == their_sk * (your_sk * base_point)
+void crypto_x25519(uint8_t       shared_secret   [32],
+                   const uint8_t your_secret_key [32],
+                   const uint8_t their_public_key[32]);
+
+// Generates a public key from the specified secret key.
+// Make sure the secret key is randomly selected.
+//
+// Implementation detail: your secret key is a scalar, and we multiply
+// the base point (a constant) by it to obtain a public key.  That is:
+//     public_key == secret_key * base_point
+// Reversing the operation is conjectured to be infeasible
+// without quantum computers (128 bits of security).
+void crypto_x25519_base(uint8_t public_key[32], const uint8_t secret_key[32]);
+
+
+#endif // X25519_H