From 70c2796ae57979172ae882d60923d15b2aa25327 Mon Sep 17 00:00:00 2001 From: Frank Denis Date: Sun, 19 Feb 2017 18:13:10 +0100 Subject: [PATCH] + crypto_kdf high-level API 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. --- src/libsodium/Makefile.am | 2 + .../crypto_kdf/blake2b/kdf_blake2b.c | 52 +++++++++++++ src/libsodium/crypto_kdf/crypto_kdf.c | 35 +++++++++ src/libsodium/include/Makefile.am | 2 + src/libsodium/include/sodium.h | 2 + src/libsodium/include/sodium/crypto_kdf.h | 42 ++++++++++ .../include/sodium/crypto_kdf_blake2b.h | 42 ++++++++++ test/default/Makefile.am | 8 ++ test/default/kdf.c | 50 ++++++++++++ test/default/kdf.exp | 77 +++++++++++++++++++ 10 files changed, 312 insertions(+) create mode 100644 src/libsodium/crypto_kdf/blake2b/kdf_blake2b.c create mode 100644 src/libsodium/crypto_kdf/crypto_kdf.c create mode 100644 src/libsodium/include/sodium/crypto_kdf.h create mode 100644 src/libsodium/include/sodium/crypto_kdf_blake2b.h create mode 100644 test/default/kdf.c create mode 100644 test/default/kdf.exp diff --git a/src/libsodium/Makefile.am b/src/libsodium/Makefile.am index 17204dbc..6f49b17d 100644 --- a/src/libsodium/Makefile.am +++ b/src/libsodium/Makefile.am @@ -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 \ diff --git a/src/libsodium/crypto_kdf/blake2b/kdf_blake2b.c b/src/libsodium/crypto_kdf/blake2b/kdf_blake2b.c new file mode 100644 index 00000000..060c9368 --- /dev/null +++ b/src/libsodium/crypto_kdf/blake2b/kdf_blake2b.c @@ -0,0 +1,52 @@ +#include + +#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); +} diff --git a/src/libsodium/crypto_kdf/crypto_kdf.c b/src/libsodium/crypto_kdf/crypto_kdf.c new file mode 100644 index 00000000..b975ebe1 --- /dev/null +++ b/src/libsodium/crypto_kdf/crypto_kdf.c @@ -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); +} diff --git a/src/libsodium/include/Makefile.am b/src/libsodium/include/Makefile.am index 1aba51e0..66101afd 100644 --- a/src/libsodium/include/Makefile.am +++ b/src/libsodium/include/Makefile.am @@ -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 \ diff --git a/src/libsodium/include/sodium.h b/src/libsodium/include/sodium.h index 4d87a803..02cfe6e6 100644 --- a/src/libsodium/include/sodium.h +++ b/src/libsodium/include/sodium.h @@ -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" diff --git a/src/libsodium/include/sodium/crypto_kdf.h b/src/libsodium/include/sodium/crypto_kdf.h new file mode 100644 index 00000000..78f1784b --- /dev/null +++ b/src/libsodium/include/sodium/crypto_kdf.h @@ -0,0 +1,42 @@ +#ifndef crypto_kdf_H +#define crypto_kdf_H + +#include +#include + +#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 diff --git a/src/libsodium/include/sodium/crypto_kdf_blake2b.h b/src/libsodium/include/sodium/crypto_kdf_blake2b.h new file mode 100644 index 00000000..5480ebe8 --- /dev/null +++ b/src/libsodium/include/sodium/crypto_kdf_blake2b.h @@ -0,0 +1,42 @@ +#ifndef crypto_kdf_blake2b_H +#define crypto_kdf_blake2b_H + +#include +#include + +#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 diff --git a/test/default/Makefile.am b/test/default/Makefile.am index 726dc9c6..809f03a1 100644 --- a/test/default/Makefile.am +++ b/test/default/Makefile.am @@ -34,6 +34,7 @@ EXTRA_DIST = \ hash.exp \ hash2.exp \ hash3.exp \ + kdf.exp \ onetimeauth.exp \ onetimeauth2.exp \ onetimeauth7.exp \ @@ -98,6 +99,7 @@ DISTCLEANFILES = \ hash.res \ hash2.res \ hash3.res \ + kdf.res \ onetimeauth.res \ onetimeauth2.res \ onetimeauth7.res \ @@ -163,6 +165,7 @@ CLEANFILES = \ hash.final \ hash2.final \ hash3.final \ + kdf.final \ onetimeauth.final \ onetimeauth2.final \ onetimeauth7.final \ @@ -223,6 +226,7 @@ CLEANFILES = \ hash.nexe \ hash2.nexe \ hash3.nexe \ + kdf.nexe \ onetimeauth.nexe \ onetimeauth2.nexe \ onetimeauth7.nexe \ @@ -294,6 +298,7 @@ TESTS_TARGETS = \ generichash3 \ hash \ hash3 \ + kdf \ onetimeauth \ onetimeauth2 \ onetimeauth7 \ @@ -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) diff --git a/test/default/kdf.c b/test/default/kdf.c new file mode 100644 index 00000000..7a277d45 --- /dev/null +++ b/test/default/kdf.c @@ -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; +} diff --git a/test/default/kdf.exp b/test/default/kdf.exp new file mode 100644 index 00000000..4aa76946 --- /dev/null +++ b/test/default/kdf.exp @@ -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