]> git.codecow.com Git - Monocypher.git/commitdiff
Added incremental interface
authorLoup Vaillant <loup@loup-vaillant.fr>
Sun, 1 Oct 2017 18:40:52 +0000 (20:40 +0200)
committerLoup Vaillant <loup@loup-vaillant.fr>
Sun, 1 Oct 2017 18:40:52 +0000 (20:40 +0200)
Fixed #29

Bonus: we now can authenticate a message without decrypting it.

doc/man/man3/crypto_lock.3monocypher
doc/man/man3/crypto_lock_auth.3monocypher [new symlink]
doc/man/man3/crypto_lock_final.3monocypher [new symlink]
doc/man/man3/crypto_lock_init.3monocypher [new symlink]
doc/man/man3/crypto_lock_update.3monocypher [new symlink]
doc/man/man3/crypto_unlock_final.3monocypher [new symlink]
doc/man/man3/crypto_unlock_update.3monocypher [new symlink]
src/monocypher.c
src/monocypher.h
tests/test.c

index f048a3f96009a10723e3b8816fbb4489dfd7fa05..162ce706808ac5d5f3726ec5dc8a086c41b384ea 100644 (file)
 .Fa "const uint8_t *cipher_text"
 .Fa "size_t text_size"
 .Fc
+.Ft void
+.Fo crypto_lock_init
+.Fa "crypto_lock_ctx *ctx"
+.Fa "const uint8_t key[32]"
+.Fa "const uint8_t nonce[24]"
+.Fc
+.Ft void
+.Fo crypto_lock_auth
+.Fa crypto_lock_ctx *ctx
+.Fa const uint8_t *ad
+.Fa size_t ad_size
+.Fc
+.Ft void
+.Fo crypto_lock_update
+.Fa crypto_lock_ctx *ctx
+.Fa uint8_t *cipher_text
+.Fa const uint8_t *plain_text
+.Fa size_t text_size
+.Fc
+.Ft void
+.Fo crypto_lock_final
+.Fa crypto_lock_ctx *ctx
+.Fa uint8_t mac[16]
+.Fc
+.Ft void
+.Fo crypto_unlock_update
+.Fa crypto_lock_ctx *ctx
+.Fa uint8_t *plain_text
+.Fa const uint8_t *cipher_text
+.Fa size_t text_size
+.Fc
+.Ft int
+.Fo crypto_unlock_final
+.Fa crypto_lock_ctx *ctx
+.Fa const uint8_t mac[16]
+.Fc
+.F
 .Sh DESCRIPTION
 Encryption makes your messages unreadable to eavesdroppers.
 Authentication ascertain the origin and integrity of the messages you
@@ -173,6 +210,88 @@ if (ret != 0) {
          */
 }
 .Ed
