Skip to content

Commit

Permalink
+ crypto_kdf high-level API
Browse files Browse the repository at this point in the history
This is a common need, and people end up reimplementing HKDF.

So, add a crypto_kdf() API similiar to libhydrogen's. The later has a
higher limit for the output length using BLAKE2X if required.

We can implement the same strategy later in libsodium if needed.
  • Loading branch information
jedisct1 committed Feb 19, 2017
1 parent 49916e5 commit 70c2796
Show file tree
Hide file tree
Showing 10 changed files with 312 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/libsodium/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ libsodium_la_SOURCES = \
crypto_hash/sha256/cp/hash_sha256.c \
crypto_hash/sha512/hash_sha512_api.c \
crypto_hash/sha512/cp/hash_sha512.c \
crypto_kdf/crypto_kdf.c \
crypto_kdf/blake2b/kdf_blake2b.c \
crypto_onetimeauth/crypto_onetimeauth.c \
crypto_onetimeauth/poly1305/onetimeauth_poly1305.c \
crypto_onetimeauth/poly1305/onetimeauth_poly1305.h \
Expand Down
52 changes: 52 additions & 0 deletions src/libsodium/crypto_kdf/blake2b/kdf_blake2b.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
#include <errno.h>

#include "crypto_kdf_blake2b.h"
#include "crypto_generichash_blake2b.h"
#include "private/common.h"

size_t
crypto_kdf_blake2b_bytes_min(void)
{
return crypto_kdf_blake2b_BYTES_MIN;
}

size_t
crypto_kdf_blake2b_bytes_max(void)
{
return crypto_kdf_blake2b_BYTES_MAX;
}

size_t
crypto_kdf_blake2b_contextbytes(void)
{
return crypto_kdf_blake2b_CONTEXTBYTES;
}

size_t
crypto_kdf_blake2b_keybytes(void)
{
return crypto_kdf_blake2b_KEYBYTES;
}

int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len,
uint64_t subkey_id,
const char ctx[crypto_kdf_blake2b_CONTEXTBYTES],
const unsigned char key[crypto_kdf_blake2b_KEYBYTES])
{
unsigned char ctx_padded[crypto_generichash_blake2b_PERSONALBYTES];
unsigned char salt[crypto_generichash_blake2b_SALTBYTES];

memcpy(ctx_padded, ctx, crypto_kdf_blake2b_CONTEXTBYTES);
memset(ctx_padded + crypto_kdf_blake2b_CONTEXTBYTES, 0, sizeof ctx_padded - crypto_kdf_blake2b_CONTEXTBYTES);
STORE64_LE(salt, subkey_id);
memset(salt + 8, 0, (sizeof salt) - 8);
if (subkey_len < crypto_kdf_blake2b_BYTES_MIN ||
subkey_len > crypto_kdf_blake2b_BYTES_MAX) {
errno = EINVAL;
return -1;
}
return crypto_generichash_blake2b_salt_personal(subkey, subkey_len,
NULL, 0,
key, crypto_kdf_blake2b_KEYBYTES,
salt, ctx_padded);
}
35 changes: 35 additions & 0 deletions src/libsodium/crypto_kdf/crypto_kdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

#include "crypto_kdf.h"

size_t
crypto_kdf_bytes_min(void)
{
return crypto_kdf_BYTES_MIN;
}

size_t
crypto_kdf_bytes_max(void)
{
return crypto_kdf_BYTES_MAX;
}

size_t
crypto_kdf_contextbytes(void)
{
return crypto_kdf_CONTEXTBYTES;
}

size_t
crypto_kdf_keybytes(void)
{
return crypto_kdf_KEYBYTES;
}

