Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/lib/libcrypt crypt(3): match the Argon2 reference implementa...



details:   https://anonhg.NetBSD.org/src/rev/ef8c7cc32f7c
branches:  trunk
changeset: 989128:ef8c7cc32f7c
user:      nia <nia%NetBSD.org@localhost>
date:      Tue Oct 12 15:25:39 2021 +0000

description:
crypt(3): match the Argon2 reference implementation's Base64 exactly

There are too many minor variations regarding padding and exact alphabet
to safely use the implementation in libc or an existing implementation
in libcrypt.

diffstat:

 lib/libcrypt/crypt-argon2.c |  107 ++++++++++++++++++++++++++++++++++---------
 lib/libcrypt/crypt.h        |    5 +-
 lib/libcrypt/pw_gensalt.c   |   12 ++--
 lib/libcrypt/util.c         |   21 +++++++-
 4 files changed, 112 insertions(+), 33 deletions(-)

diffs (282 lines):

diff -r d7e8735dccd3 -r ef8c7cc32f7c lib/libcrypt/crypt-argon2.c
--- a/lib/libcrypt/crypt-argon2.c       Tue Oct 12 15:25:27 2021 +0000
+++ b/lib/libcrypt/crypt-argon2.c       Tue Oct 12 15:25:39 2021 +0000
@@ -7,7 +7,6 @@
 #include <pwd.h>
 #include <errno.h>
 #include <argon2.h>
-#include <resolv.h> /* for b64_pton... */
 
 #include <err.h>
 #include "crypt.h"
@@ -32,17 +31,84 @@
 #define ARGON2_ARGON2D_STR     "argon2d"
 #define ARGON2_ARGON2ID_STR    "argon2id"
 
+
+/*
+ * Some macros for constant-time comparisons. These work over values in
+ * the 0..255 range. Returned value is 0x00 on "false", 0xFF on "true".
+ */
+#define EQ(x, y) ((((0U - ((unsigned)(x) ^ (unsigned)(y))) >> 8) & 0xFF) ^ 0xFF)
+#define GT(x, y) ((((unsigned)(y) - (unsigned)(x)) >> 8) & 0xFF)
+#define GE(x, y) (GT(y, x) ^ 0xFF)
+#define LT(x, y) GT(y, x)
+#define LE(x, y) GE(y, x)
+
+static unsigned
+b64_char_to_byte(int c)
+{
+    unsigned x;
+
+    x = (GE(c, 'A') & LE(c, 'Z') & (c - 'A')) |
+        (GE(c, 'a') & LE(c, 'z') & (c - ('a' - 26))) |
+        (GE(c, '0') & LE(c, '9') & (c - ('0' - 52))) | (EQ(c, '+') & 62) |
+        (EQ(c, '/') & 63);
+    return x | (EQ(x, 0) & (EQ(c, 'A') ^ 0xFF));
+}
+
+static const char *
+from_base64(void *dst, size_t *dst_len, const char *src)
+{
+       size_t len;
+       unsigned char *buf;
+       unsigned acc, acc_len;
+
+       buf = (unsigned char *)dst;
+       len = 0;
+       acc = 0;
+       acc_len = 0;
+       for (;;) {
+               unsigned d;
+
+               d = b64_char_to_byte(*src);
+               if (d == 0xFF) {
+                       break;
+               }
+               src++;
+               acc = (acc << 6) + d;
+               acc_len += 6;
+               if (acc_len >= 8) {
+                       acc_len -= 8;
+                       if ((len++) >= *dst_len) {
+                               return NULL;
+                       }
+                       *buf++ = (acc >> acc_len) & 0xFF;
+               }
+       }
+
+       /*
+        * If the input length is equal to 1 modulo 4 (which is
+        * invalid), then there will remain 6 unprocessed bits;
+        * otherwise, only 0, 2 or 4 bits are buffered. The buffered
+        * bits must also all be zero.
+        */
+       if (acc_len > 4 || (acc & (((unsigned)1 << acc_len) - 1)) != 0) {
+               return NULL;
+       }
+       *dst_len = len;
+       return src;
+}
+
 /* process params to argon2 */
 /* we don't force param order as input, */
 /* but we do provide the expected order to argon2 api */