+.Sh INCREMENTAL INTERFACE
+Useful for decrypting huge inputs.
+This time, decryption is performed regardless of whether the message
+is corrupted or not.
+This may be relevant if you expect a high rate of corrupted messages.
+.Pp
+Encryption:
+.Bd -literal -offset indent
+/* Prepare the key, nonce, and input */
+
+/* First, initialise the context */
+crypto_lock_ctx ctx;
+crypto_lock_init(&ctx, key, nonce);
+
+/* Second, authenticate the additional data, if any. */
+crypto_lock_auth(&ctx, ad1, ad_size1);
+crypto_lock_auth(&ctx, ad2, ad_size2);
+crypto_lock_auth(&ctx, ad3, ad_size3);
+
+/* Third, encrypt the plain text */
+crypto_lock_update(&ctx, cipher1, plain1, text_size1);
+crypto_lock_update(&ctx, cipher2, plain2, text_size2);
+crypto_lock_update(&ctx, cipher3, plain2, text_size3);
+
+/* Finally, compute the authentication code */
+crypto_lock_final (&ctx, mac);
+.Ed
+.Pp
+Make sure you authenticate the additional data before you begin the
+encryption, or the mac won't be compatible with the direct interface.
+.Pp
+To decrypt the above:
+.Bd -literal -offset indent
+/* First, initialise the context.
+ * Use the key and nonce that were used for encryption.
+ */
+crypto_lock_ctx ctx;
+crypto_lock_init(&ctx, key, nonce);
+
+/* Second, authenticate the additional data, if any. */
+crypto_lock_auth(&ctx, ad1, ad_size1);
+crypto_lock_auth(&ctx, ad2, ad_size2);
+crypto_lock_auth(&ctx, ad3, ad_size3);
+
+/* Third, decrypt the cipher text */
+crypto_unlock_update(&ctx, re_plain1, cipher1, text_size1);
+crypto_unlock_update(&ctx, re_plain2, cipher2, text_size2);
+crypto_unlock_update(&ctx, re_plain3, cipher3, text_size3);
+
+/* Finally, check the authentication code */
+if (crypto_unlock_final(&ctx, mac2)) {
+    /* Message corrupted. */
+} else {
+    /* Decryption went well. */
+}
+.Ed
+.Pp
+To authenticate without decrypting at all:
+.Bd -literal -offset indent
+/* First, initialise the context.
+ * Use the key and nonce that were used for encryption.
+ */
+crypto_lock_ctx ctx;
+crypto_lock_init(&ctx, key, nonce);
+
+/* Second, authenticate the additional data, if any. */
+crypto_lock_auth(&ctx, ad1, ad_size1);
+crypto_lock_auth(&ctx, ad2, ad_size2);
+crypto_lock_auth(&ctx, ad3, ad_size3);
+
+/* Third, authenticate the cipher text */
+crypto_lock_auth(&ctx, re_plain1, cipher1, text_size1);
+crypto_lock_auth(&ctx, re_plain2, cipher2, text_size2);
+crypto_lock_auth(&ctx, re_plain3, cipher3, text_size3);
+
+/* Finally, check the authentication code */
+if (crypto_unlock_final(&ctx, mac2)) {
+    /* Message corrupted. */
+} else {
+    /* Message authentic. */
+}
+.Ed
 .Sh SEE ALSO
 .Xr crypto_aead_lock 3monocypher ,
 .Xr crypto_aead_unlock 3monocypher ,
diff --git a/doc/man/man3/crypto_lock_auth.3monocypher b/doc/man/man3/crypto_lock_auth.3monocypher
new file mode 120000 (symlink)
index 0000000..126507a
--- /dev/null
@@ -0,0 +1 @@
+crypto_lock.3monocypher
\ No newline at end of file
diff --git a/doc/man/man3/crypto_lock_final.3monocypher b/doc/man/man3/crypto_lock_final.3monocypher
new file mode 120000 (symlink)
index 0000000..126507a
--- /dev/null
@@ -0,0 +1 @@
+crypto_lock.3monocypher
\ No newline at end of file
diff --git a/doc/man/man3/crypto_lock_init.3monocypher b/doc/man/man3/crypto_lock_init.3monocypher
new file mode 120000 (symlink)
index 0000000..126507a
--- /dev/null
@@ -0,0 +1 @@
+crypto_lock.3monocypher
\ No newline at end of file
diff --git a/doc/man/man3/crypto_lock_update.3monocypher b/doc/man/man3/crypto_lock_update.3monocypher
new file mode 120000 (symlink)
index 0000000..126507a
--- /dev/null
@@ -0,0 +1 @@
+crypto_lock.3monocypher
\ No newline at end of file
diff --git a/doc/man/man3/crypto_unlock_final.3monocypher b/doc/man/man3/crypto_unlock_final.3monocypher
new file mode 120000 (symlink)
index 0000000..126507a
--- /dev/null
@@ -0,0 +1 @@
+crypto_lock.3monocypher
\ No newline at end of file
diff --git a/doc/man/man3/crypto_unlock_update.3monocypher b/doc/man/man3/crypto_unlock_update.3monocypher
new file mode 120000 (symlink)
index 0000000..126507a
--- /dev/null
@@ -0,0 +1 @@
+crypto_lock.3monocypher
\ No newline at end of file
index 140543c1ac1f2c1948147405ffd91c88db8aa874..cafaee6ac5fb712d80ac17d11fa48c81b0ed4967 100644 (file)
@@ -1653,3 +1653,42 @@ int crypto_unlock(u8       *plain_text,
     return crypto_aead_unlock(plain_text, key, nonce, mac, 0, 0,
                               cipher_text, text_size);
 }