int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len,
uint64_t subkey_id,
const char ctx[crypto_kdf_CONTEXTBYTES],
const unsigned char key[crypto_kdf_KEYBYTES])
{
return crypto_kdf_blake2b_derive_from_key(subkey, subkey_len,
subkey_id, ctx, key);
}
2 changes: 2 additions & 0 deletions src/libsodium/include/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ SODIUM_EXPORT = \
sodium/crypto_hash.h \
sodium/crypto_hash_sha256.h \
sodium/crypto_hash_sha512.h \
sodium/crypto_kdf.h \
sodium/crypto_kdf_blake2b.h \
sodium/crypto_onetimeauth.h \
sodium/crypto_onetimeauth_poly1305.h \
sodium/crypto_pwhash.h \
Expand Down
2 changes: 2 additions & 0 deletions src/libsodium/include/sodium.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include "sodium/crypto_hash.h"
#include "sodium/crypto_hash_sha256.h"
#include "sodium/crypto_hash_sha512.h"
#include "sodium/crypto_kdf.h"
#include "sodium/crypto_kdf_blake2b.h"
#include "sodium/crypto_onetimeauth.h"
#include "sodium/crypto_onetimeauth_poly1305.h"
#include "sodium/crypto_pwhash.h"
Expand Down
42 changes: 42 additions & 0 deletions src/libsodium/include/sodium/crypto_kdf.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef crypto_kdf_H
#define crypto_kdf_H

#include <stddef.h>
#include <stdint.h>

#include "crypto_kdf_blake2b.h"
#include "export.h"

#ifdef __cplusplus
# ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wlong-long"
# endif
extern "C" {
#endif

#define crypto_kdf_BYTES_MIN crypto_kdf_blake2b_BYTES_MIN
SODIUM_EXPORT
size_t crypto_kdf_bytes_min(void);

#define crypto_kdf_BYTES_MAX crypto_kdf_blake2b_BYTES_MAX
SODIUM_EXPORT
size_t crypto_kdf_bytes_max(void);

#define crypto_kdf_CONTEXTBYTES crypto_kdf_blake2b_CONTEXTBYTES
SODIUM_EXPORT
size_t crypto_kdf_contextbytes(void);

#define crypto_kdf_KEYBYTES crypto_kdf_blake2b_KEYBYTES
SODIUM_EXPORT
size_t crypto_kdf_keybytes(void);

SODIUM_EXPORT
int crypto_kdf_derive_from_key(unsigned char *subkey, size_t subkey_len,
uint64_t subkey_id,
const char ctx[crypto_kdf_CONTEXTBYTES],
const unsigned char key[crypto_kdf_KEYBYTES]);
#ifdef __cplusplus
}
#endif

#endif
42 changes: 42 additions & 0 deletions src/libsodium/include/sodium/crypto_kdf_blake2b.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef crypto_kdf_blake2b_H
#define crypto_kdf_blake2b_H

#include <stddef.h>
#include <stdint.h>

#include "crypto_kdf_blake2b.h"
#include "export.h"

#ifdef __cplusplus
# ifdef __GNUC__
# pragma GCC diagnostic ignored "-Wlong-long"
# endif
extern "C" {
#endif

#define crypto_kdf_blake2b_BYTES_MIN 16
SODIUM_EXPORT
size_t crypto_kdf_blake2b_bytes_min(void);

#define crypto_kdf_blake2b_BYTES_MAX 64
SODIUM_EXPORT
size_t crypto_kdf_blake2b_bytes_max(void);

#define crypto_kdf_blake2b_CONTEXTBYTES 8
SODIUM_EXPORT
size_t crypto_kdf_blake2b_contextbytes(void);

#define crypto_kdf_blake2b_KEYBYTES 32
SODIUM_EXPORT
size_t crypto_kdf_blake2b_keybytes(void);

SODIUM_EXPORT
int crypto_kdf_blake2b_derive_from_key(unsigned char *subkey, size_t subkey_len,
uint64_t subkey_id,
const char ctx[crypto_kdf_blake2b_CONTEXTBYTES],
const unsigned char key[crypto_kdf_blake2b_KEYBYTES]);
#ifdef __cplusplus
}
#endif