-static int decode_option(argon2_context * ctx, argon2_type * atype, const char * option) 
+static int
+decode_option(argon2_context *ctx, argon2_type *atype, const char *option) 
 {
-       size_t tmp=0;
-        char * in = 0,*inp;
-        char * a=0;
-        char * p=0;
+       size_t tmp = 0;
+        char *in = 0, *inp;
+        char *a = 0;
+        char *p = 0;
        size_t sl;
-       int    error=0;
+       int error = 0;
 
         in = (char *)strdup(option);
        inp = in;
@@ -127,7 +193,12 @@
 
        a = strsep(&inp, "$");
 
-       b64_pton(a, ctx->salt, ctx->saltlen);
+       sl = ctx->saltlen;
+
+       if (from_base64(ctx->salt, &sl, a) == NULL)
+               return -1;
+
+       ctx->saltlen = sl;
 
        a = strsep(&inp, "$");
 
@@ -151,11 +222,9 @@
 {
        /* we use the libargon2 api to generate */
        /* return code */
-       int rc=0;
+       int rc = 0;
        /* output buffer */
        char ebuf[32];
-       /* ptr into argon2 encoded buffer */
-       char * blkp=0;
        /* argon2 variable, default to id */
        argon2_type atype = Argon2_id;
        /* default to current argon2 version */
@@ -184,7 +253,7 @@
        ctx.salt = (uint8_t *)saltbuf;
        ctx.saltlen = sizeof(saltbuf);
 
-       ctx.pwd= (uint8_t *)pwdbuf;
+       ctx.pwd = (uint8_t *)pwdbuf;
        ctx.pwdlen = sizeof(pwdbuf);
 
        /* decode salt string to argon2 params */
@@ -197,8 +266,9 @@
        }
 
        rc = argon2_hash(ctx.t_cost, ctx.m_cost,
-               ctx.threads, pw, strlen(pw), ctx.salt, strlen((char*)ctx.salt),
-               ebuf, sizeof(ebuf), encodebuf, sizeof(encodebuf), atype, ctx.version);
+           ctx.threads, pw, strlen(pw), ctx.salt, ctx.saltlen,
+           ebuf, sizeof(ebuf), encodebuf, sizeof(encodebuf),
+           atype, ctx.version);
 
        if (rc != ARGON2_OK) {
                fprintf(stderr, "argon2: failed: %s\n",
@@ -206,14 +276,7 @@
                return 0;
        }
 
-       /* get encoded passwd */
-       if ((blkp = strrchr(encodebuf, '$')) == NULL) {
-               return 0;
-       }
-
-       /* skip over '$' */
-       blkp++;
-
+       puts(encodebuf);
        memcpy(rbuf, encodebuf, sizeof(encodebuf));
 
        /* clear buffers */
diff -r d7e8735dccd3 -r ef8c7cc32f7c lib/libcrypt/crypt.h
--- a/lib/libcrypt/crypt.h      Tue Oct 12 15:25:27 2021 +0000
+++ b/lib/libcrypt/crypt.h      Tue Oct 12 15:25:39 2021 +0000
@@ -1,5 +1,5 @@
 /*
- * $NetBSD: crypt.h,v 1.6 2021/10/12 13:24:00 nia Exp $
+ * $NetBSD: crypt.h,v 1.7 2021/10/12 15:25:39 nia Exp $
  */
 
 #define crypt_private     __attribute__((__visibility__("hidden")))
@@ -10,7 +10,6 @@
 unsigned int __crypt_sha1_iterations (unsigned int hint);
 void __hmac_sha1(const unsigned char *, size_t, const unsigned char *, size_t,
                 unsigned char *);
-void __crypt_to64(char *s, u_int32_t v, int n);
 
 #ifdef HAVE_ARGON2
 char *__crypt_argon2(const char *pw, const char *salt);
@@ -26,6 +25,8 @@
 int __gensalt_sha1(char *salt, size_t saltsiz, const char *option);
 
 crypt_private int getnum(const char *, size_t *);
+crypt_private void __crypt_to64(char *s, uint32_t v, int n);
+crypt_private void __crypt_tobase64(char *s, uint32_t v, int n);
 
 #define SHA1_MAGIC "$sha1$"
 #define SHA1_SIZE 20
diff -r d7e8735dccd3 -r ef8c7cc32f7c lib/libcrypt/pw_gensalt.c
--- a/lib/libcrypt/pw_gensalt.c Tue Oct 12 15:25:27 2021 +0000
+++ b/lib/libcrypt/pw_gensalt.c Tue Oct 12 15:25:39 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: pw_gensalt.c,v 1.10 2021/10/12 13:24:00 nia Exp $      */
+/*     $NetBSD: pw_gensalt.c,v 1.11 2021/10/12 15:25:39 nia Exp $      */
 
 /*
  * Copyright 1997 Niels Provos <provos%physnet.uni-hamburg.de@localhost>
@@ -34,7 +34,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__RCSID("$NetBSD: pw_gensalt.c,v 1.10 2021/10/12 13:24:00 nia Exp $");
+__RCSID("$NetBSD: pw_gensalt.c,v 1.11 2021/10/12 15:25:39 nia Exp $");
 #endif /* not lint */
 
 #include <sys/syslimits.h>
@@ -242,10 +242,10 @@
                return 0;
        }
 