+
+void crypto_lock_init(crypto_lock_ctx *ctx, const u8 key[32], const u8 nonce[24])
+{
+    u8 auth_key[32];
+    crypto_chacha20_x_init(&(ctx->chacha), key, nonce);
+    crypto_chacha20_stream(&(ctx->chacha), auth_key, 32);
+    crypto_poly1305_init  (&(ctx->poly  ), auth_key);
+}
+
+void crypto_lock_auth(crypto_lock_ctx *ctx, const u8 *ad, size_t ad_size)
+{
+    crypto_poly1305_update(&(ctx->poly), ad, ad_size);
+}
+
+void crypto_lock_update(crypto_lock_ctx *ctx, u8 *cipher_text,
+                        const u8 *plain_text, size_t text_size)
+{
+    crypto_chacha20_encrypt(&(ctx->chacha), cipher_text, plain_text, text_size);
+    crypto_poly1305_update (&(ctx->poly  ), cipher_text, text_size);
+}
+
+void crypto_lock_final(crypto_lock_ctx *ctx, u8 mac[16])
+{
+    crypto_poly1305_final (&(ctx->poly), mac);
+}
+
+void crypto_unlock_update(crypto_lock_ctx *ctx, u8 *plain_text,
+                          const u8 *cipher_text, size_t text_size)
+{
+    crypto_poly1305_update (&(ctx->poly  ), cipher_text, text_size);
+    crypto_chacha20_encrypt(&(ctx->chacha), plain_text, cipher_text, text_size);
+}
+
+int crypto_unlock_final(crypto_lock_ctx *ctx, const u8 mac[16])
+{
+    u8 real_mac[16];
+    crypto_poly1305_final(&(ctx->poly), real_mac);
+    return crypto_memcmp(real_mac, mac, 16);
+}
index 4d6eb660bccbe10adf20194f1762c98c5fbcdff6..9bcce73d1e712634542a1082b92af0f0665e4979 100644 (file)
@@ -175,4 +175,28 @@ int crypto_unlock(uint8_t       *plain_text,
                   const uint8_t  mac[16],
                   const uint8_t *cipher_text, size_t text_size);
 
+typedef struct {
+    crypto_chacha_ctx   chacha;
+    crypto_poly1305_ctx poly;
+} crypto_lock_ctx;
+
+void crypto_lock_init(crypto_lock_ctx *ctx,
+                      const uint8_t key[32],
+                      const uint8_t nonce[24]);
+
+void crypto_lock_auth(crypto_lock_ctx *ctx,
+                      const uint8_t *ad, size_t ad_size);
+
+void crypto_lock_update(crypto_lock_ctx *ctx,
+                        uint8_t *cipher_text,
+                        const uint8_t *plain_text, size_t text_size);
+
+void crypto_lock_final(crypto_lock_ctx *ctx, uint8_t mac[16]);
+
+void crypto_unlock_update(crypto_lock_ctx *ctx,
+                          uint8_t *plain_text,
+                          const uint8_t *cipher_text, size_t text_size);
+
+int crypto_unlock_final(crypto_lock_ctx *ctx, const uint8_t mac[16]);
+
 #endif // MONOCYPHER_H
index cf70cd7233d21ccc59ba665ec101af68e1895eb3..03afeedb7a7ab44c1b3e32db9aee307fd065e1b8 100644 (file)
@@ -667,6 +667,71 @@ static int p_aead()
     return status;
 }
 