#endif
8 changes: 8 additions & 0 deletions test/default/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ EXTRA_DIST = \
hash.exp \
hash2.exp \
hash3.exp \
kdf.exp \
onetimeauth.exp \
onetimeauth2.exp \
onetimeauth7.exp \
Expand Down Expand Up @@ -98,6 +99,7 @@ DISTCLEANFILES = \
hash.res \
hash2.res \
hash3.res \
kdf.res \
onetimeauth.res \
onetimeauth2.res \
onetimeauth7.res \
Expand Down Expand Up @@ -163,6 +165,7 @@ CLEANFILES = \
hash.final \
hash2.final \
hash3.final \
kdf.final \
onetimeauth.final \
onetimeauth2.final \
onetimeauth7.final \
Expand Down Expand Up @@ -223,6 +226,7 @@ CLEANFILES = \
hash.nexe \
hash2.nexe \
hash3.nexe \
kdf.nexe \
onetimeauth.nexe \
onetimeauth2.nexe \
onetimeauth7.nexe \
Expand Down Expand Up @@ -294,6 +298,7 @@ TESTS_TARGETS = \
generichash3 \
hash \
hash3 \
kdf \
onetimeauth \
onetimeauth2 \
onetimeauth7 \
Expand Down Expand Up @@ -428,6 +433,9 @@ hash_LDADD = $(TESTS_LDADD)
hash3_SOURCE = cmptest.h hash3.c
hash3_LDADD = $(TESTS_LDADD)

kdf_SOURCE = cmptest.h kdf.c
kdf_LDADD = $(TESTS_LDADD)

onetimeauth_SOURCE = cmptest.h onetimeauth.c
onetimeauth_LDADD = $(TESTS_LDADD)

Expand Down
50 changes: 50 additions & 0 deletions test/default/kdf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@

#define TEST_NAME "kdf"
#include "cmptest.h"

static void
tv_kdf(void)
{
unsigned char *master_key;
unsigned char *subkey;
char *context;
char hex[crypto_kdf_BYTES_MAX * 2 + 1];
uint64_t i;

context = (char *) sodium_malloc(crypto_kdf_CONTEXTBYTES);
memcpy(context, "KDF test", strlen("KDF test"));
master_key = (unsigned char *) sodium_malloc(crypto_kdf_KEYBYTES);
for (i = 0; i < crypto_kdf_KEYBYTES; i++) {
master_key[i] = i;
}
subkey = (unsigned char *) sodium_malloc(crypto_kdf_BYTES_MAX);
for (i = 0; i < 10; i++) {
assert(crypto_kdf_blake2b_derive_from_key(subkey, crypto_kdf_BYTES_MAX,
i, context, master_key) == 0);
sodium_bin2hex(hex, sizeof hex, subkey, crypto_kdf_BYTES_MAX);
printf("%s\n", hex);
}
sodium_free(subkey);

for (i = 0; i < crypto_kdf_BYTES_MAX + 2; i++) {
subkey = (unsigned char *) sodium_malloc(crypto_kdf_BYTES_MAX);
if (crypto_kdf_blake2b_derive_from_key(subkey, (size_t) i,
i, context, master_key) == 0) {
sodium_bin2hex(hex, sizeof hex, subkey, (size_t) i);
printf("%s\n", hex);
} else {
printf("Failure -- probably expected for output length=%u\n",
(unsigned int) i);
}
sodium_free(subkey);
}
printf("tv_kdf: ok\n");
}