-       __crypt_to64(&salt[n], arc4random(), 4);
-       __crypt_to64(&salt[n + 4], arc4random(), 4);
-       __crypt_to64(&salt[n + 8], arc4random(), 4);
-       __crypt_to64(&salt[n + 12], arc4random(), 4);
+       __crypt_tobase64(&salt[n], arc4random(), 4);
+       __crypt_tobase64(&salt[n + 4], arc4random(), 4);
+       __crypt_tobase64(&salt[n + 8], arc4random(), 4);
+       __crypt_tobase64(&salt[n + 12], arc4random(), 4);
 
        salt[n + 16] = '$';
        salt[n + 17] = '\0';
diff -r d7e8735dccd3 -r ef8c7cc32f7c lib/libcrypt/util.c
--- a/lib/libcrypt/util.c       Tue Oct 12 15:25:27 2021 +0000
+++ b/lib/libcrypt/util.c       Tue Oct 12 15:25:39 2021 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: util.c,v 1.2 2021/10/12 13:24:00 nia Exp $     */
+/*     $NetBSD: util.c,v 1.3 2021/10/12 15:25:39 nia Exp $     */
 /*
  * Copyright 1997 Niels Provos <provos%physnet.uni-hamburg.de@localhost>
  * All rights reserved.
@@ -30,7 +30,7 @@
  */
 #include <sys/cdefs.h>
 #if !defined(lint)
-__RCSID("$NetBSD: util.c,v 1.2 2021/10/12 13:24:00 nia Exp $");
+__RCSID("$NetBSD: util.c,v 1.3 2021/10/12 15:25:39 nia Exp $");
 #endif /* not lint */
 
 #include <sys/types.h>
@@ -41,9 +41,14 @@
 
 #include "crypt.h"
 
+/* traditional unix "B64" encoding */
 static const unsigned char itoa64[] =          /* 0 ... 63 => ascii - 64 */
        "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
 
+/* standard base64 encoding, used by Argon2 */
+static const unsigned char itoabase64[] =
+       "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
 crypt_private int
 getnum(const char *str, size_t *num)
 {
@@ -68,7 +73,7 @@
        return 0;
 }
 
-void
+crypt_private void
 __crypt_to64(char *s, uint32_t v, int n)
 {
 
@@ -77,3 +82,13 @@
                v >>= 6;
        }
 }
+
+crypt_private void
+__crypt_tobase64(char *s, uint32_t v, int n)
+{
+
+       while (--n >= 0) {
+               *s++ = itoabase64[v & 0x3f];
+               v >>= 6;
+       }
+}



Home | Main Index | Thread Index | Old Index