Welcome to little lamb

Code » limb » commit b6e9da1

Add pbkdf2() to derive a key from password & salt..

author Olivier Brunel
2023-04-06 18:14:03 UTC
committer Olivier Brunel
2023-05-20 18:06:35 UTC
parent 0bdbefac680bfd9e25b9e824d41c5958a76ce52a

Add pbkdf2() to derive a key from password & salt..

..using the given hasher.

src/doc/hasher.h.0.md +1 -1
src/doc/hasher.h/hasher_hash.3.md +1 -1
src/doc/hmac.h.0.md +1 -1
src/doc/hmac.h/hmac.3.md +8 -1
src/doc/pbkdf2.h.0.md +27 -0
src/doc/pbkdf2.h/pbkdf2.3.md +35 -0
src/liblimb/include/limb/pbkdf2.h +13 -0
src/liblimb/pbkdf2.h/pbkdf2.c +48 -0

diff --git a/src/doc/hasher.h.0.md b/src/doc/hasher.h.0.md
index 1b2fae4..f5482c0 100644
--- a/src/doc/hasher.h.0.md
+++ b/src/doc/hasher.h.0.md
@@ -53,4 +53,4 @@ The following functions/macros are defined :
 
 # SEE ALSO
 
-[hmac.h](0)
+[hmac.h](0), [pbkdf2.h](0)
diff --git a/src/doc/hasher.h/hasher_hash.3.md b/src/doc/hasher.h/hasher_hash.3.md
index 01b60f2..598c7e6 100644
--- a/src/doc/hasher.h/hasher_hash.3.md
+++ b/src/doc/hasher.h/hasher_hash.3.md
@@ -130,4 +130,4 @@ out("The SHA1 of ", ESC, msg, ESC, " is ", HEX(digest, sizeof(digest)));
 
 # SEE ALSO
 
-[hmac](3), [blake3_init](3), [sha3_224_init](3)
+[hmac](3), [pbkdf2](3), [blake3_init](3), [sha3_224_init](3)
diff --git a/src/doc/hmac.h.0.md b/src/doc/hmac.h.0.md
index bdc21ad..4c48283 100644
--- a/src/doc/hmac.h.0.md
+++ b/src/doc/hmac.h.0.md
@@ -22,4 +22,4 @@ The following functions are defined :
 
 # SEE ALSO
 