int
main(void)
{
tv_kdf();

return 0;
}
77 changes: 77 additions & 0 deletions test/default/kdf.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
a0c724404728c8bb95e5433eb6a9716171144d61efb23e74b873fcbeda51d8071b5d70aae12066dfc94ce943f145aa176c055040c3dd73b0a15e36254d450614
02507f144fa9bf19010bf7c70b235b4c2663cc00e074f929602a5e2c10a780757d2a3993d06debc378a90efdac196dd841817b977d67b786804f6d3cd585bab5
1944da61ff18dc2028c3578ac85be904931b83860896598f62468f1cb5471c6a344c945dbc62c9aaf70feb62472d17775ea5db6ed5494c68b7a9a59761f39614
131c0ca1633ed074986215b264f6e0474f362c52b029effc7b0f75977ee89cc95d85c3db87f7e399197a25411592beeeb7e5128a74646a460ecd6deb4994b71e
a7023a0bf9be245d078aed26bcde0465ff0cc0961196a5482a0ff4ff8b4015971e13611f50529cb408f5776b14a90e7c3dd9160a22211db64ff4b5c0b9953680
50f49313f3a05b2e565c13feedb44daa675cafd42c2b2cf9edbce9c949fbfc3f175dcb738671509ae2ea66fb85e552394d479afa7fa3affe8791744796b94176
13b58d6d69780089293862cd59a1a8a4ef79bb850e3f3ba41fb22446a7dd1dc4da4667d37b33bf1225dcf8173c4c349a5d911c5bd2db9c5905ed70c11e809e3b
15d44b4b44ffa006eeceeb508c98a970aaa573d65905687b9e15854dec6d49c612757e149f78268f727660dedf9abce22a9691feb20a01b0525f4b47a3cf19db
9aebba11c5428ae8225716369e30a48943be39159a899f804e9963ef78822e186c21fe95bb0b85e60ef03a6f58d0b9d06e91f79d0ab998450b8810c73ca935b4
70f9b83e463fb441e7a4c43275125cd5b19d8e2e4a5d179a39f5db10bbce745a199104563d308cf8d4c6b27bbb759ded232f5bdb7c367dd632a9677320dfe416
Failure -- probably expected for output length=0
Failure -- probably expected for output length=1
Failure -- probably expected for output length=2
Failure -- probably expected for output length=3
Failure -- probably expected for output length=4
Failure -- probably expected for output length=5
Failure -- probably expected for output length=6
Failure -- probably expected for output length=7
Failure -- probably expected for output length=8
Failure -- probably expected for output length=9
Failure -- probably expected for output length=10
Failure -- probably expected for output length=11
Failure -- probably expected for output length=12
Failure -- probably expected for output length=13
Failure -- probably expected for output length=14
Failure -- probably expected for output length=15
a529216624ef9161e4cf117272aafff2
068bd6940b80c6cc2530a68c31d9f4e323
0acf4f6c74a590c8a1c0997ec9a1a3f48b2a
ac17a37ce74c0efece75f9337de20795dbadcc
268214dc9477a2e3c1022829f934ab992a5a3d84
33b76197b4531665e494760909eda1cc570e7da9bb
3d4efbc569ca7f858ad4f49c56b820986a406e6eebbc
983fea27520f507c40231f9557908f07c095bdf4a4ce5d
94d678717625e011995c7355f2092267dee47bf0722dd380
198901896c4f51e74ffa8b2805415c6eaba5accfc85a6e6b34
4ffabb81d49021f85ef5d2a713ab02ae86bc2e7d1522f5e077fe
eebc3d55b3f4fc8b64d2474063254da7db98e7398dfdd510e28075
22c134b9d664e1bdb14dc309a936bf1512b19e4f5175642efb1a0df7
4b179762bfc8e27a9e575113faa76247b9c046d6f22d5a02e2910a299b
abc45eb2b031307b8822c7e59a43f4108850c34a7445936bc848422251c4
d6565bd3265b6373f4f6a6b6458e981006da5e9d532ce94ca4737e188995e9
154b291f11196737f8b7f491e4ca11764e0227d34f94295408a869f007aa8618
e9dd395570e09ebb523ffc6ba098a38b17bc4944f14bd3725bdd7edbd8bcff54fb
7248294d37159e85bacde68c7762a673794c91b811e05f4e3b9e3ecc82bfcf63a2cd
d060ee4d93f8de6d9ae60fca9596413455183a1f83c7a2381227cec8f7a217e4072f85
20790290347b9b0f413a954f40e52e270b3b45417e96c8733161672188701c08dd76cc3d
7674188112a1ab8d3926d468be8e51d788ce4144bb20ff842034e4d1ddab3929a4f1a13a74
a2ab1f980a47472d8a539f20410cc9bf143d941331ab2259ea73684c0608939c5b23e9cbcb3d
f4cfbe3050f15ebbaf8d2f3bf3a678c01fc21ee1f4be07d0744c7fbf4835ea9d9472a3d785c24c
66efa5dfe3efd4cc8ca25f2d622c97a20a192d7add965f26b002b7eb81aae4203c0e5f07fd945845
ad5d8031055c96dc9db10285206d7edc38d3af85736df8a3b5fdd30a318e80c28d9b26c95a60fa3e68
9107c8a57a2c9ca40158f33ca0bfb64c095d2f21ca98bb7138477599330a36cdfc2ae5751e370d0e024e
b0c190177358b955ebebc5e0b86ec91dde3b6f1982ea4d68ec5ec3bdd6527c362e5275600b263601c98452
31bfaaad4adde0f87d87372e398c42cb7befe065ab2957ebb91ef9dc534b410783899b2e1e84221286f3bab4
2258dd1f3e516cb8e3d1f6c45808573c365192f073698939721af8961a02a8bdd002a31fd239b9498663a01f27
7c7a88016610493bb44a9432a88b50f97e2e94383972ff95da826692d96c52d82f86899b3561ec9c95a8b1bf3213
3929dc7473be4c633be9e08801a8abd284dc0c6154c5c81a4c18259699dd86753c5e14fbd723be46ebb04f4ab3058c
30b720220015fa60daa69c83f9754d772b1b2dd12ab6baaa2f4edab458d4d251c1cddb8c4a554f3eb13969316b890fbd
33fa2412a5c3294d49e964419e96d043a2099a72b3351e3bed0f07e12255c95b509ea9bf2963a4c0fe9cc2314dbc44f673
ca891d2c82a6a8f833dc1a05f190bab6de221307eab1dd2c88341d4d2537a2fc0056b0d04d8104fd3fe89e1ea20877893e81
fd78ac89a64d03672ad99d663f2613d15277cda1636e334a1706b7211ff1f3a3b3d2e671e391c75e3d242c482ce7e1b8b427ed
36a6072743d3aafd3ee89344b9ef92cb58a2853ae92b20283520439fcb55afffd3d4b5e4e8c92a85d3cf74497bdcf68bbf1fcf93
a90afcfaffec1105ad05fdaa9473fb5daf1bf8fb376b7326db46ef4c120c553188c69131933371d409eb56d66d5adca618e1dac65b
9b990d1fcddbdb5e5c7a48a6a2a666e02e7d4d4a814ece40660d99e1c02d5f023c56ae82526fc6dc8c933d0add92fc376efcddd55a42
ec545dcf456d1b0907c07418a42bf2b3d668b4797ba6874bf0d563f5f429a820f02177dd4d05e639a06807c9619fee54ffe07712493543
b0106957626894586682a275f69ed4533e2f94334cc0430394b68d82679aca00dd579e712bdd2d7f5bbce9a050269739bd8427b75b06027f
05751bfeebb480c9bca0d25d8197e2673845f405d7fb9793e29169ac19956c525f6e637f3d5ea50597b04342afed4ca16f988b4f21a34f1902
7b4e4294d3f64085b5c09be73548f1f5cb5c6f04e57ce6cdd3077e2fb37640bf1ca0c6393b87d48a6b7e3e42628bd30fca132ded03ce51f71d9d
082d248862cbfd71a634769a4b1cf52a4af47ace5b9ea4d583ca52207efc7234a6d321788130cbdec122579ad03afe00bc68c9fb3f68dd0532a96f
a2b39b4428d981013e8a9c0e41b3eed504983fc18dc4b60332b1ab28b9705228147bdb95cc17889d5f0f9cfb7fd16f9d414b1a829346a8922e945b40
efbf0f8bda1b9ef24fe389f1cf0c0c8a08bca03fc95badabb79a487d8ce1351683f59183aa6229f880d69ad60114ac128f69b2be250109972ab1f3fc3b
dfe0ba2a6de25fa06b47375e9d9cf6c6fa1493a8a2a81c28d6e09bc161057b445659db76e92e349ff44f34a2a9e3bcaa6b84b21bae56f1499c170ab81af0
02f9cbdb10759314515b01379c474ad74a1b575137bd3949776dbcfc3e18060cb13ee1f6dcf86035768fc7be63e01de321cacbfade209900dd94273fd8e176
06ae14308eeeda62a00cb6d5edf18d1707029515db98f472bbf0617419301b1d4f4f2ab65849446be46f87e1d31c6c74283897b9976f70d8a16253ac927e0d9f
Failure -- probably expected for output length=65
tv_kdf: ok

0 comments on commit 70c2796

Please sign in to comment.