+static int p_lock_incremental()
+{
+    int status = 0;
+    FOR (i, 0, 1000) {
+        RANDOM_INPUT(key  ,  32);
+        RANDOM_INPUT(nonce,  24);
+        RANDOM_INPUT(ad   , 128);
+        RANDOM_INPUT(plain, 256);
+        // total sizes
+        size_t ad_size    = rand64() % 128;
+        size_t text_size  = rand64() % 256;
+        // incremental sizes
+        size_t ad_size1   = ad_size   == 0 ? 0 : rand64() % ad_size;
+        size_t text_size1 = text_size == 0 ? 0 : rand64() % text_size;
+        size_t ad_size2   = ad_size   - ad_size1;
+        size_t text_size2 = text_size - text_size1;
+        // incremental buffers
+        u8 *ad1    = ad;    u8 *ad2    = ad + ad_size1;
+        u8 *plain1 = plain; u8 *plain2 = plain + text_size1;
+
+        u8 mac1[16], cipher1[256];
+        u8 mac2[16], cipher2[256];
+        crypto_aead_lock(mac1, cipher1, key, nonce,
+                         ad, ad_size, plain, text_size);
+        crypto_lock_ctx ctx;
+        crypto_lock_init  (&ctx, key, nonce);
+        crypto_lock_auth  (&ctx, ad1, ad_size1); // just to show ad also have
+        crypto_lock_auth  (&ctx, ad2, ad_size2); // an incremental interface
+        crypto_lock_update(&ctx, cipher2             , plain1, text_size1);
+        crypto_lock_update(&ctx, cipher2 + text_size1, plain2, text_size2);
+        crypto_lock_final (&ctx, mac2);
+        status |= crypto_memcmp(mac1   , mac2   , 16       );
+        status |= crypto_memcmp(cipher1, cipher2, text_size);
+
+        // Now test the round trip.
+        u8 re_plain1[256];
+        u8 re_plain2[256];
+        status |= crypto_aead_unlock(re_plain1, key, nonce, mac1,
+                                     ad, ad_size, cipher1, text_size);
+        crypto_lock_init    (&ctx, key, nonce);
+        crypto_lock_auth    (&ctx, ad, ad_size);
+        crypto_unlock_update(&ctx, re_plain2, cipher2, text_size);
+        status |= crypto_unlock_final(&ctx, mac2);
+        status |= crypto_memcmp(mac1 , mac2     , 16       );
+        status |= crypto_memcmp(plain, re_plain1, text_size);
+        status |= crypto_memcmp(plain, re_plain2, text_size);
+
+        // Test authentication without decryption
+        crypto_lock_init(&ctx, key, nonce);
+        crypto_lock_auth(&ctx, ad     , ad_size  );
+        crypto_lock_auth(&ctx, cipher2, text_size);
+        status |= crypto_unlock_final(&ctx, mac2);
+        // The same, except we're supposed to reject forgeries
+        if (text_size > 0) {
+            cipher2[0]++; // forgery attempt
+            crypto_lock_init(&ctx, key, nonce);
+            crypto_lock_auth(&ctx, ad     , ad_size  );
+            crypto_lock_auth(&ctx, cipher2, text_size);
+            status |= !crypto_unlock_final(&ctx, mac2);
+        }
+    }
+    printf("%s: aead (incremental)\n", status != 0 ? "FAILED" : "OK");
+    return status;
+}
+
 int main(void)
 {
     int status = 0;
@@ -698,11 +763,11 @@ int main(void)
     status |= p_eddsa();
     status |= p_eddsa_overlap();
     status |= p_aead();
-
+    status |= p_lock_incremental();
     printf("\nConstant time tests");
     printf("\n-------------------\n");
     status |= test_cmp();
 
-    printf("\n");
+    printf("\n%s\n\n", status != 0 ? "SOME TESTS FAILED" : "All tests OK!");
     return status;
 }