-[hasher.h](0)
+[hasher.h](0), [pbkdf2.h](0)
diff --git a/src/doc/hmac.h/hmac.3.md b/src/doc/hmac.h/hmac.3.md
index b9d1c0b..c794238 100644
--- a/src/doc/hmac.h/hmac.3.md
+++ b/src/doc/hmac.h/hmac.3.md
@@ -16,7 +16,8 @@ void hmac(char *<em>out</em>, hasher *<em>hr</em>, const void *<em>key</em>, siz
 # DESCRIPTION
 
 The `hmac`() function calculates the HMAC of message `msg` of length `mlen`,
-using the secret key `key` of length `klen` and the cryptographic hasher `hr`.
+using the secret key `key` of length `klen` and the cryptographic hasher `hr`,
+as described in [RFC 2104][rfc2104].
 
 The results if then copied into the buffer pointed by `out` which must be able
 to hold at least the length of a message digest from the hash function used,
@@ -24,6 +25,8 @@ i.e. `hr->hlen` bytes.
 
 For a list of available hashers, refer to [hasher_hash](3).
 
+[rfc2104]: https://datatracker.ietf.org/doc/html/rfc2104
+
 # EXAMPLE
 
 ```c
@@ -43,3 +46,7 @@ int main(void)
     return 0;
 }
 ```
+
+# SEE ALSO
+
+[pbkdf2](3)
diff --git a/src/doc/pbkdf2.h.0.md b/src/doc/pbkdf2.h.0.md
new file mode 100644
index 0000000..3b7fd5f
--- /dev/null
+++ b/src/doc/pbkdf2.h.0.md
@@ -0,0 +1,27 @@
+% limb manual
+% pbkdf2.h(0)
+
+# NAME
+
+pbkdf2.h - compute PBKDF2
+
+# SYNOPSIS
+
+    #include <limb/pbkdf2.h>
+
+# DESCRIPTION
+
+This header defines the required functions to derive a key from a password via
+PBKDF2.
+
+## Functions
+
+The following functions are defined :
+
+: [pbkdf2](3)
+:: Derive a key from given password & salt using PBKDF2 based on the given
+:: hasher.
+
+# SEE ALSO
+
+[hasher.h](0), [hmac.h](0)
diff --git a/src/doc/pbkdf2.h/pbkdf2.3.md b/src/doc/pbkdf2.h/pbkdf2.3.md
new file mode 100644
index 0000000..f2fc38b
--- /dev/null
+++ b/src/doc/pbkdf2.h/pbkdf2.3.md
@@ -0,0 +1,35 @@
+% limb manual
+% pbkdf2(3)
+
+# NAME
+
+pbkdf2 - derive a key from given password & salt using PBKDF2
+
+# SYNOPSIS
+
+    #include <limb/pbkdf2.h>
+
+```pre hl
+int pbkdf2(char *<em>dst</em>, size_t dlen, hasher *<em>hr</em>, const char *<em>pwd</em>, size_t <em>plen</em>,
+           const char *<em>salt</em>, size_t <em>slen</em>, size_t <em>iter</em)
+```
+
+# DESCRIPTION
+
+The `pbkdf2`() function derives a key of `dlen` bytes from the given `password`
+of length `plen` bytes and `salt` of length `slen` bytes, through `iter`
+iterations, using the HMAC based on the cryptographioc hasher `hr`, and writing
+it into `dst`, as described in [RFC 8018][rfc8018].
+
+For a list of available hashers, refer to [hasher_hash](3).
+
+[rfc8018]: https://datatracker.ietf.org/doc/html/rfc8018
+
+# RETURN VALUE
+
+The `pbkdf2`() function returns 1 on success. Otherwise it returns 0, which can
+only happen if `dlen` is too large, i.e. greater than 2^32 - 1.
+
+# SEE ALSO
+
+[hmac](3), [hasher_hash](3)
diff --git a/src/liblimb/include/limb/pbkdf2.h b/src/liblimb/include/limb/pbkdf2.h
new file mode 100644
index 0000000..49e7929
--- /dev/null
+++ b/src/liblimb/include/limb/pbkdf2.h
@@ -0,0 +1,13 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#ifndef LIMB_PBKDF2_H
+#define LIMB_PBKDF2_H
+
+#include <stddef.h> /* size_t */
+#include <limb/hasher.h>
+
+extern int pbkdf2(char *dst, size_t dlen, hasher *hr, const char *pwd, size_t plen,
+                  const char *salt, size_t slen, size_t iter);
+
+#endif /* LIMB_PBKDF2_H */
diff --git a/src/liblimb/pbkdf2.h/pbkdf2.c b/src/liblimb/pbkdf2.h/pbkdf2.c
new file mode 100644
index 0000000..2d76e14
--- /dev/null
+++ b/src/liblimb/pbkdf2.h/pbkdf2.c
@@ -0,0 +1,48 @@
+/* This file is part of limb                           https://lila.oss/limb
+ * Copyright (C) 2023 Olivier Brunel                          jjk@jjacky.com */
+/* SPDX-License-Identifier: GPL-2.0-only */
+#include <string.h>
+#include <limb/hasher.h>
+#include <limb/hmac.h>
+#include <limb/memxor.h>
+#include <limb/u32.h>
+
+static void
+block(void *dst, hasher *hr, const char *pwd, size_t plen, const char *salt, size_t slen,
+      size_t iter, size_t num, size_t r)
+{
+    size_t blen, mlen = slen + sizeof(u32);
+    if (hr->hlen > mlen)
+        blen = hr->hlen;
+    else
+        blen = mlen;
+
+    char buf[blen];
+    memcpy(buf, salt, slen);
+    u32_pack_big(buf + slen, num);
+    hmac(buf, hr, pwd, plen, buf, mlen);
+
+    memcpy(dst, buf, r);
+    for (size_t i = 1; i < iter; ++i) {
+        hmac(buf, hr, pwd, plen, buf, hr->hlen);
+        memxor(dst, buf, r);
+    }
+}
+
+int
+pbkdf2(char *dst, size_t dlen, hasher *hr, const char *pwd, size_t plen,
+       const char *salt, size_t slen, size_t iter)
+{
+    if (dlen > (1ULL << 32) - 1)
+        return 0;
+
+    size_t l = dlen / hr->hlen;
+    if (dlen % hr->hlen) ++l;
+
+    size_t r = dlen - (l - 1) * hr->hlen;
+    for (size_t i = 1; i <= l; ++i)
+        block(dst + (i - 1) * hr->hlen, hr, pwd, plen, salt, slen, iter, i,
+              (i < l) ? hr->hlen : r);
+
+    return 1;
+}