]> WPIA git - cassiopeia.git/blobdiff - lib/openssl/crypto/ec/ecdh_kdf.c
upd: openssl to 1.1.0
[cassiopeia.git] / lib / openssl / crypto / ec / ecdh_kdf.c
diff --git a/lib/openssl/crypto/ec/ecdh_kdf.c b/lib/openssl/crypto/ec/ecdh_kdf.c
new file mode 100644 (file)
index 0000000..d47486e
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2015-2016 The OpenSSL Project Authors. All Rights Reserved.
+ *
+ * Licensed under the OpenSSL license (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+#include <string.h>
+#include <openssl/ec.h>
+#include <openssl/evp.h>
+
+/* Key derivation function from X9.62/SECG */
+/* Way more than we will ever need */
+#define ECDH_KDF_MAX    (1 << 30)
+
+int ECDH_KDF_X9_62(unsigned char *out, size_t outlen,
+                   const unsigned char *Z, size_t Zlen,
+                   const unsigned char *sinfo, size_t sinfolen,
+                   const EVP_MD *md)
+{
+    EVP_MD_CTX *mctx = NULL;
+    int rv = 0;
+    unsigned int i;
+    size_t mdlen;
+    unsigned char ctr[4];
+    if (sinfolen > ECDH_KDF_MAX || outlen > ECDH_KDF_MAX
+        || Zlen > ECDH_KDF_MAX)
+        return 0;
+    mctx = EVP_MD_CTX_new();
+    if (mctx == NULL)
+        return 0;
+    mdlen = EVP_MD_size(md);
+    for (i = 1;; i++) {
+        unsigned char mtmp[EVP_MAX_MD_SIZE];
+        if (!EVP_DigestInit_ex(mctx, md, NULL))
+            goto err;
+        ctr[3] = i & 0xFF;
+        ctr[2] = (i >> 8) & 0xFF;
+        ctr[1] = (i >> 16) & 0xFF;
+        ctr[0] = (i >> 24) & 0xFF;
+        if (!EVP_DigestUpdate(mctx, Z, Zlen))
+            goto err;
+        if (!EVP_DigestUpdate(mctx, ctr, sizeof(ctr)))
+            goto err;
+        if (!EVP_DigestUpdate(mctx, sinfo, sinfolen))
+            goto err;
+        if (outlen >= mdlen) {
+            if (!EVP_DigestFinal(mctx, out, NULL))
+                goto err;
+            outlen -= mdlen;
+            if (outlen == 0)
+                break;
+            out += mdlen;
+        } else {
+            if (!EVP_DigestFinal(mctx, mtmp, NULL))
+                goto err;
+            memcpy(out, mtmp, outlen);
+            OPENSSL_cleanse(mtmp, mdlen);
+            break;
+        }
+    }
+    rv = 1;
+ err:
+    EVP_MD_CTX_free(mctx);
+    return rv;
+}