* Implement ECDH under kpp API * Provide ECC software support for curve P-192 and P-256. * Add kpp test for ECDH with data generated by OpenSSL Signed-off-by: Salvatore Benedetto <salvatore.benedetto@intel.com> Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>tirimbino
parent
802c7f1c84
commit
3c4b23901a
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,83 @@ |
||||
/*
|
||||
* Copyright (c) 2013, Kenneth MacKay |
||||
* All rights reserved. |
||||
* |
||||
* Redistribution and use in source and binary forms, with or without |
||||
* modification, are permitted provided that the following conditions are |
||||
* met: |
||||
* * Redistributions of source code must retain the above copyright |
||||
* notice, this list of conditions and the following disclaimer. |
||||
* * Redistributions in binary form must reproduce the above copyright |
||||
* notice, this list of conditions and the following disclaimer in the |
||||
* documentation and/or other materials provided with the distribution. |
||||
* |
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
||||
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||
*/ |
||||
#ifndef _CRYPTO_ECC_H |
||||
#define _CRYPTO_ECC_H |
||||
|
||||
#define ECC_MAX_DIGITS 4 /* 256 */ |
||||
|
||||
#define ECC_DIGITS_TO_BYTES_SHIFT 3 |
||||
|
||||
/**
|
||||
* ecc_is_key_valid() - Validate a given ECDH private key |
||||
* |
||||
* @curve_id: id representing the curve to use |
||||
* @ndigits: curve number of digits |
||||
* @private_key: private key to be used for the given curve |
||||
* @private_key_len: private key len |
||||
* |
||||
* Returns 0 if the key is acceptable, a negative value otherwise |
||||
*/ |
||||
int ecc_is_key_valid(unsigned int curve_id, unsigned int ndigits, |
||||
const u8 *private_key, unsigned int private_key_len); |
||||
|
||||
/**
|
||||
* ecdh_make_pub_key() - Compute an ECC public key |
||||
* |
||||
* @curve_id: id representing the curve to use |
||||
* @private_key: pregenerated private key for the given curve |
||||
* @private_key_len: length of private_key |
||||
* @public_key: buffer for storing the public key generated |
||||
* @public_key_len: length of the public_key buffer |
||||
* |
||||
* Returns 0 if the public key was generated successfully, a negative value |
||||
* if an error occurred. |
||||
*/ |
||||
int ecdh_make_pub_key(const unsigned int curve_id, unsigned int ndigits, |
||||
const u8 *private_key, unsigned int private_key_len, |
||||
u8 *public_key, unsigned int public_key_len); |
||||
|
||||
/**
|
||||
* ecdh_shared_secret() - Compute a shared secret |
||||
* |
||||
* @curve_id: id representing the curve to use |
||||
* @private_key: private key of part A |
||||
* @private_key_len: length of private_key |
||||
* @public_key: public key of counterpart B |
||||
* @public_key_len: length of public_key |
||||
* @secret: buffer for storing the calculated shared secret |
||||
* @secret_len: length of the secret buffer |
||||
* |
||||
* Note: It is recommended that you hash the result of ecdh_shared_secret |
||||
* before using it for symmetric encryption or HMAC. |
||||
* |
||||
* Returns 0 if the shared secret was generated successfully, a negative value |
||||
* if an error occurred. |
||||
*/ |
||||
int ecdh_shared_secret(unsigned int curve_id, unsigned int ndigits, |
||||
const u8 *private_key, unsigned int private_key_len, |
||||
const u8 *public_key, unsigned int public_key_len, |
||||
u8 *secret, unsigned int secret_len); |
||||
#endif |
@ -0,0 +1,57 @@ |
||||
#ifndef _CRYTO_ECC_CURVE_DEFS_H |
||||
#define _CRYTO_ECC_CURVE_DEFS_H |
||||
|
||||
struct ecc_point { |
||||
u64 *x; |
||||
u64 *y; |
||||
u8 ndigits; |
||||
}; |
||||
|
||||
struct ecc_curve { |
||||
char *name; |
||||
struct ecc_point g; |
||||
u64 *p; |
||||
u64 *n; |
||||
}; |
||||
|
||||
/* NIST P-192 */ |
||||
static u64 nist_p192_g_x[] = { 0xF4FF0AFD82FF1012ull, 0x7CBF20EB43A18800ull, |
||||
0x188DA80EB03090F6ull }; |
||||
static u64 nist_p192_g_y[] = { 0x73F977A11E794811ull, 0x631011ED6B24CDD5ull, |
||||
0x07192B95FFC8DA78ull }; |
||||
static u64 nist_p192_p[] = { 0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFFFFFFFFFEull, |
||||
0xFFFFFFFFFFFFFFFFull }; |
||||
static u64 nist_p192_n[] = { 0x146BC9B1B4D22831ull, 0xFFFFFFFF99DEF836ull, |
||||
0xFFFFFFFFFFFFFFFFull }; |
||||
static struct ecc_curve nist_p192 = { |
||||
.name = "nist_192", |
||||
.g = { |
||||
.x = nist_p192_g_x, |
||||
.y = nist_p192_g_y, |
||||
.ndigits = 3, |
||||
}, |
||||
.p = nist_p192_p, |
||||
.n = nist_p192_n |
||||
}; |
||||
|
||||
/* NIST P-256 */ |
||||
static u64 nist_p256_g_x[] = { 0xF4A13945D898C296ull, 0x77037D812DEB33A0ull, |
||||
0xF8BCE6E563A440F2ull, 0x6B17D1F2E12C4247ull }; |
||||
static u64 nist_p256_g_y[] = { 0xCBB6406837BF51F5ull, 0x2BCE33576B315ECEull, |
||||
0x8EE7EB4A7C0F9E16ull, 0x4FE342E2FE1A7F9Bull }; |
||||
static u64 nist_p256_p[] = { 0xFFFFFFFFFFFFFFFFull, 0x00000000FFFFFFFFull, |
||||
0x0000000000000000ull, 0xFFFFFFFF00000001ull }; |
||||
static u64 nist_p256_n[] = { 0xF3B9CAC2FC632551ull, 0xBCE6FAADA7179E84ull, |
||||
0xFFFFFFFFFFFFFFFFull, 0xFFFFFFFF00000000ull }; |
||||
static struct ecc_curve nist_p256 = { |
||||
.name = "nist_256", |
||||
.g = { |
||||
.x = nist_p256_g_x, |
||||
.y = nist_p256_g_y, |
||||
.ndigits = 4, |
||||
}, |
||||
.p = nist_p256_p, |
||||
.n = nist_p256_n |
||||
}; |
||||
|
||||
#endif |
@ -0,0 +1,151 @@ |
||||
/* ECDH key-agreement protocol
|
||||
* |
||||
* Copyright (c) 2016, Intel Corporation |
||||
* Authors: Salvator Benedetto <salvatore.benedetto@intel.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public Licence |
||||
* as published by the Free Software Foundation; either version |
||||
* 2 of the Licence, or (at your option) any later version. |
||||
*/ |
||||
|
||||
#include <linux/module.h> |
||||
#include <crypto/internal/kpp.h> |
||||
#include <crypto/kpp.h> |
||||
#include <crypto/ecdh.h> |
||||
#include <linux/scatterlist.h> |
||||
#include "ecc.h" |
||||
|
||||
struct ecdh_ctx { |
||||
unsigned int curve_id; |
||||
unsigned int ndigits; |
||||
u64 private_key[ECC_MAX_DIGITS]; |
||||
u64 public_key[2 * ECC_MAX_DIGITS]; |
||||
u64 shared_secret[ECC_MAX_DIGITS]; |
||||
}; |
||||
|
||||
static inline struct ecdh_ctx *ecdh_get_ctx(struct crypto_kpp *tfm) |
||||
{ |
||||
return kpp_tfm_ctx(tfm); |
||||
} |
||||
|
||||
static unsigned int ecdh_supported_curve(unsigned int curve_id) |
||||
{ |
||||
switch (curve_id) { |
||||
case ECC_CURVE_NIST_P192: return 3; |
||||
case ECC_CURVE_NIST_P256: return 4; |
||||
default: return 0; |
||||
} |
||||
} |
||||
|
||||
static int ecdh_set_secret(struct crypto_kpp *tfm, void *buf, unsigned int len) |
||||
{ |
||||
struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); |
||||
struct ecdh params; |
||||
unsigned int ndigits; |
||||
|
||||
if (crypto_ecdh_decode_key(buf, len, ¶ms) < 0) |
||||
return -EINVAL; |
||||
|
||||
ndigits = ecdh_supported_curve(params.curve_id); |
||||
if (!ndigits) |
||||
return -EINVAL; |
||||
|
||||
ctx->curve_id = params.curve_id; |
||||
ctx->ndigits = ndigits; |
||||
|
||||
if (ecc_is_key_valid(ctx->curve_id, ctx->ndigits, |
||||
(const u8 *)params.key, params.key_size) < 0) |
||||
return -EINVAL; |
||||
|
||||
memcpy(ctx->private_key, params.key, params.key_size); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
static int ecdh_compute_value(struct kpp_request *req) |
||||
{ |
||||
int ret = 0; |
||||
struct crypto_kpp *tfm = crypto_kpp_reqtfm(req); |
||||
struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); |
||||
size_t copied, nbytes; |
||||
void *buf; |
||||
|
||||
nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; |
||||
|
||||
if (req->src) { |
||||
copied = sg_copy_to_buffer(req->src, 1, ctx->public_key, |
||||
2 * nbytes); |
||||
if (copied != 2 * nbytes) |
||||
return -EINVAL; |
||||
|
||||
ret = ecdh_shared_secret(ctx->curve_id, ctx->ndigits, |
||||
(const u8 *)ctx->private_key, nbytes, |
||||
(const u8 *)ctx->public_key, 2 * nbytes, |
||||
(u8 *)ctx->shared_secret, nbytes); |
||||
|
||||
buf = ctx->shared_secret; |
||||
} else { |
||||
ret = ecdh_make_pub_key(ctx->curve_id, ctx->ndigits, |
||||
(const u8 *)ctx->private_key, nbytes, |
||||
(u8 *)ctx->public_key, |
||||
sizeof(ctx->public_key)); |
||||
buf = ctx->public_key; |
||||
/* Public part is a point thus it has both coordinates */ |
||||
nbytes *= 2; |
||||
} |
||||
|
||||
if (ret < 0) |
||||
return ret; |
||||
|
||||
copied = sg_copy_from_buffer(req->dst, 1, buf, nbytes); |
||||
if (copied != nbytes) |
||||
return -EINVAL; |
||||
|
||||
return ret; |
||||
} |
||||
|
||||
static int ecdh_max_size(struct crypto_kpp *tfm) |
||||
{ |
||||
struct ecdh_ctx *ctx = ecdh_get_ctx(tfm); |
||||
int nbytes = ctx->ndigits << ECC_DIGITS_TO_BYTES_SHIFT; |
||||
|
||||
/* Public key is made of two coordinates */ |
||||
return 2 * nbytes; |
||||
} |
||||
|
||||
static void no_exit_tfm(struct crypto_kpp *tfm) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
static struct kpp_alg ecdh = { |
||||
.set_secret = ecdh_set_secret, |
||||
.generate_public_key = ecdh_compute_value, |
||||
.compute_shared_secret = ecdh_compute_value, |
||||
.max_size = ecdh_max_size, |
||||
.exit = no_exit_tfm, |
||||
.base = { |
||||
.cra_name = "ecdh", |
||||
.cra_driver_name = "ecdh-generic", |
||||
.cra_priority = 100, |
||||
.cra_module = THIS_MODULE, |
||||
.cra_ctxsize = sizeof(struct ecdh_ctx), |
||||
}, |
||||
}; |
||||
|
||||
static int ecdh_init(void) |
||||
{ |
||||
return crypto_register_kpp(&ecdh); |
||||
} |
||||
|
||||
static void ecdh_exit(void) |
||||
{ |
||||
crypto_unregister_kpp(&ecdh); |
||||
} |
||||
|
||||
module_init(ecdh_init); |
||||
module_exit(ecdh_exit); |
||||
MODULE_ALIAS_CRYPTO("ecdh"); |
||||
MODULE_LICENSE("GPL"); |
||||
MODULE_DESCRIPTION("ECDH generic algorithm"); |
@ -0,0 +1,86 @@ |
||||
/*
|
||||
* Copyright (c) 2016, Intel Corporation |
||||
* Authors: Salvatore Benedetto <salvatore.benedetto@intel.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or |
||||
* modify it under the terms of the GNU General Public Licence |
||||
* as published by the Free Software Foundation; either version |
||||
* 2 of the Licence, or (at your option) any later version. |
||||
*/ |
||||
#include <linux/kernel.h> |
||||
#include <linux/export.h> |
||||
#include <linux/err.h> |
||||
#include <linux/string.h> |
||||
#include <crypto/ecdh.h> |
||||
#include <crypto/kpp.h> |
||||
|
||||
#define ECDH_KPP_SECRET_MIN_SIZE (sizeof(struct kpp_secret) + 2 * sizeof(short)) |
||||
|
||||
static inline u8 *ecdh_pack_data(void *dst, const void *src, size_t sz) |
||||
{ |
||||
memcpy(dst, src, sz); |
||||
return dst + sz; |
||||
} |
||||
|
||||
static inline const u8 *ecdh_unpack_data(void *dst, const void *src, size_t sz) |
||||
{ |
||||
memcpy(dst, src, sz); |
||||
return src + sz; |
||||
} |
||||
|
||||
int crypto_ecdh_key_len(const struct ecdh *params) |
||||
{ |
||||
return ECDH_KPP_SECRET_MIN_SIZE + params->key_size; |
||||
} |
||||
EXPORT_SYMBOL_GPL(crypto_ecdh_key_len); |
||||
|
||||
int crypto_ecdh_encode_key(char *buf, unsigned int len, |
||||
const struct ecdh *params) |
||||
{ |
||||
u8 *ptr = buf; |
||||
struct kpp_secret secret = { |
||||
.type = CRYPTO_KPP_SECRET_TYPE_ECDH, |
||||
.len = len |
||||
}; |
||||
|
||||
if (unlikely(!buf)) |
||||
return -EINVAL; |
||||
|
||||
if (len != crypto_ecdh_key_len(params)) |
||||
return -EINVAL; |
||||
|
||||
ptr = ecdh_pack_data(ptr, &secret, sizeof(secret)); |
||||
ptr = ecdh_pack_data(ptr, ¶ms->curve_id, sizeof(params->curve_id)); |
||||
ptr = ecdh_pack_data(ptr, ¶ms->key_size, sizeof(params->key_size)); |
||||
ecdh_pack_data(ptr, params->key, params->key_size); |
||||
|
||||
return 0; |
||||
} |
||||
EXPORT_SYMBOL_GPL(crypto_ecdh_encode_key); |
||||
|
||||
int crypto_ecdh_decode_key(const char *buf, unsigned int len, |
||||
struct ecdh *params) |
||||
{ |
||||
const u8 *ptr = buf; |
||||
struct kpp_secret secret; |
||||
|
||||
if (unlikely(!buf || len < ECDH_KPP_SECRET_MIN_SIZE)) |
||||
return -EINVAL; |
||||
|
||||
ptr = ecdh_unpack_data(&secret, ptr, sizeof(secret)); |
||||
if (secret.type != CRYPTO_KPP_SECRET_TYPE_ECDH) |
||||
return -EINVAL; |
||||
|
||||
ptr = ecdh_unpack_data(¶ms->curve_id, ptr, sizeof(params->curve_id)); |
||||
ptr = ecdh_unpack_data(¶ms->key_size, ptr, sizeof(params->key_size)); |
||||
if (secret.len != crypto_ecdh_key_len(params)) |
||||
return -EINVAL; |
||||
|
||||
/* Don't allocate memory. Set pointer to data
|
||||
* within the given buffer |
||||
*/ |
||||
params->key = (void *)ptr; |
||||
|
||||
return 0; |
||||
} |
||||
EXPORT_SYMBOL_GPL(crypto_ecdh_decode_key); |
@ -0,0 +1,30 @@ |
||||
/*
|
||||
* ECDH params to be used with kpp API |
||||
* |
||||
* Copyright (c) 2016, Intel Corporation |
||||
* Authors: Salvatore Benedetto <salvatore.benedetto@intel.com> |
||||
* |
||||
* This program is free software; you can redistribute it and/or modify it |
||||
* under the terms of the GNU General Public License as published by the Free |
||||
* Software Foundation; either version 2 of the License, or (at your option) |
||||
* any later version. |
||||
* |
||||
*/ |
||||
#ifndef _CRYPTO_ECDH_ |
||||
#define _CRYPTO_ECDH_ |
||||
|
||||
/* Curves IDs */ |
||||
#define ECC_CURVE_NIST_P192 0x0001 |
||||
#define ECC_CURVE_NIST_P256 0x0002 |
||||
|
||||
struct ecdh { |
||||
unsigned short curve_id; |
||||
char *key; |
||||
unsigned short key_size; |
||||
}; |
||||
|
||||
int crypto_ecdh_key_len(const struct ecdh *params); |
||||
int crypto_ecdh_encode_key(char *buf, unsigned int len, const struct ecdh *p); |
||||
int crypto_ecdh_decode_key(const char *buf, unsigned int len, struct ecdh *p); |
||||
|
||||
#endif |
Loading…
Reference in new issue