mirror of
https://github.com/Telecominfraproject/OpenCellular.git
synced 2025-12-27 18:25:05 +00:00
CR50: Add initial elliptic curve crypto implementation.
This change adds support for NIST-P256 curve operations. BRANCH=none BUG=chrome-os-partner:43025,chrome-os-partner:47524 TEST=new tests under test/tpm2/ pass. Change-Id: I03a35ff3ab8af3c52282d882937880bfa2bdcd32 Signed-off-by: nagendra modadugu <ngm@google.com> Reviewed-on: https://chromium-review.googlesource.com/324540 Commit-Ready: Nagendra Modadugu <ngm@google.com> Tested-by: Nagendra Modadugu <ngm@google.com> Reviewed-by: Marius Schilder <mschilder@chromium.org> Reviewed-by: Vadim Bendebury <vbendeb@chromium.org>
This commit is contained in:
committed by
chrome-bot
parent
89424bfbed
commit
7ac69e594b
@@ -31,6 +31,7 @@ dirs-y += $(BDIR)/tpm2
|
||||
board-y = board.o
|
||||
board-y += tpm2/NVMem.o
|
||||
board-y += tpm2/aes.o
|
||||
board-y += tpm2/ecc.o
|
||||
board-y += tpm2/hash.o
|
||||
board-y += tpm2/hash_data.o
|
||||
board-y += tpm2/platform.o
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
#define CONFIG_TASK_LIST \
|
||||
TASK_ALWAYS(HOOKS, hook_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(BLOB, blob_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_NOTEST(TPM, tpm_task, NULL, 4096) \
|
||||
TASK_NOTEST(TPM, tpm_task, NULL, 8192) \
|
||||
TASK_NOTEST(HOSTCMD, host_command_task, NULL, TASK_STACK_SIZE) \
|
||||
TASK_ALWAYS(CONSOLE, console_task, NULL, TASK_STACK_SIZE)
|
||||
|
||||
464
board/cr50/tpm2/ecc.c
Normal file
464
board/cr50/tpm2/ecc.c
Normal file
@@ -0,0 +1,464 @@
|
||||
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
/*
|
||||
* TODO(ngm): only the NIST-P256 curve is currently supported.
|
||||
*/
|
||||
|
||||
#include "CryptoEngine.h"
|
||||
#include "TPMB.h"
|
||||
|
||||
#include "trng.h"
|
||||
#include "dcrypto.h"
|
||||
|
||||
TPM2B_BYTE_VALUE(4);
|
||||
|
||||
static int check_p256_param(const TPM2B_ECC_PARAMETER *a)
|
||||
{
|
||||
return a->b.size == sizeof(p256_int);
|
||||
}
|
||||
|
||||
static int check_p256_point(const TPMS_ECC_POINT *a)
|
||||
{
|
||||
return check_p256_param(&a->x) &&
|
||||
check_p256_param(&a->y);
|
||||
}
|
||||
|
||||
BOOL _cpri__EccIsPointOnCurve(TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q)
|
||||
{
|
||||
switch (curve_id) {
|
||||
case TPM_ECC_NIST_P256:
|
||||
if (!check_p256_point(q))
|
||||
return FALSE;
|
||||
|
||||
if (DCRYPTO_p256_valid_point((p256_int *) q->x.b.buffer,
|
||||
(p256_int *) q->y.b.buffer))
|
||||
return TRUE;
|
||||
else
|
||||
return FALSE;
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* out = n1*G + n2*in */
|
||||
CRYPT_RESULT _cpri__EccPointMultiply(
|
||||
TPMS_ECC_POINT *out, TPM_ECC_CURVE curve_id,
|
||||
TPM2B_ECC_PARAMETER *n1, TPMS_ECC_POINT *in, TPM2B_ECC_PARAMETER *n2)
|
||||
{
|
||||
int result;
|
||||
|
||||
switch (curve_id) {
|
||||
case TPM_ECC_NIST_P256:
|
||||
if (!check_p256_param(n1))
|
||||
return CRYPT_PARAMETER;
|
||||
if (in != NULL && !check_p256_point(in))
|
||||
return CRYPT_PARAMETER;
|
||||
if (n2 != NULL && !check_p256_param(n2))
|
||||
return CRYPT_PARAMETER;
|
||||
|
||||
if (in == NULL || n2 == NULL)
|
||||
result = DCRYPTO_p256_base_point_mul(
|
||||
(p256_int *) out->x.b.buffer,
|
||||
(p256_int *) out->y.b.buffer,
|
||||
(p256_int *) n1->b.buffer);
|
||||
else
|
||||
result = DCRYPTO_p256_points_mul(
|
||||
(p256_int *) out->x.b.buffer,
|
||||
(p256_int *) out->y.b.buffer,
|
||||
(p256_int *) n1->b.buffer,
|
||||
(p256_int *) n2->b.buffer,
|
||||
(p256_int *) in->x.b.buffer,
|
||||
(p256_int *) in->y.b.buffer);
|
||||
|
||||
if (result) {
|
||||
out->x.b.size = sizeof(p256_int);
|
||||
out->y.b.size = sizeof(p256_int);
|
||||
return CRYPT_SUCCESS;
|
||||
} else {
|
||||
return CRYPT_NO_RESULT;
|
||||
}
|
||||
default:
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
/* Key generation based on FIPS-186.4 section B.1.2 (Key Generation by
|
||||
* Testing Candidates) */
|
||||
CRYPT_RESULT _cpri__GenerateKeyEcc(
|
||||
TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
|
||||
TPM_ECC_CURVE curve_id, TPM_ALG_ID hash_alg,
|
||||
TPM2B *seed, const char *label, TPM2B *extra, UINT32 *counter)
|
||||
{
|
||||
TPM2B_4_BYTE_VALUE marshaled_counter = { .t = {4} };
|
||||
uint32_t count = 0;
|
||||
uint8_t key_bytes[P256_NBYTES];
|
||||
|
||||
if (curve_id != TPM_ECC_NIST_P256)
|
||||
return CRYPT_PARAMETER;
|
||||
|
||||
/* extra may be empty, but seed must be specified. */
|
||||
if (seed == NULL || seed->size < PRIMARY_SEED_SIZE)
|
||||
return CRYPT_PARAMETER;
|
||||
|
||||
if (counter != NULL)
|
||||
count = *counter;
|
||||
if (count == 0)
|
||||
count++;
|
||||
|
||||
for (; count != 0; count++) {
|
||||
memcpy(marshaled_counter.t.buffer, &count, sizeof(count));
|
||||
_cpri__KDFa(hash_alg, seed, label, extra, &marshaled_counter.b,
|
||||
sizeof(key_bytes) * 8, key_bytes, NULL, FALSE);
|
||||
if (DCRYPTO_p256_key_from_bytes(
|
||||
(p256_int *) q->x.b.buffer,
|
||||
(p256_int *) q->y.b.buffer,
|
||||
(p256_int *) d->b.buffer, key_bytes))
|
||||
break;
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
FAIL(FATAL_ERROR_INTERNAL);
|
||||
if (counter != NULL)
|
||||
*counter = count;
|
||||
return CRYPT_SUCCESS;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__SignEcc(
|
||||
TPM2B_ECC_PARAMETER *r, TPM2B_ECC_PARAMETER *s,
|
||||
TPM_ALG_ID scheme, TPM_ALG_ID hash_alg, TPM_ECC_CURVE curve_id,
|
||||
TPM2B_ECC_PARAMETER *d, TPM2B *digest, TPM2B_ECC_PARAMETER *k)
|
||||
{
|
||||
uint8_t digest_local[sizeof(p256_int)];
|
||||
const size_t digest_len = MIN(digest->size, sizeof(digest_local));
|
||||
p256_int p256_digest;
|
||||
|
||||
if (curve_id != TPM_ECC_NIST_P256)
|
||||
return CRYPT_PARAMETER;
|
||||
|
||||
switch (scheme) {
|
||||
case TPM_ALG_ECDSA:
|
||||
if (!check_p256_param(d))
|
||||
return CRYPT_PARAMETER;
|
||||
/* Trucate / zero-pad the digest as appropriate. */
|
||||
memset(digest_local, 0, sizeof(digest_local));
|
||||
memcpy(digest_local + sizeof(digest_local) - digest_len,
|
||||
digest->buffer, digest_len);
|
||||
p256_from_bin(digest_local, &p256_digest);
|
||||
DCRYPTO_p256_ecdsa_sign((p256_int *) d->b.buffer,
|
||||
&p256_digest,
|
||||
(p256_int *) r->b.buffer,
|
||||
(p256_int *) s->b.buffer);
|
||||
r->b.size = sizeof(p256_int);
|
||||
s->b.size = sizeof(p256_int);
|
||||
return CRYPT_SUCCESS;
|
||||
default:
|
||||
return CRYPT_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__ValidateSignatureEcc(
|
||||
TPM2B_ECC_PARAMETER *r, TPM2B_ECC_PARAMETER *s,
|
||||
TPM_ALG_ID scheme, TPM_ALG_ID hash_alg,
|
||||
TPM_ECC_CURVE curve_id, TPMS_ECC_POINT *q, TPM2B *digest)
|
||||
{
|
||||
uint8_t digest_local[sizeof(p256_int)];
|
||||
const size_t digest_len = MIN(digest->size, sizeof(digest_local));
|
||||
p256_int p256_digest;
|
||||
|
||||
if (curve_id != TPM_ECC_NIST_P256)
|
||||
return CRYPT_PARAMETER;
|
||||
|
||||
switch (scheme) {
|
||||
case TPM_ALG_ECDSA:
|
||||
/* Trucate / zero-pad the digest as appropriate. */
|
||||
memset(digest_local, 0, sizeof(digest_local));
|
||||
memcpy(digest_local + sizeof(digest_local) - digest_len,
|
||||
digest->buffer, digest_len);
|
||||
p256_from_bin(digest_local, &p256_digest);
|
||||
if (DCRYPTO_p256_ecdsa_verify(
|
||||
(p256_int *) q->x.b.buffer,
|
||||
(p256_int *) q->y.b.buffer,
|
||||
&p256_digest,
|
||||
(p256_int *) r->b.buffer,
|
||||
(p256_int *) s->b.buffer))
|
||||
return CRYPT_SUCCESS;
|
||||
else
|
||||
return CRYPT_FAIL;
|
||||
default:
|
||||
return CRYPT_PARAMETER;
|
||||
}
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__GetEphemeralEcc(TPMS_ECC_POINT *q, TPM2B_ECC_PARAMETER *d,
|
||||
TPM_ECC_CURVE curve_id)
|
||||
{
|
||||
uint8_t key_bytes[P256_NBYTES] __aligned(4);
|
||||
|
||||
if (curve_id != TPM_ECC_NIST_P256)
|
||||
return CRYPT_PARAMETER;
|
||||
|
||||
rand_bytes(key_bytes, sizeof(key_bytes));
|
||||
if (DCRYPTO_p256_key_from_bytes((p256_int *) q->x.b.buffer,
|
||||
(p256_int *) q->y.b.buffer,
|
||||
(p256_int *) d->b.buffer,
|
||||
key_bytes))
|
||||
return CRYPT_SUCCESS;
|
||||
else
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
#ifdef CRYPTO_TEST_SETUP
|
||||
|
||||
#include "extension.h"
|
||||
|
||||
enum {
|
||||
TEST_SIGN = 0,
|
||||
TEST_VERIFY = 1,
|
||||
TEST_KEYGEN = 2,
|
||||
TEST_KEYDERIVE = 3
|
||||
};
|
||||
|
||||
struct TPM2B_ECC_PARAMETER_aligned {
|
||||
uint16_t pad;
|
||||
TPM2B_ECC_PARAMETER d;
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct TPM2B_MAX_BUFFER_aligned {
|
||||
uint16_t pad;
|
||||
TPM2B_MAX_BUFFER d;
|
||||
} __packed __aligned(4);
|
||||
|
||||
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_d = {
|
||||
.d = {
|
||||
.t = {32, {
|
||||
0x0a, 0xd2, 0xa0, 0xfe, 0x89, 0xb2, 0x91, 0x09,
|
||||
0x87, 0xd4, 0x7f, 0xa2, 0x1f, 0xc9, 0x3e, 0x7e,
|
||||
0x7b, 0x2f, 0x48, 0x29, 0x6b, 0xe6, 0xb7, 0x09,
|
||||
0xf1, 0x48, 0x4e, 0x74, 0x07, 0x1e, 0x44, 0xfc
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qx = {
|
||||
.d = {
|
||||
.t = {32, {
|
||||
0xde, 0x81, 0x07, 0xe1, 0xe9, 0xb3, 0x6a, 0xa3,
|
||||
0xb2, 0x02, 0xac, 0xb0, 0x04, 0x7a, 0x57, 0xb4,
|
||||
0xbc, 0xd5, 0x4e, 0x20, 0x7f, 0x92, 0x4d, 0x3c,
|
||||
0xee, 0xa8, 0x9c, 0x67, 0xa2, 0xd6, 0xc3, 0x12
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static const struct TPM2B_ECC_PARAMETER_aligned NIST_P256_qy = {
|
||||
.d = {
|
||||
.t = {32, {
|
||||
0x1d, 0x52, 0x65, 0x86, 0xb5, 0xa4, 0xcc, 0xc6,
|
||||
0x9b, 0x68, 0x6d, 0x62, 0x8a, 0xfd, 0x9f, 0xc5,
|
||||
0x7b, 0x0e, 0x9d, 0xee, 0x8f, 0x73, 0xa5, 0xfc,
|
||||
0x72, 0x11, 0x97, 0x13, 0x74, 0xad, 0x85, 0x5c
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#define MAX_MSG_BYTES MAX_DIGEST_BUFFER
|
||||
|
||||
static int point_equals(const TPMS_ECC_POINT *a, const TPMS_ECC_POINT *b)
|
||||
{
|
||||
return a->x.b.size == b->x.b.size &&
|
||||
a->y.b.size == b->y.b.size &&
|
||||
memcmp(a->x.b.buffer, b->x.b.buffer, a->x.b.size) == 0 &&
|
||||
memcmp(a->y.b.buffer, b->y.b.buffer, a->y.b.size) == 0;
|
||||
|
||||
}
|
||||
|
||||
static void ec_command_handler(void *cmd_body, size_t cmd_size,
|
||||
size_t *response_size_out)
|
||||
{
|
||||
uint8_t *cmd;
|
||||
uint8_t op;
|
||||
uint8_t curve_id;
|
||||
uint8_t sign_mode;
|
||||
uint8_t hashing;
|
||||
uint16_t in_len;
|
||||
uint8_t in[MAX_MSG_BYTES];
|
||||
uint16_t digest_len;
|
||||
struct TPM2B_MAX_BUFFER_aligned digest;
|
||||
uint8_t *out = (uint8_t *) cmd_body;
|
||||
uint32_t *response_size = (uint32_t *) response_size_out;
|
||||
|
||||
TPMS_ECC_POINT q;
|
||||
TPM2B_ECC_PARAMETER *d;
|
||||
TPM2B_ECC_PARAMETER *qx;
|
||||
TPM2B_ECC_PARAMETER *qy;
|
||||
struct TPM2B_ECC_PARAMETER_aligned r;
|
||||
struct TPM2B_ECC_PARAMETER_aligned s;
|
||||
|
||||
/* Command format.
|
||||
*
|
||||
* OFFSET FIELD
|
||||
* 0 OP
|
||||
* 1 CURVE_ID
|
||||
* 2 SIGN_MODE
|
||||
* 3 HASHING
|
||||
* 4 MSB IN LEN
|
||||
* 5 LSB IN LEN
|
||||
* 6 IN
|
||||
* 6 + IN_LEN MSB DIGEST LEN
|
||||
* 7 + IN_LEN LSB DIGEST LEN
|
||||
* 8 + IN_LEN DIGEST
|
||||
*/
|
||||
|
||||
cmd = (uint8_t *) cmd_body;
|
||||
op = *cmd++;
|
||||
curve_id = *cmd++;
|
||||
sign_mode = *cmd++;
|
||||
hashing = *cmd++;
|
||||
in_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
|
||||
cmd += 2;
|
||||
if (in_len > sizeof(in)) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
memcpy(in, cmd, in_len);
|
||||
cmd += in_len;
|
||||
|
||||
digest_len = ((uint16_t) (cmd[0] << 8)) | cmd[1];
|
||||
cmd += 2;
|
||||
if (digest_len > sizeof(digest.d.t.buffer)) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
digest.d.t.size = digest_len;
|
||||
memcpy(digest.d.t.buffer, cmd, digest_len);
|
||||
cmd += digest_len;
|
||||
|
||||
switch (curve_id) {
|
||||
case TPM_ECC_NIST_P256:
|
||||
d = (TPM2B_ECC_PARAMETER *) &NIST_P256_d.d;
|
||||
qx = (TPM2B_ECC_PARAMETER *) &NIST_P256_qx.d;
|
||||
qy = (TPM2B_ECC_PARAMETER *) &NIST_P256_qy.d;
|
||||
q.x = *qx;
|
||||
q.y = *qy;
|
||||
break;
|
||||
default:
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (op) {
|
||||
case TEST_SIGN:
|
||||
if (_cpri__SignEcc(&r.d, &s.d, sign_mode, hashing,
|
||||
curve_id, d, &digest.d.b, NULL)
|
||||
!= CRYPT_SUCCESS) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
memcpy(out, r.d.b.buffer, r.d.b.size);
|
||||
out += r.d.b.size;
|
||||
memcpy(out, s.d.b.buffer, s.d.b.size);
|
||||
*response_size = r.d.b.size + s.d.b.size;
|
||||
break;
|
||||
case TEST_VERIFY:
|
||||
r.d.b.size = in_len / 2;
|
||||
memcpy(r.d.b.buffer, in, r.d.b.size);
|
||||
s.d.b.size = in_len / 2;
|
||||
memcpy(s.d.b.buffer, in + r.d.b.size, s.d.b.size);
|
||||
if (_cpri__ValidateSignatureEcc(
|
||||
&r.d, &s.d, sign_mode, hashing, curve_id,
|
||||
&q, &digest.d.b) != CRYPT_SUCCESS) {
|
||||
*response_size = 0;
|
||||
} else {
|
||||
*out = 1;
|
||||
*response_size = 1;
|
||||
}
|
||||
return;
|
||||
case TEST_KEYGEN:
|
||||
{
|
||||
struct TPM2B_ECC_PARAMETER_aligned d_local;
|
||||
TPMS_ECC_POINT q_local;
|
||||
|
||||
if (_cpri__GetEphemeralEcc(&q, &d_local.d, curve_id)
|
||||
!= CRYPT_SUCCESS) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify correspondence of secret with the public point. */
|
||||
if (_cpri__EccPointMultiply(
|
||||
&q_local, curve_id, &d_local.d,
|
||||
NULL, NULL) != CRYPT_SUCCESS) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
if (!point_equals(&q, &q_local)) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
*out = 1;
|
||||
*response_size = 1;
|
||||
return;
|
||||
}
|
||||
case TEST_KEYDERIVE:
|
||||
{
|
||||
/* Random seed. */
|
||||
TPM2B_SEED seed;
|
||||
struct TPM2B_ECC_PARAMETER_aligned d_local;
|
||||
TPMS_ECC_POINT q_local;
|
||||
const char *label = "ec_test";
|
||||
|
||||
|
||||
if (in_len > PRIMARY_SEED_SIZE) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
seed.t.size = in_len;
|
||||
memcpy(seed.t.buffer, in, in_len);
|
||||
|
||||
if (_cpri__GenerateKeyEcc(
|
||||
&q, &d_local.d, curve_id, hashing,
|
||||
&seed.b, label, NULL, NULL) != CRYPT_SUCCESS) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_cpri__EccIsPointOnCurve(curve_id, &q) != TRUE) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Verify correspondence of secret with the public point. */
|
||||
if (_cpri__EccPointMultiply(
|
||||
&q_local, curve_id, &d_local.d,
|
||||
NULL, NULL) != CRYPT_SUCCESS) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
if (!point_equals(&q, &q_local)) {
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
*out = 1;
|
||||
*response_size = 1;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
*response_size = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DECLARE_EXTENSION_COMMAND(EXTENSION_EC, ec_command_handler);
|
||||
|
||||
#endif /* CRYPTO_TEST_SETUP */
|
||||
@@ -46,45 +46,6 @@ CRYPT_RESULT _cpri__EccCommitCompute(
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
BOOL _cpri__EccIsPointOnCurve(
|
||||
TPM_ECC_CURVE curveId, // IN: the curve selector
|
||||
TPMS_ECC_POINT * Q // IN: the point.
|
||||
)
|
||||
{
|
||||
ecprintf("%s called\n", __func__);
|
||||
return 0;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__EccPointMultiply(
|
||||
TPMS_ECC_POINT * Rout, // OUT: the product point R
|
||||
TPM_ECC_CURVE curveId, // IN: the curve to use
|
||||
TPM2B_ECC_PARAMETER * dIn, // IN: value to multiply against the
|
||||
// curve generator
|
||||
TPMS_ECC_POINT * Qin, // IN: point Q
|
||||
TPM2B_ECC_PARAMETER * uIn // IN: scalar value for the multiplier of Q
|
||||
)
|
||||
{
|
||||
ecprintf("%s called\n", __func__);
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__GenerateKeyEcc(
|
||||
TPMS_ECC_POINT * Qout, // OUT: the public point
|
||||
TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar
|
||||
TPM_ECC_CURVE curveId, // IN: the curve identifier
|
||||
TPM_ALG_ID hashAlg, // IN: hash algorithm to use in the key
|
||||
// generation process
|
||||
TPM2B * seed, // IN: the seed to use
|
||||
const char *label, // IN: A label for the generation process.
|
||||
TPM2B * extra, // IN: Party 1 data for the KDF
|
||||
UINT32 * counter // IN/OUT: Counter value to allow KDF
|
||||
// iteration to be propagated across multiple functions
|
||||
)
|
||||
{
|
||||
ecprintf("%s called\n", __func__);
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__GenerateKeyRSA(
|
||||
TPM2B * n, // OUT: The public modulu
|
||||
TPM2B * p, // OUT: One of the prime factors of n
|
||||
@@ -102,31 +63,6 @@ CRYPT_RESULT _cpri__GenerateKeyRSA(
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__GetEphemeralEcc(
|
||||
TPMS_ECC_POINT * Qout, // OUT: the public point
|
||||
TPM2B_ECC_PARAMETER * dOut, // OUT: the private scalar
|
||||
TPM_ECC_CURVE curveId // IN: the curve for the key
|
||||
)
|
||||
{
|
||||
ecprintf("%s called\n", __func__);
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__SignEcc(
|
||||
TPM2B_ECC_PARAMETER * rOut, // OUT: r component of the signature
|
||||
TPM2B_ECC_PARAMETER * sOut, // OUT: s component of the signature
|
||||
TPM_ALG_ID scheme, // IN: the scheme selector
|
||||
TPM_ALG_ID hashAlg, // IN: the hash algorithm if need
|
||||
TPM_ECC_CURVE curveId, // IN: the curve used in the signature process
|
||||
TPM2B_ECC_PARAMETER * dIn, // IN: the private key
|
||||
TPM2B * digest, // IN: the digest to sign
|
||||
TPM2B_ECC_PARAMETER * kIn // IN: k for input
|
||||
)
|
||||
{
|
||||
ecprintf("%s called\n", __func__);
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
BOOL _cpri__Startup(
|
||||
void)
|
||||
{
|
||||
@@ -159,22 +95,6 @@ CRYPT_RESULT _cpri__TestKeyRSA(
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
CRYPT_RESULT _cpri__ValidateSignatureEcc(
|
||||
TPM2B_ECC_PARAMETER * rIn, // IN: r component of the signature
|
||||
TPM2B_ECC_PARAMETER * sIn, // IN: s component of the signature
|
||||
TPM_ALG_ID scheme, // IN: the scheme selector
|
||||
TPM_ALG_ID hashAlg, // IN: the hash algorithm used (not used
|
||||
// in all schemes)
|
||||
TPM_ECC_CURVE curveId, // IN: the curve used in the
|
||||
// signature process
|
||||
TPMS_ECC_POINT * Qin, // IN: the public point of the key
|
||||
TPM2B * digest // IN: the digest that was signed
|
||||
)
|
||||
{
|
||||
ecprintf("%s called\n", __func__);
|
||||
return CRYPT_FAIL;
|
||||
}
|
||||
|
||||
int _math__Comp(
|
||||
const UINT32 aSize, // IN: size of a
|
||||
const BYTE * a, // IN: a buffer
|
||||
|
||||
@@ -27,6 +27,10 @@ endif
|
||||
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/aes.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/bn.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/hmac.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ec.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/p256_ecdsa.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/rsa.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/sha1.o
|
||||
chip-$(CONFIG_DCRYPTO)+= dcrypto/sha256.o
|
||||
|
||||
@@ -119,4 +119,22 @@ int DCRYPTO_rsa_verify(struct RSA *rsa, const uint8_t *digest,
|
||||
const uint32_t sig_len, enum padding_mode padding,
|
||||
enum hashing_mode hashing);
|
||||
|
||||
/*
|
||||
* EC.
|
||||
*/
|
||||
int DCRYPTO_p256_valid_point(const p256_int *x, const p256_int *y);
|
||||
int DCRYPTO_p256_base_point_mul(p256_int *out_x, p256_int *out_y,
|
||||
const p256_int *n);
|
||||
int DCRYPTO_p256_points_mul(p256_int *out_x, p256_int *out_y,
|
||||
const p256_int *n1, const p256_int *n2,
|
||||
const p256_int *in_x, const p256_int *in_y);
|
||||
int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
|
||||
const uint8_t key_bytes[P256_NBYTES]);
|
||||
|
||||
void DCRYPTO_p256_ecdsa_sign(const p256_int *d, const p256_int *digest,
|
||||
p256_int *r, p256_int *s);
|
||||
int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
|
||||
const p256_int *digest, const p256_int *r,
|
||||
const p256_int *s);
|
||||
|
||||
#endif /* ! __EC_CHIP_G_DCRYPTO_DCRYPTO_H */
|
||||
|
||||
56
chip/g/dcrypto/hmac.c
Normal file
56
chip/g/dcrypto/hmac.c
Normal file
@@ -0,0 +1,56 @@
|
||||
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "internal.h"
|
||||
#include "dcrypto.h"
|
||||
|
||||
static void HMAC_init(struct HMAC_CTX *ctx, const void *key, unsigned int len)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
memset(&ctx->opad[0], 0, sizeof(ctx->opad));
|
||||
|
||||
if (len > sizeof(ctx->opad)) {
|
||||
DCRYPTO_SHA256_init(&ctx->hash, 0);
|
||||
DCRYPTO_HASH_update(&ctx->hash, key, len);
|
||||
memcpy(&ctx->opad[0], DCRYPTO_HASH_final(&ctx->hash),
|
||||
DCRYPTO_HASH_size(&ctx->hash));
|
||||
} else {
|
||||
memcpy(&ctx->opad[0], key, len);
|
||||
}
|
||||
|
||||
for (i = 0; i < sizeof(ctx->opad); ++i)
|
||||
ctx->opad[i] ^= 0x36;
|
||||
|
||||
DCRYPTO_SHA256_init(&ctx->hash, 0);
|
||||
/* hash ipad */
|
||||
DCRYPTO_HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
|
||||
|
||||
for (i = 0; i < sizeof(ctx->opad); ++i)
|
||||
ctx->opad[i] ^= (0x36 ^ 0x5c);
|
||||
}
|
||||
|
||||
void dcrypto_HMAC_SHA256_init(struct HMAC_CTX *ctx, const void *key,
|
||||
unsigned int len)
|
||||
{
|
||||
DCRYPTO_SHA256_init(&ctx->hash, 0);
|
||||
HMAC_init(ctx, key, len);
|
||||
}
|
||||
|
||||
const uint8_t *dcrypto_HMAC_final(struct HMAC_CTX *ctx)
|
||||
{
|
||||
uint8_t digest[SHA_DIGEST_MAX_BYTES]; /* upto SHA2 */
|
||||
|
||||
memcpy(digest, DCRYPTO_HASH_final(&ctx->hash),
|
||||
(DCRYPTO_HASH_size(&ctx->hash) <= sizeof(digest) ?
|
||||
DCRYPTO_HASH_size(&ctx->hash) : sizeof(digest)));
|
||||
DCRYPTO_SHA256_init(&ctx->hash, 0);
|
||||
DCRYPTO_HASH_update(&ctx->hash, ctx->opad, sizeof(ctx->opad));
|
||||
DCRYPTO_HASH_update(&ctx->hash, digest, DCRYPTO_HASH_size(&ctx->hash));
|
||||
memset(&ctx->opad[0], 0, sizeof(ctx->opad)); /* wipe key */
|
||||
return DCRYPTO_HASH_final(&ctx->hash);
|
||||
}
|
||||
@@ -82,6 +82,21 @@ void dcrypto_sha_update(struct HASH_CTX *unused,
|
||||
const uint8_t *data, uint32_t n);
|
||||
void dcrypto_sha_wait(enum sha_mode mode, uint32_t *digest);
|
||||
|
||||
/*
|
||||
* HMAC.
|
||||
*/
|
||||
struct HMAC_CTX {
|
||||
struct HASH_CTX hash;
|
||||
uint8_t opad[64];
|
||||
};
|
||||
|
||||
#define HASH_update(ctx, data, len) \
|
||||
((ctx)->vtab->update((ctx), (data), (len)))
|
||||
void dcrypto_HMAC_SHA256_init(struct HMAC_CTX *ctx, const void *key,
|
||||
unsigned int len);
|
||||
#define dcrypto_HMAC_update(ctx, data, len) HASH_update(&(ctx)->hash, data, len)
|
||||
const uint8_t *dcrypto_HMAC_final(struct HMAC_CTX *ctx);
|
||||
|
||||
/*
|
||||
* BIGNUM.
|
||||
*/
|
||||
@@ -101,6 +116,53 @@ int bn_check_topbit(const struct BIGNUM *N);
|
||||
void bn_mont_modexp(struct BIGNUM *output, const struct BIGNUM *input,
|
||||
const struct BIGNUM *exp, const struct BIGNUM *N);
|
||||
|
||||
/*
|
||||
* EC.
|
||||
*/
|
||||
#define P256_BITSPERDIGIT 32
|
||||
#define P256_NDIGITS 8
|
||||
#define P256_NBYTES 32
|
||||
|
||||
typedef uint32_t p256_digit;
|
||||
typedef int32_t p256_sdigit;
|
||||
typedef uint64_t p256_ddigit;
|
||||
typedef int64_t p256_sddigit;
|
||||
|
||||
/* Define p256_int as a struct to leverage struct assignment. */
|
||||
typedef struct {
|
||||
p256_digit a[P256_NDIGITS] __packed;
|
||||
} p256_int;
|
||||
|
||||
#define P256_DIGITS(x) ((x)->a)
|
||||
#define P256_DIGIT(x, y) ((x)->a[y])
|
||||
|
||||
#define P256_ZERO { {0} }
|
||||
#define P256_ONE { {1} }
|
||||
|
||||
/* Curve constants. */
|
||||
extern const p256_int SECP256r1_n;
|
||||
extern const p256_int SECP256r1_p;
|
||||
extern const p256_int SECP256r1_b;
|
||||
|
||||
void p256_init(p256_int *a);
|
||||
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst);
|
||||
#define p256_clear(a) p256_init((a))
|
||||
int p256_is_zero(const p256_int *a);
|
||||
int p256_cmp(const p256_int *a, const p256_int *b);
|
||||
int p256_get_bit(const p256_int *scalar, int bit);
|
||||
p256_digit p256_shl(const p256_int *a, int n, p256_int *b);
|
||||
void p256_shr(const p256_int *a, int n, p256_int *b);
|
||||
int p256_add(const p256_int *a, const p256_int *b, p256_int *c);
|
||||
int p256_add_d(const p256_int *a, p256_digit d, p256_int *b);
|
||||
void p256_points_mul_vartime(
|
||||
const p256_int *n1, const p256_int *n2, const p256_int *in_x,
|
||||
const p256_int *in_y, p256_int *out_x, p256_int *out_y);
|
||||
void p256_mod(const p256_int *MOD, const p256_int *in, p256_int *out);
|
||||
void p256_modmul(const p256_int *MOD, const p256_int *a,
|
||||
const p256_digit top_b, const p256_int *b, p256_int *c);
|
||||
void p256_modinv(const p256_int *MOD, const p256_int *a, p256_int *b);
|
||||
void p256_modinv_vartime(const p256_int *MOD, const p256_int *a, p256_int *b);
|
||||
|
||||
/*
|
||||
* Utility functions.
|
||||
*/
|
||||
|
||||
444
chip/g/dcrypto/p256.c
Normal file
444
chip/g/dcrypto/p256.c
Normal file
@@ -0,0 +1,444 @@
|
||||
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "dcrypto.h"
|
||||
#include "internal.h"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
const p256_int SECP256r1_n = /* curve order */
|
||||
{ {0xfc632551, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1} };
|
||||
static const p256_int SECP256r1_nMin2 = /* curve order - 2 */
|
||||
{ {0xfc632551 - 2, 0xf3b9cac2, 0xa7179e84, 0xbce6faad, -1, -1, 0, -1} };
|
||||
const p256_int SECP256r1_p = /* curve field size */
|
||||
{ {-1, -1, -1, 0, 0, 0, 1, -1 } };
|
||||
const p256_int SECP256r1_b = /* curve b */
|
||||
{ {0x27d2604b, 0x3bce3c3e, 0xcc53b0f6, 0x651d06b0,
|
||||
0x769886bc, 0xb3ebbd55, 0xaa3a93e7, 0x5ac635d8} };
|
||||
static const p256_int p256_one = P256_ONE;
|
||||
|
||||
void p256_init(p256_int *a)
|
||||
{
|
||||
memset(a, 0, sizeof(*a));
|
||||
}
|
||||
|
||||
int p256_get_bit(const p256_int *scalar, int bit)
|
||||
{
|
||||
return (P256_DIGIT(scalar, bit / P256_BITSPERDIGIT)
|
||||
>> (bit & (P256_BITSPERDIGIT - 1))) & 1;
|
||||
}
|
||||
|
||||
p256_digit p256_shl(const p256_int *a, int n, p256_int *b)
|
||||
{
|
||||
int i;
|
||||
p256_digit top = P256_DIGIT(a, P256_NDIGITS - 1);
|
||||
|
||||
n %= P256_BITSPERDIGIT;
|
||||
for (i = P256_NDIGITS - 1; i > 0; --i) {
|
||||
p256_digit accu = (P256_DIGIT(a, i) << n);
|
||||
|
||||
accu |= (P256_DIGIT(a, i - 1) >> (P256_BITSPERDIGIT - n));
|
||||
P256_DIGIT(b, i) = accu;
|
||||
}
|
||||
P256_DIGIT(b, i) = (P256_DIGIT(a, i) << n);
|
||||
|
||||
top >>= (P256_BITSPERDIGIT - n);
|
||||
|
||||
return top;
|
||||
}
|
||||
|
||||
void p256_shr(const p256_int *a, int n, p256_int *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
n %= P256_BITSPERDIGIT;
|
||||
for (i = 0; i < P256_NDIGITS - 1; ++i) {
|
||||
p256_digit accu = (P256_DIGIT(a, i) >> n);
|
||||
|
||||
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - n));
|
||||
P256_DIGIT(b, i) = accu;
|
||||
}
|
||||
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> n);
|
||||
}
|
||||
|
||||
int p256_is_zero(const p256_int *a)
|
||||
{
|
||||
int i, result = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i)
|
||||
result |= P256_DIGIT(a, i);
|
||||
return !result;
|
||||
}
|
||||
|
||||
int p256_cmp(const p256_int *a, const p256_int *b)
|
||||
{
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
p256_digit notzero = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += (p256_sddigit) P256_DIGIT(a, i) - P256_DIGIT(b, i);
|
||||
/* Track whether any result digit is ever not zero.
|
||||
* Relies on !!(non-zero) evaluating to 1, e.g., !!(-1)
|
||||
* evaluating to 1. */
|
||||
notzero |= !!((p256_digit) borrow);
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int) borrow | notzero;
|
||||
}
|
||||
|
||||
/* c = a - b. Returns borrow: 0 or -1. */
|
||||
int p256_sub(const p256_int *a, const p256_int *b, p256_int *c)
|
||||
{
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += (p256_sddigit) P256_DIGIT(a, i) - P256_DIGIT(b, i);
|
||||
if (c)
|
||||
P256_DIGIT(c, i) = (p256_digit) borrow;
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int) borrow;
|
||||
}
|
||||
|
||||
/* c = a + b. Returns carry: 0 or 1. */
|
||||
int p256_add(const p256_int *a, const p256_int *b, p256_int *c)
|
||||
{
|
||||
int i;
|
||||
p256_ddigit carry = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += (p256_ddigit) P256_DIGIT(a, i) + P256_DIGIT(b, i);
|
||||
if (c)
|
||||
P256_DIGIT(c, i) = (p256_digit) carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int) carry;
|
||||
}
|
||||
|
||||
/* b = a + d. Returns carry, 0 or 1. */
|
||||
int p256_add_d(const p256_int *a, p256_digit d, p256_int *b)
|
||||
{
|
||||
int i;
|
||||
p256_ddigit carry = d;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += (p256_ddigit) P256_DIGIT(a, i);
|
||||
if (b)
|
||||
P256_DIGIT(b, i) = (p256_digit) carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return (int) carry;
|
||||
}
|
||||
|
||||
/* top, c[] += a[] * b */
|
||||
/* Returns new top. */
|
||||
static p256_digit p256_muladd(const p256_int *a, p256_digit b,
|
||||
p256_digit top, p256_digit *c)
|
||||
{
|
||||
int i;
|
||||
p256_ddigit carry = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += *c;
|
||||
carry += (p256_ddigit) P256_DIGIT(a, i) * b;
|
||||
*c++ = (p256_digit) carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return top + (p256_digit) carry;
|
||||
}
|
||||
|
||||
/* top, c[] -= top_a, a[] */
|
||||
static p256_digit p256_subtop(p256_digit top_a, const p256_digit *a,
|
||||
p256_digit top_c, p256_digit *c)
|
||||
{
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += *c;
|
||||
borrow -= *a++;
|
||||
*c++ = (p256_digit) borrow;
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
borrow += top_c;
|
||||
borrow -= top_a;
|
||||
top_c = (p256_digit) borrow;
|
||||
assert((borrow >> P256_BITSPERDIGIT) == 0);
|
||||
return top_c;
|
||||
}
|
||||
|
||||
/* top, c[] += MOD[] & mask (0 or -1) */
|
||||
/* returns new top. */
|
||||
static p256_digit p256_addM(const p256_int *MOD, p256_digit top,
|
||||
p256_digit *c, p256_digit mask)
|
||||
{
|
||||
int i;
|
||||
p256_ddigit carry = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
carry += *c;
|
||||
carry += P256_DIGIT(MOD, i) & mask;
|
||||
*c++ = (p256_digit) carry;
|
||||
carry >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return top + (p256_digit) carry;
|
||||
}
|
||||
|
||||
/* top, c[] -= MOD[] & mask (0 or -1) */
|
||||
/* returns new top. */
|
||||
static p256_digit p256_subM(const p256_int *MOD, p256_digit top,
|
||||
p256_digit *c, p256_digit mask)
|
||||
{
|
||||
int i;
|
||||
p256_sddigit borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
borrow += *c;
|
||||
borrow -= P256_DIGIT(MOD, i) & mask;
|
||||
*c++ = (p256_digit) borrow;
|
||||
borrow >>= P256_BITSPERDIGIT;
|
||||
}
|
||||
return top + (p256_digit) borrow;
|
||||
}
|
||||
|
||||
/* Convert in. */
|
||||
void p256_from_bin(const uint8_t src[P256_NBYTES], p256_int *dst)
|
||||
{
|
||||
int i;
|
||||
const uint8_t *p = &src[0];
|
||||
|
||||
for (i = P256_NDIGITS - 1; i >= 0; --i) {
|
||||
P256_DIGIT(dst, i) =
|
||||
(p[0] << 24) |
|
||||
(p[1] << 16) |
|
||||
(p[2] << 8) |
|
||||
p[3];
|
||||
p += 4;
|
||||
}
|
||||
}
|
||||
|
||||
void p256_mod(const p256_int *MOD, const p256_int *in, p256_int *out)
|
||||
{
|
||||
if (out != in)
|
||||
*out = *in;
|
||||
p256_addM(MOD, 0, P256_DIGITS(out),
|
||||
p256_subM(MOD, 0, P256_DIGITS(out), -1));
|
||||
}
|
||||
|
||||
|
||||
void p256_modmul(const p256_int *MOD, const p256_int *a,
|
||||
const p256_digit top_b, const p256_int *b, p256_int *c)
|
||||
{
|
||||
p256_digit tmp[P256_NDIGITS * 2 + 1] = { 0 };
|
||||
p256_digit top = 0;
|
||||
int i;
|
||||
|
||||
/* Multiply/add into tmp. */
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
if (i)
|
||||
tmp[i + P256_NDIGITS - 1] = top;
|
||||
top = p256_muladd(a, P256_DIGIT(b, i), 0, tmp + i);
|
||||
}
|
||||
|
||||
/* Multiply/add top digit. */
|
||||
tmp[i + P256_NDIGITS - 1] = top;
|
||||
top = p256_muladd(a, top_b, 0, tmp + i);
|
||||
|
||||
/* Reduce tmp, digit by digit. */
|
||||
for (; i >= 0; --i) {
|
||||
p256_digit reducer[P256_NDIGITS] = { 0 };
|
||||
p256_digit top_reducer;
|
||||
|
||||
/* top can be any value at this point.
|
||||
* Guestimate reducer as top * MOD, since msw of MOD is -1. */
|
||||
top_reducer = p256_muladd(MOD, top, 0, reducer);
|
||||
|
||||
/* Subtract reducer from top | tmp. */
|
||||
top = p256_subtop(top_reducer, reducer, top, tmp + i);
|
||||
|
||||
/* top is now either 0 or 1. Make it 0, fixed-timing. */
|
||||
assert(top <= 1);
|
||||
|
||||
top = p256_subM(MOD, top, tmp + i, ~(top - 1));
|
||||
|
||||
assert(top == 0);
|
||||
|
||||
/* We have now reduced the top digit off tmp. Fetch
|
||||
* new top digit. */
|
||||
top = tmp[i + P256_NDIGITS - 1];
|
||||
}
|
||||
|
||||
/* tmp might still be larger than MOD, yet same bit length.
|
||||
* Make sure it is less, fixed-timing. */
|
||||
p256_addM(MOD, 0, tmp, p256_subM(MOD, 0, tmp, -1));
|
||||
|
||||
memcpy(c, tmp, P256_NBYTES);
|
||||
}
|
||||
|
||||
/* if (mask) dst = src, fixed-timing style. */
|
||||
static void conditional_copy(const p256_int *src, p256_int *dst, int mask)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS; ++i) {
|
||||
p256_digit b = P256_DIGIT(src, i) & mask; /* 0 or src[i] */
|
||||
|
||||
b |= P256_DIGIT(dst, i) & ~mask; /* dst[i] or 0 */
|
||||
P256_DIGIT(dst, i) = b;
|
||||
}
|
||||
}
|
||||
|
||||
/* -1 iff (x & 15) == 0, 0 otherwise. */
|
||||
/* Relies on arithmetic shift right behavior. */
|
||||
#define ZEROtoONES(x) (((int32_t)(((x) & 15) - 1)) >> 31)
|
||||
|
||||
/* tbl[0] = tbl[idx], fixed-timing style. */
|
||||
static void set0ToIdx(p256_int tbl[16], int idx)
|
||||
{
|
||||
int32_t i;
|
||||
|
||||
tbl[0] = p256_one;
|
||||
for (i = 1; i < 16; ++i)
|
||||
conditional_copy(&tbl[i], &tbl[0], ZEROtoONES(i - idx));
|
||||
}
|
||||
|
||||
/* b = 1/a mod MOD, fixed timing, Fermat's little theorem. */
|
||||
void p256_modinv(const p256_int *MOD, const p256_int *a, p256_int *b)
|
||||
{
|
||||
int i;
|
||||
p256_int tbl[16];
|
||||
|
||||
/* tbl[i] = a**i, tbl[0] unused. */
|
||||
tbl[1] = *a;
|
||||
for (i = 2; i < 16; ++i)
|
||||
p256_modmul(MOD, &tbl[i-1], 0, a, &tbl[i]);
|
||||
|
||||
*b = p256_one;
|
||||
for (i = 256; i > 0; i -= 4) {
|
||||
int32_t idx = 0;
|
||||
|
||||
p256_modmul(MOD, b, 0, b, b);
|
||||
p256_modmul(MOD, b, 0, b, b);
|
||||
p256_modmul(MOD, b, 0, b, b);
|
||||
p256_modmul(MOD, b, 0, b, b);
|
||||
idx |= p256_get_bit(&SECP256r1_nMin2, i - 1) << 3;
|
||||
idx |= p256_get_bit(&SECP256r1_nMin2, i - 2) << 2;
|
||||
idx |= p256_get_bit(&SECP256r1_nMin2, i - 3) << 1;
|
||||
idx |= p256_get_bit(&SECP256r1_nMin2, i - 4) << 0;
|
||||
set0ToIdx(tbl, idx); /* tbl[0] = tbl[idx] */
|
||||
p256_modmul(MOD, b, 0, &tbl[0], &tbl[0]);
|
||||
conditional_copy(&tbl[0], b, ~ZEROtoONES(idx));
|
||||
}
|
||||
}
|
||||
|
||||
static int p256_is_even(const p256_int *a)
|
||||
{
|
||||
return !(P256_DIGIT(a, 0) & 1);
|
||||
}
|
||||
|
||||
static void p256_shr1(const p256_int *a, int highbit, p256_int *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < P256_NDIGITS - 1; ++i) {
|
||||
p256_digit accu = (P256_DIGIT(a, i) >> 1);
|
||||
|
||||
accu |= (P256_DIGIT(a, i + 1) << (P256_BITSPERDIGIT - 1));
|
||||
P256_DIGIT(b, i) = accu;
|
||||
}
|
||||
P256_DIGIT(b, i) = (P256_DIGIT(a, i) >> 1) |
|
||||
(highbit << (P256_BITSPERDIGIT - 1));
|
||||
}
|
||||
|
||||
/* b = 1/a mod MOD, binary euclid. */
|
||||
void p256_modinv_vartime(const p256_int *MOD, const p256_int *a, p256_int *b)
|
||||
{
|
||||
p256_int R = P256_ZERO;
|
||||
p256_int S = P256_ONE;
|
||||
p256_int U = *MOD;
|
||||
p256_int V = *a;
|
||||
|
||||
for (;;) {
|
||||
if (p256_is_even(&U)) {
|
||||
p256_shr1(&U, 0, &U);
|
||||
if (p256_is_even(&R)) {
|
||||
p256_shr1(&R, 0, &R);
|
||||
} else {
|
||||
/* R = (R + MOD)/2 */
|
||||
p256_shr1(&R, p256_add(&R, MOD, &R), &R);
|
||||
}
|
||||
} else if (p256_is_even(&V)) {
|
||||
p256_shr1(&V, 0, &V);
|
||||
if (p256_is_even(&S)) {
|
||||
p256_shr1(&S, 0, &S);
|
||||
} else {
|
||||
/* S = (S + MOD)/2 */
|
||||
p256_shr1(&S, p256_add(&S, MOD, &S) , &S);
|
||||
}
|
||||
} else { /* U, V both odd. */
|
||||
if (!p256_sub(&V, &U, NULL)) {
|
||||
p256_sub(&V, &U, &V);
|
||||
if (p256_sub(&S, &R, &S))
|
||||
p256_add(&S, MOD, &S);
|
||||
if (p256_is_zero(&V))
|
||||
break; /* done. */
|
||||
} else {
|
||||
p256_sub(&U, &V, &U);
|
||||
if (p256_sub(&R, &S, &R))
|
||||
p256_add(&R, MOD, &R);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
p256_mod(MOD, &R, b);
|
||||
}
|
||||
|
||||
int DCRYPTO_p256_valid_point(const p256_int *x, const p256_int *y)
|
||||
{
|
||||
p256_int y2, x3;
|
||||
|
||||
if (p256_cmp(&SECP256r1_p, x) <= 0 || p256_cmp(&SECP256r1_p, y) <= 0 ||
|
||||
p256_is_zero(x) || p256_is_zero(y))
|
||||
return 0;
|
||||
|
||||
p256_modmul(&SECP256r1_p, y, 0, y, &y2); /* y^2 */
|
||||
|
||||
p256_modmul(&SECP256r1_p, x, 0, x, &x3); /* x^2 */
|
||||
p256_modmul(&SECP256r1_p, x, 0, &x3, &x3); /* x^3 */
|
||||
if (p256_sub(&x3, x, &x3))
|
||||
p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - x */
|
||||
if (p256_sub(&x3, x, &x3))
|
||||
p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - 2x */
|
||||
if (p256_sub(&x3, x, &x3))
|
||||
p256_add(&x3, &SECP256r1_p, &x3); /* x^3 - 3x */
|
||||
if (p256_add(&x3, &SECP256r1_b, &x3)) /* x^3 - 3x + b */
|
||||
p256_sub(&x3, &SECP256r1_p, &x3);
|
||||
if (p256_sub(&x3, &SECP256r1_p, &x3)) /* make sure 0 <= x3 < p */
|
||||
p256_add(&x3, &SECP256r1_p, &x3);
|
||||
|
||||
return p256_cmp(&y2, &x3) == 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Key selection based on FIPS-186-4, section B.4.2 (Key Pair
|
||||
* Generation by Testing Candidates).
|
||||
*/
|
||||
int DCRYPTO_p256_key_from_bytes(p256_int *x, p256_int *y, p256_int *d,
|
||||
const uint8_t key_bytes[P256_NBYTES])
|
||||
{
|
||||
int valid;
|
||||
p256_int key;
|
||||
|
||||
p256_from_bin(key_bytes, &key);
|
||||
if (p256_cmp(&SECP256r1_nMin2, &key) < 0)
|
||||
return 0;
|
||||
p256_add(&key, &p256_one, &key);
|
||||
valid = DCRYPTO_p256_base_point_mul(x, y, &key);
|
||||
if (valid)
|
||||
*d = key;
|
||||
return valid;
|
||||
}
|
||||
1403
chip/g/dcrypto/p256_ec.c
Normal file
1403
chip/g/dcrypto/p256_ec.c
Normal file
File diff suppressed because it is too large
Load Diff
103
chip/g/dcrypto/p256_ecdsa.c
Normal file
103
chip/g/dcrypto/p256_ecdsa.c
Normal file
@@ -0,0 +1,103 @@
|
||||
/* Copyright 2015 The Chromium OS Authors. All rights reserved.
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "dcrypto.h"
|
||||
|
||||
/* Compute k based on a given {key, digest} pair, 0 < k < n. */
|
||||
static void determine_k(const p256_int *key, const p256_int *digest,
|
||||
char *tweak, p256_int *k)
|
||||
{
|
||||
do {
|
||||
p256_int p1, p2;
|
||||
struct HMAC_CTX hmac;
|
||||
|
||||
/* NOTE: taking the p256_int in-memory representation
|
||||
* is not endian neutral. Signatures with an
|
||||
* identical key on identical digests will differ per
|
||||
* host endianness. This however does not jeopardize
|
||||
* the key bits. */
|
||||
dcrypto_HMAC_SHA256_init(&hmac, key, P256_NBYTES);
|
||||
dcrypto_HMAC_update(&hmac, tweak, 1);
|
||||
dcrypto_HMAC_update(&hmac, (uint8_t *) digest, P256_NBYTES);
|
||||
++(*tweak);
|
||||
p256_from_bin(dcrypto_HMAC_final(&hmac), &p1);
|
||||
|
||||
dcrypto_HMAC_SHA256_init(&hmac, key, P256_NBYTES);
|
||||
dcrypto_HMAC_update(&hmac, tweak, 1);
|
||||
dcrypto_HMAC_update(&hmac, (uint8_t *) digest, P256_NBYTES);
|
||||
++(*tweak);
|
||||
p256_from_bin(dcrypto_HMAC_final(&hmac), &p2);
|
||||
|
||||
/* Combine p1 and p2 into well distributed k. */
|
||||
p256_modmul(&SECP256r1_n, &p1, 0, &p2, k);
|
||||
|
||||
/* (Attempt to) clear stack state. */
|
||||
p256_clear(&p1);
|
||||
p256_clear(&p2);
|
||||
|
||||
} while (p256_is_zero(k));
|
||||
}
|
||||
|
||||
void DCRYPTO_p256_ecdsa_sign(const p256_int *key, const p256_int *digest,
|
||||
p256_int *r, p256_int *s)
|
||||
{
|
||||
char tweak = 'A';
|
||||
p256_digit top;
|
||||
|
||||
for (;;) {
|
||||
p256_int k, kinv;
|
||||
|
||||
determine_k(key, digest, &tweak, &k);
|
||||
DCRYPTO_p256_base_point_mul(r, s, &k);
|
||||
p256_mod(&SECP256r1_n, r, r);
|
||||
|
||||
/* Make sure r != 0. */
|
||||
if (p256_is_zero(r))
|
||||
continue;
|
||||
|
||||
p256_modmul(&SECP256r1_n, r, 0, key, s);
|
||||
top = p256_add(s, digest, s);
|
||||
p256_modinv(&SECP256r1_n, &k, &kinv);
|
||||
p256_modmul(&SECP256r1_n, &kinv, top, s, s);
|
||||
|
||||
/* (Attempt to) clear stack state. */
|
||||
p256_clear(&k);
|
||||
p256_clear(&kinv);
|
||||
|
||||
/* Make sure s != 0. */
|
||||
if (p256_is_zero(s))
|
||||
continue;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int DCRYPTO_p256_ecdsa_verify(const p256_int *key_x, const p256_int *key_y,
|
||||
const p256_int *digest,
|
||||
const p256_int *r, const p256_int *s)
|
||||
{
|
||||
p256_int u, v;
|
||||
|
||||
/* Check public key. */
|
||||
if (!DCRYPTO_p256_valid_point(key_x, key_y))
|
||||
return 0;
|
||||
|
||||
/* Check r and s are != 0 % n. */
|
||||
p256_mod(&SECP256r1_n, r, &u);
|
||||
p256_mod(&SECP256r1_n, s, &v);
|
||||
if (p256_is_zero(&u) || p256_is_zero(&v))
|
||||
return 0;
|
||||
|
||||
p256_modinv_vartime(&SECP256r1_n, s, &v);
|
||||
p256_modmul(&SECP256r1_n, digest, 0, &v, &u); /* digest / s % n */
|
||||
p256_modmul(&SECP256r1_n, r, 0, &v, &v); /* r / s % n */
|
||||
|
||||
p256_points_mul_vartime(&u, &v, key_x, key_y, &u, &v);
|
||||
|
||||
p256_mod(&SECP256r1_n, &u, &u); /* (x coord % p) % n */
|
||||
return p256_cmp(r, &u) == 0;
|
||||
}
|
||||
@@ -49,6 +49,7 @@ enum {
|
||||
EXTENSION_AES = 0,
|
||||
EXTENSION_HASH = 1,
|
||||
EXTENSION_RSA = 2,
|
||||
EXTENSION_EC = 3,
|
||||
};
|
||||
|
||||
|
||||
|
||||
169
test/tpm_test/ecc_test.py
Normal file
169
test/tpm_test/ecc_test.py
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/python
|
||||
# Copyright 2016 The Chromium OS Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style license that can be
|
||||
# found in the LICENSE file.
|
||||
|
||||
"""Module for testing ecc functions using extended commands."""
|
||||
import binascii
|
||||
import hashlib
|
||||
import os
|
||||
import struct
|
||||
|
||||
import subcmd
|
||||
import utils
|
||||
|
||||
_EC_OPCODES = {
|
||||
'SIGN': 0x00,
|
||||
'VERIFY': 0x01,
|
||||
'KEYGEN': 0x02,
|
||||
'KEYDERIVE': 0x03,
|
||||
}
|
||||
|
||||
_EC_CURVES = {
|
||||
'NIST-P256': 0x03,
|
||||
}
|
||||
|
||||
# TPM2 signature codes.
|
||||
_SIGN_MODE = {
|
||||
'NONE': 0x00,
|
||||
'ECDSA': 0x18,
|
||||
# TODO(ngm): add support for SCHNORR.
|
||||
# 'SCHNORR': 0x1c
|
||||
}
|
||||
|
||||
# TPM2 ALG codes.
|
||||
_HASH = {
|
||||
'NONE': 0x00,
|
||||
'SHA1': 0x04,
|
||||
'SHA256': 0x0B
|
||||
}
|
||||
|
||||
_HASH_FUNC = {
|
||||
'NIST-P256': hashlib.sha256
|
||||
}
|
||||
|
||||
# Command format.
|
||||
#
|
||||
# 0x00 OP
|
||||
# 0x00 CURVE_ID
|
||||
# 0x00 SIGN_MODE
|
||||
# 0x00 HASHING
|
||||
# 0x00 MSB IN LEN
|
||||
# 0x00 LSB IN LEN
|
||||
# .... IN
|
||||
# 0x00 MSB DIGEST LEN
|
||||
# 0x00 LSB DIGEST LEN
|
||||
# .... DIGEST
|
||||
#
|
||||
_EC_CMD_FORMAT = '{o:c}{c:c}{s:c}{h:c}{ml:s}{msg}{dl:s}{dig}'
|
||||
|
||||
|
||||
def _sign_cmd(curve_id, hash_func, sign_mode, msg):
|
||||
op = _EC_OPCODES['SIGN']
|
||||
digest = hash_func(msg).digest()
|
||||
digest_len = len(digest)
|
||||
return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=sign_mode, h=_HASH['NONE'],
|
||||
ml=struct.pack('>H', 0), msg='',
|
||||
dl=struct.pack('>H', digest_len), dig=digest)
|
||||
|
||||
|
||||
def _verify_cmd(curve_id, hash_func, sign_mode, msg, sig):
|
||||
op = _EC_OPCODES['VERIFY']
|
||||
sig_len = len(sig)
|
||||
digest = hash_func(msg).digest()
|
||||
digest_len = len(digest)
|
||||
return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=sign_mode, h=_HASH['NONE'],
|
||||
ml=struct.pack('>H', sig_len), msg=sig,
|
||||
dl=struct.pack('>H', digest_len), dig=digest)
|
||||
|
||||
|
||||
def _keygen_cmd(curve_id):
|
||||
op = _EC_OPCODES['KEYGEN']
|
||||
return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=_SIGN_MODE['NONE'],
|
||||
h=_HASH['NONE'], ml=struct.pack('>H', 0), msg='',
|
||||
dl=struct.pack('>H', 0), dig='')
|
||||
|
||||
|
||||
def _keyderive_cmd(curve_id, seed):
|
||||
op = _EC_OPCODES['KEYDERIVE']
|
||||
seed_len = len(seed)
|
||||
return _EC_CMD_FORMAT.format(o=op, c=curve_id, s=_SIGN_MODE['NONE'],
|
||||
h=_HASH['NONE'], ml=struct.pack('>H', seed_len),
|
||||
msg=seed, dl=struct.pack('>H', 0), dig='')
|
||||
|
||||
|
||||
_SIGN_INPUTS = (
|
||||
('NIST-P256', 'ECDSA'),
|
||||
)
|
||||
|
||||
|
||||
_KEYGEN_INPUTS = (
|
||||
('NIST-P256',),
|
||||
)
|
||||
|
||||
|
||||
_KEYDERIVE_INPUTS = (
|
||||
# Curve-id, random seed size.
|
||||
('NIST-P256', 32),
|
||||
)
|
||||
|
||||
|
||||
class ECError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _sign_test(tpm):
|
||||
msg = 'Hello CR50'
|
||||
|
||||
for data in _SIGN_INPUTS:
|
||||
curve_id, sign_mode = data
|
||||
test_name = 'EC-SIGN:%s:%s' % data
|
||||
cmd = _sign_cmd(_EC_CURVES[curve_id], _HASH_FUNC[curve_id],
|
||||
_SIGN_MODE[sign_mode], msg)
|
||||
wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
|
||||
signature = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
|
||||
|
||||
cmd = _verify_cmd(_EC_CURVES[curve_id], _HASH_FUNC[curve_id],
|
||||
_SIGN_MODE[sign_mode], msg, signature)
|
||||
wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
|
||||
verified = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
|
||||
expected = '\x01'
|
||||
if verified != expected:
|
||||
raise ECError('%s error:%s:%s' % (
|
||||
test_name, utils.hex_dump(verified), utils.hex_dump(expected)))
|
||||
print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
|
||||
|
||||
|
||||
def _keygen_test(tpm):
|
||||
for data in _KEYGEN_INPUTS:
|
||||
curve_id, = data
|
||||
test_name = 'EC-KEYGEN:%s' % data
|
||||
cmd = _keygen_cmd(_EC_CURVES[curve_id])
|
||||
wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
|
||||
valid = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
|
||||
expected = '\x01'
|
||||
if valid != expected:
|
||||
raise ECError('%s error:%s:%s' % (
|
||||
test_name, utils.hex_dump(valid), utils.hex_dump(expected)))
|
||||
print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
|
||||
|
||||
|
||||
def _keyderive_test(tpm):
|
||||
for data in _KEYDERIVE_INPUTS:
|
||||
curve_id, seed_bytes = data
|
||||
seed = os.urandom(seed_bytes)
|
||||
test_name = 'EC-KEYDERIVE:%s' % data[0]
|
||||
cmd = _keyderive_cmd(_EC_CURVES[curve_id], seed)
|
||||
wrapped_response = tpm.command(tpm.wrap_ext_command(subcmd.EC, cmd))
|
||||
valid = tpm.unwrap_ext_response(subcmd.EC, wrapped_response)
|
||||
expected = '\x01'
|
||||
if valid != expected:
|
||||
raise ECError('%s error:%s:%s' % (
|
||||
test_name, utils.hex_dump(valid), utils.hex_dump(expected)))
|
||||
print('%sSUCCESS: %s' % (utils.cursor_back(), test_name))
|
||||
|
||||
|
||||
def ecc_test(tpm):
|
||||
_sign_test(tpm)
|
||||
_keygen_test(tpm)
|
||||
_keyderive_test(tpm)
|
||||
@@ -9,3 +9,4 @@
|
||||
AES = 0
|
||||
HASH = 1
|
||||
RSA = 2
|
||||
EC = 3
|
||||
|
||||
@@ -19,6 +19,7 @@ root_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
|
||||
sys.path.append(os.path.join(root_dir, '..', '..', 'build', 'tpm_test'))
|
||||
|
||||
import crypto_test
|
||||
import ecc_test
|
||||
import ftdi_spi_tpm
|
||||
import hash_test
|
||||
import rsa_test
|
||||
@@ -135,6 +136,7 @@ if __name__ == '__main__':
|
||||
t = TPM(debug_mode=debug_needed)
|
||||
|
||||
crypto_test.crypto_tests(t, os.path.join(root_dir, 'crypto_test.xml'))
|
||||
ecc_test.ecc_test(t)
|
||||
hash_test.hash_test(t)
|
||||
rsa_test.rsa_test(t)
|
||||
except (TpmError, crypto_test.CryptoError, hash_test.HashError,
|
||||
|
||||
Reference in New Issue
Block a user