Add fixed key generation for Trust Token.

Certain applications of Trust Token need to be able to generate
a large number of keys, instead of storing them all, we provide
an API to take a secret that can be used to generate keys
in a deterministic manner.

Change-Id: I2b61958d1e949a3a47a3c91ab3a866c2e33a9d1d
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/53011
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
chromium-5359
Steven Valdez 2 years ago committed by Boringssl LUCI CQ
parent 1f51cfc7d7
commit aa5f60182e
  1. 14
      crypto/trust_token/internal.h
  2. 157
      crypto/trust_token/pmbtoken.c
  3. 40
      crypto/trust_token/trust_token.c
  4. 165
      crypto/trust_token/trust_token_test.cc
  5. 61
      crypto/trust_token/voprf.c
  6. 21
      include/openssl/trust_token.h

@ -93,6 +93,9 @@ DEFINE_STACK_OF(TRUST_TOKEN_PRETOKEN)
// functions for |TRUST_TOKENS_experiment_v1|'s PMBTokens construction which
// uses P-384.
int pmbtoken_exp1_generate_key(CBB *out_private, CBB *out_public);
int pmbtoken_exp1_derive_key_from_secret(CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len);
int pmbtoken_exp1_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len);
int pmbtoken_exp1_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
@ -118,6 +121,9 @@ OPENSSL_EXPORT int pmbtoken_exp1_get_h_for_testing(uint8_t out[97]);
// functions for |TRUST_TOKENS_experiment_v2|'s PMBTokens construction which
// uses P-384.
int pmbtoken_exp2_generate_key(CBB *out_private, CBB *out_public);
int pmbtoken_exp2_derive_key_from_secret(CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len);
int pmbtoken_exp2_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len);
int pmbtoken_exp2_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
@ -153,6 +159,8 @@ OPENSSL_EXPORT int pmbtoken_exp2_get_h_for_testing(uint8_t out[97]);
// functions for |TRUST_TOKENS_experiment_v2|'s VOPRF construction which uses
// P-384.
int voprf_exp2_generate_key(CBB *out_private, CBB *out_public);
int voprf_exp2_derive_key_from_secret(CBB *out_private, CBB *out_public,
const uint8_t *secret, size_t secret_len);
int voprf_exp2_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len);
int voprf_exp2_issuer_key_from_bytes(TRUST_TOKEN_ISSUER_KEY *key,
@ -179,6 +187,12 @@ struct trust_token_method_st {
// zero on failure.
int (*generate_key)(CBB *out_private, CBB *out_public);
// derive_key_from_secret deterministically derives a keypair based on
// |secret| and writes their serialized forms into |out_private| and
// |out_public|. It returns one on success and zero on failure.
int (*derive_key_from_secret)(CBB *out_private, CBB *out_public,
const uint8_t *secret, size_t secret_len);
// client_key_from_bytes decodes a client key from |in| and sets |key|
// to the resulting key. It returns one on success and zero
// on failure.

@ -37,6 +37,8 @@ typedef int (*hash_s_func_t)(const EC_GROUP *group, EC_RAW_POINT *out,
const uint8_t s[TRUST_TOKEN_NONCE_SIZE]);
typedef int (*hash_c_func_t)(const EC_GROUP *group, EC_SCALAR *out,
uint8_t *buf, size_t len);
typedef int (*hash_to_scalar_func_t)(const EC_GROUP *group, EC_SCALAR *out,
uint8_t *buf, size_t len);
typedef struct {
const EC_GROUP *group;
@ -52,6 +54,9 @@ typedef struct {
// hash_c implements the H_c operation in PMBTokens. It returns one on success
// and zero on error.
hash_c_func_t hash_c;
// hash_to_scalar implements the HashToScalar operation for PMBTokens. It
// returns one on success and zero on error.
hash_to_scalar_func_t hash_to_scalar;
int prefix_point : 1;
} PMBTOKEN_METHOD;
@ -60,7 +65,9 @@ static const uint8_t kDefaultAdditionalData[32] = {0};
static int pmbtoken_init_method(PMBTOKEN_METHOD *method, int curve_nid,
const uint8_t *h_bytes, size_t h_len,
hash_t_func_t hash_t, hash_s_func_t hash_s,
hash_c_func_t hash_c, int prefix_point) {
hash_c_func_t hash_c,
hash_to_scalar_func_t hash_to_scalar,
int prefix_point) {
method->group = EC_GROUP_new_by_curve_name(curve_nid);
if (method->group == NULL) {
return 0;
@ -69,6 +76,7 @@ static int pmbtoken_init_method(PMBTOKEN_METHOD *method, int curve_nid,
method->hash_t = hash_t;
method->hash_s = hash_s;
method->hash_c = hash_c;
method->hash_to_scalar = hash_to_scalar;
method->prefix_point = prefix_point;
EC_AFFINE h;
@ -85,21 +93,32 @@ static int pmbtoken_init_method(PMBTOKEN_METHOD *method, int curve_nid,
return 1;
}
// generate_keypair generates a keypair for the PMBTokens construction.
// |out_x| and |out_y| are set to the secret half of the keypair, while
// |*out_pub| is set to the public half of the keypair. It returns one on
// success and zero on failure.
static int generate_keypair(const PMBTOKEN_METHOD *method, EC_SCALAR *out_x,
EC_SCALAR *out_y, EC_RAW_POINT *out_pub) {
if (!ec_random_nonzero_scalar(method->group, out_x, kDefaultAdditionalData) ||
!ec_random_nonzero_scalar(method->group, out_y, kDefaultAdditionalData) ||
!ec_point_mul_scalar_precomp(method->group, out_pub, &method->g_precomp,
out_x, &method->h_precomp, out_y, NULL,
NULL)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, ERR_R_MALLOC_FAILURE);
return 0;
static int derive_scalar_from_secret(const PMBTOKEN_METHOD *method,
EC_SCALAR *out, const uint8_t *secret,
size_t secret_len, uint8_t scalar_id) {
static const uint8_t kKeygenLabel[] = "TrustTokenPMBTokenKeyGen";
int ok = 0;
CBB cbb;
CBB_zero(&cbb);
uint8_t *buf = NULL;
size_t len;
if (!CBB_init(&cbb, 0) ||
!CBB_add_bytes(&cbb, kKeygenLabel, sizeof(kKeygenLabel)) ||
!CBB_add_u8(&cbb, scalar_id) ||
!CBB_add_bytes(&cbb, secret, secret_len) ||
!CBB_finish(&cbb, &buf, &len) ||
!method->hash_to_scalar(method->group, out, buf, len)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
goto err;
}
return 1;
ok = 1;
err:
CBB_cleanup(&cbb);
OPENSSL_free(buf);
return ok;
}
static int point_to_cbb(CBB *out, const EC_GROUP *group,
@ -165,19 +184,24 @@ static int mul_public_3(const EC_GROUP *group, EC_RAW_POINT *out,
scalars, 3);
}
static int pmbtoken_generate_key(const PMBTOKEN_METHOD *method,
CBB *out_private, CBB *out_public) {
static int pmbtoken_compute_keys(const PMBTOKEN_METHOD *method,
CBB *out_private, CBB *out_public,
const EC_SCALAR *x0, const EC_SCALAR *y0,
const EC_SCALAR *x1, const EC_SCALAR *y1,
const EC_SCALAR *xs, const EC_SCALAR *ys) {
const EC_GROUP *group = method->group;
EC_RAW_POINT pub[3];
EC_SCALAR x0, y0, x1, y1, xs, ys;
if (!generate_keypair(method, &x0, &y0, &pub[0]) ||
!generate_keypair(method, &x1, &y1, &pub[1]) ||
!generate_keypair(method, &xs, &ys, &pub[2])) {
if (!ec_point_mul_scalar_precomp(group, &pub[0], &method->g_precomp,
x0, &method->h_precomp, y0, NULL, NULL) ||
!ec_point_mul_scalar_precomp(group, &pub[1], &method->g_precomp,
x1, &method->h_precomp, y1, NULL, NULL) ||
!ec_point_mul_scalar_precomp(method->group, &pub[2], &method->g_precomp,
xs, &method->h_precomp, ys, NULL, NULL)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
return 0;
}
const EC_SCALAR *scalars[] = {&x0, &y0, &x1, &y1, &xs, &ys};
const EC_SCALAR *scalars[] = {x0, y0, x1, y1, xs, ys};
size_t scalar_len = BN_num_bytes(&group->order);
for (size_t i = 0; i < OPENSSL_ARRAY_SIZE(scalars); i++) {
uint8_t *buf;
@ -206,6 +230,42 @@ static int pmbtoken_generate_key(const PMBTOKEN_METHOD *method,
return 1;
}
static int pmbtoken_generate_key(const PMBTOKEN_METHOD *method,
CBB *out_private, CBB *out_public) {
EC_SCALAR x0, y0, x1, y1, xs, ys;
if (!ec_random_nonzero_scalar(method->group, &x0, kDefaultAdditionalData) ||
!ec_random_nonzero_scalar(method->group, &y0, kDefaultAdditionalData) ||
!ec_random_nonzero_scalar(method->group, &x1, kDefaultAdditionalData) ||
!ec_random_nonzero_scalar(method->group, &y1, kDefaultAdditionalData) ||
!ec_random_nonzero_scalar(method->group, &xs, kDefaultAdditionalData) ||
!ec_random_nonzero_scalar(method->group, &ys, kDefaultAdditionalData)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
return 0;
}
return pmbtoken_compute_keys(method, out_private, out_public, &x0, &y0, &x1,
&y1, &xs, &ys);
}
static int pmbtoken_derive_key_from_secret(const PMBTOKEN_METHOD *method,
CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len) {
EC_SCALAR x0, y0, x1, y1, xs, ys;
if (!derive_scalar_from_secret(method, &x0, secret, secret_len, 0) ||
!derive_scalar_from_secret(method, &y0, secret, secret_len, 1) ||
!derive_scalar_from_secret(method, &x1, secret, secret_len, 2) ||
!derive_scalar_from_secret(method, &y1, secret, secret_len, 3) ||
!derive_scalar_from_secret(method, &xs, secret, secret_len, 4) ||
!derive_scalar_from_secret(method, &ys, secret, secret_len, 5)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
return 0;
}
return pmbtoken_compute_keys(method, out_private, out_public, &x0, &y0, &x1,
&y1, &xs, &ys);
}
static int pmbtoken_client_key_from_bytes(const PMBTOKEN_METHOD *method,
TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len) {
@ -1140,6 +1200,13 @@ static int pmbtoken_exp1_hash_c(const EC_GROUP *group, EC_SCALAR *out,
group, out, kHashCLabel, sizeof(kHashCLabel), buf, len);
}
static int pmbtoken_exp1_hash_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
uint8_t *buf, size_t len) {
const uint8_t kHashLabel[] = "PMBTokens Experiment V1 HashToScalar";
return ec_hash_to_scalar_p384_xmd_sha512_draft07(
group, out, kHashLabel, sizeof(kHashLabel), buf, len);
}
static int pmbtoken_exp1_ok = 0;
static PMBTOKEN_METHOD pmbtoken_exp1_method;
static CRYPTO_once_t pmbtoken_exp1_method_once = CRYPTO_ONCE_INIT;
@ -1159,10 +1226,10 @@ static void pmbtoken_exp1_init_method_impl(void) {
0x87, 0xc3, 0x95, 0xd0, 0x13, 0xb7, 0x0b, 0x5c, 0xc7,
};
pmbtoken_exp1_ok =
pmbtoken_init_method(&pmbtoken_exp1_method, NID_secp384r1, kH, sizeof(kH),
pmbtoken_exp1_hash_t, pmbtoken_exp1_hash_s,
pmbtoken_exp1_hash_c, 1);
pmbtoken_exp1_ok = pmbtoken_init_method(
&pmbtoken_exp1_method, NID_secp384r1, kH, sizeof(kH),
pmbtoken_exp1_hash_t, pmbtoken_exp1_hash_s, pmbtoken_exp1_hash_c,
pmbtoken_exp1_hash_to_scalar, 1);
}
static int pmbtoken_exp1_init_method(void) {
@ -1182,6 +1249,17 @@ int pmbtoken_exp1_generate_key(CBB *out_private, CBB *out_public) {
return pmbtoken_generate_key(&pmbtoken_exp1_method, out_private, out_public);
}
int pmbtoken_exp1_derive_key_from_secret(CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len) {
if (!pmbtoken_exp1_init_method()) {
return 0;
}
return pmbtoken_derive_key_from_secret(&pmbtoken_exp1_method, out_private,
out_public, secret, secret_len);
}
int pmbtoken_exp1_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len) {
if (!pmbtoken_exp1_init_method()) {
@ -1290,6 +1368,13 @@ static int pmbtoken_exp2_hash_c(const EC_GROUP *group, EC_SCALAR *out,
group, out, kHashCLabel, sizeof(kHashCLabel), buf, len);
}
static int pmbtoken_exp2_hash_to_scalar(const EC_GROUP *group, EC_SCALAR *out,
uint8_t *buf, size_t len) {
const uint8_t kHashLabel[] = "PMBTokens Experiment V2 HashToScalar";
return ec_hash_to_scalar_p384_xmd_sha512_draft07(
group, out, kHashLabel, sizeof(kHashLabel), buf, len);
}
static int pmbtoken_exp2_ok = 0;
static PMBTOKEN_METHOD pmbtoken_exp2_method;
static CRYPTO_once_t pmbtoken_exp2_method_once = CRYPTO_ONCE_INIT;
@ -1309,10 +1394,10 @@ static void pmbtoken_exp2_init_method_impl(void) {
0x25, 0x62, 0xbf, 0x59, 0xb2, 0xd2, 0x3d, 0x71, 0xff
};
pmbtoken_exp2_ok =
pmbtoken_init_method(&pmbtoken_exp2_method, NID_secp384r1, kH, sizeof(kH),
pmbtoken_exp2_hash_t, pmbtoken_exp2_hash_s,
pmbtoken_exp2_hash_c, 0);
pmbtoken_exp2_ok = pmbtoken_init_method(
&pmbtoken_exp2_method, NID_secp384r1, kH, sizeof(kH),
pmbtoken_exp2_hash_t, pmbtoken_exp2_hash_s, pmbtoken_exp2_hash_c,
pmbtoken_exp2_hash_to_scalar, 0);
}
static int pmbtoken_exp2_init_method(void) {
@ -1332,6 +1417,18 @@ int pmbtoken_exp2_generate_key(CBB *out_private, CBB *out_public) {
return pmbtoken_generate_key(&pmbtoken_exp2_method, out_private, out_public);
}
int pmbtoken_exp2_derive_key_from_secret(CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len) {
if (!pmbtoken_exp2_init_method()) {
return 0;
}
return pmbtoken_derive_key_from_secret(&pmbtoken_exp2_method, out_private,
out_public, secret, secret_len);
}
int pmbtoken_exp2_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len) {
if (!pmbtoken_exp2_init_method()) {

@ -30,6 +30,7 @@
const TRUST_TOKEN_METHOD *TRUST_TOKEN_experiment_v1(void) {
static const TRUST_TOKEN_METHOD kMethod = {
pmbtoken_exp1_generate_key,
pmbtoken_exp1_derive_key_from_secret,
pmbtoken_exp1_client_key_from_bytes,
pmbtoken_exp1_issuer_key_from_bytes,
pmbtoken_exp1_blind,
@ -46,6 +47,7 @@ const TRUST_TOKEN_METHOD *TRUST_TOKEN_experiment_v1(void) {
const TRUST_TOKEN_METHOD *TRUST_TOKEN_experiment_v2_voprf(void) {
static const TRUST_TOKEN_METHOD kMethod = {
voprf_exp2_generate_key,
voprf_exp2_derive_key_from_secret,
voprf_exp2_client_key_from_bytes,
voprf_exp2_issuer_key_from_bytes,
voprf_exp2_blind,
@ -62,6 +64,7 @@ const TRUST_TOKEN_METHOD *TRUST_TOKEN_experiment_v2_voprf(void) {
const TRUST_TOKEN_METHOD *TRUST_TOKEN_experiment_v2_pmb(void) {
static const TRUST_TOKEN_METHOD kMethod = {
pmbtoken_exp2_generate_key,
pmbtoken_exp2_derive_key_from_secret,
pmbtoken_exp2_client_key_from_bytes,
pmbtoken_exp2_issuer_key_from_bytes,
pmbtoken_exp2_blind,
@ -140,6 +143,43 @@ err:
return ret;
}
int TRUST_TOKEN_derive_key_from_secret(
const TRUST_TOKEN_METHOD *method, uint8_t *out_priv_key,
size_t *out_priv_key_len, size_t max_priv_key_len, uint8_t *out_pub_key,
size_t *out_pub_key_len, size_t max_pub_key_len, uint32_t id,
const uint8_t *secret, size_t secret_len) {
// Prepend the key ID in front of the PMBTokens format.
int ret = 0;
CBB priv_cbb, pub_cbb;
CBB_zero(&priv_cbb);
CBB_zero(&pub_cbb);
if (!CBB_init_fixed(&priv_cbb, out_priv_key, max_priv_key_len) ||
!CBB_init_fixed(&pub_cbb, out_pub_key, max_pub_key_len) ||
!CBB_add_u32(&priv_cbb, id) ||
!CBB_add_u32(&pub_cbb, id)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BUFFER_TOO_SMALL);
goto err;
}
if (!method->derive_key_from_secret(&priv_cbb, &pub_cbb, secret,
secret_len)) {
goto err;
}
if (!CBB_finish(&priv_cbb, NULL, out_priv_key_len) ||
!CBB_finish(&pub_cbb, NULL, out_pub_key_len)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BUFFER_TOO_SMALL);
goto err;
}
ret = 1;
err:
CBB_cleanup(&priv_cbb);
CBB_cleanup(&pub_cbb);
return ret;
}
TRUST_TOKEN_CLIENT *TRUST_TOKEN_CLIENT_new(const TRUST_TOKEN_METHOD *method,
size_t max_batchsize) {
if (max_batchsize > 0xffff) {

@ -54,6 +54,73 @@ TEST(TrustTokenTest, KeyGenExp1) {
TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0x0001));
ASSERT_EQ(292u, priv_key_len);
ASSERT_EQ(301u, pub_key_len);
const uint8_t kKeygenSecret[] = "SEED";
ASSERT_TRUE(TRUST_TOKEN_derive_key_from_secret(
TRUST_TOKEN_experiment_v1(), priv_key, &priv_key_len,
TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE, pub_key, &pub_key_len,
TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0x0001, kKeygenSecret,
sizeof(kKeygenSecret) - 1));
const uint8_t kExpectedPriv[] = {
0x00, 0x00, 0x00, 0x01, 0x98, 0xaa, 0x32, 0xfc, 0x5f, 0x83, 0x35, 0xea,
0x57, 0x4f, 0x9e, 0x61, 0x48, 0x6e, 0x89, 0x9d, 0x3d, 0xaa, 0x38, 0x5d,
0xd0, 0x06, 0x96, 0x62, 0xe8, 0x0b, 0xd6, 0x5f, 0x12, 0xa4, 0xcc, 0xa9,
0xb5, 0x20, 0x1b, 0x13, 0x8c, 0x1c, 0xaf, 0x36, 0x1b, 0xab, 0x0c, 0xc6,
0xac, 0x38, 0xae, 0x96, 0x3d, 0x14, 0x9d, 0xb8, 0x8d, 0xf4, 0x7f, 0xe2,
0x7d, 0xeb, 0x17, 0xc2, 0xbc, 0x63, 0x42, 0x93, 0x94, 0xe4, 0x97, 0xbf,
0x97, 0xea, 0x02, 0x40, 0xac, 0xb6, 0xa5, 0x03, 0x4c, 0x6b, 0x4c, 0xb8,
0x8c, 0xf4, 0x66, 0x1b, 0x4e, 0x02, 0x45, 0xf9, 0xcd, 0xb6, 0x0f, 0x59,
0x09, 0x21, 0x03, 0x7e, 0x92, 0x1f, 0x3f, 0x40, 0x83, 0x50, 0xe3, 0xdc,
0x9e, 0x6f, 0x65, 0xc5, 0xbd, 0x2c, 0x7d, 0xab, 0x74, 0x49, 0xc8, 0xa2,
0x3c, 0xab, 0xcb, 0x4d, 0x63, 0x73, 0x81, 0x2b, 0xb2, 0x1e, 0x00, 0x8f,
0x00, 0xb8, 0xd8, 0xb4, 0x5d, 0xc4, 0x3f, 0x3d, 0xa8, 0x4f, 0x4c, 0x72,
0x0e, 0x20, 0x17, 0x4b, 0xac, 0x14, 0x8f, 0xb2, 0xa5, 0x20, 0x41, 0x2b,
0xf7, 0x62, 0x25, 0x6a, 0xd6, 0x41, 0x26, 0x62, 0x10, 0xc1, 0xbc, 0x42,
0xac, 0x54, 0x1b, 0x75, 0x05, 0xd6, 0x53, 0xb1, 0x7b, 0x84, 0x6a, 0x7b,
0x5b, 0x2a, 0x34, 0x6e, 0x43, 0x4b, 0x43, 0xcc, 0x6c, 0xdb, 0x1d, 0x02,
0x34, 0x7f, 0xd1, 0xe8, 0xfd, 0x42, 0x2c, 0xd9, 0x14, 0xdb, 0xd6, 0xf4,
0xad, 0xb5, 0xe4, 0xac, 0xdd, 0x7e, 0xb5, 0x4c, 0x3f, 0x59, 0x24, 0xfa,
0x04, 0xd9, 0xb6, 0xd2, 0xb7, 0x7d, 0xf1, 0xfa, 0x13, 0xc0, 0x4d, 0xd5,
0xca, 0x3a, 0x4e, 0xa8, 0xdd, 0xa9, 0xfc, 0xcb, 0x06, 0xb2, 0xde, 0x4b,
0x2a, 0x86, 0xbb, 0x0d, 0x41, 0xb6, 0x3d, 0xfb, 0x49, 0xc8, 0xdf, 0x9a,
0x48, 0xe5, 0x68, 0x8a, 0xfc, 0x86, 0x9c, 0x79, 0x5a, 0x79, 0xc1, 0x09,
0x33, 0x53, 0xdc, 0x3d, 0xe9, 0x93, 0x7c, 0x5b, 0x72, 0xf7, 0xa0, 0x8a,
0x1f, 0x07, 0x6c, 0x38, 0x3c, 0x99, 0x0b, 0xe4, 0x4e, 0xa4, 0xbd, 0x41,
0x1f, 0x83, 0xa6, 0xd3
};
ASSERT_EQ(Bytes(kExpectedPriv, sizeof(kExpectedPriv)),
Bytes(priv_key, priv_key_len));
const uint8_t kExpectedPub[] = {
0x00, 0x00, 0x00, 0x01, 0x00, 0x61, 0x04, 0x5e, 0x06, 0x6b, 0x7b, 0xfd,
0x54, 0x01, 0xe0, 0xd2, 0xb5, 0x12, 0xce, 0x48, 0x16, 0x66, 0xb2, 0xdf,
0xfd, 0xa8, 0x38, 0x7c, 0x1f, 0x45, 0x1a, 0xb8, 0x21, 0x52, 0x17, 0x25,
0xbb, 0x0b, 0x00, 0xd4, 0xa1, 0xbc, 0x28, 0xd9, 0x08, 0x36, 0x98, 0xb2,
0x17, 0xd3, 0xb5, 0xad, 0xb6, 0x4e, 0x03, 0x5f, 0xd3, 0x66, 0x2c, 0x58,
0x1c, 0xcc, 0xc6, 0x23, 0xa4, 0xf9, 0xa2, 0x7e, 0xb0, 0xe4, 0xd3, 0x95,
0x41, 0x6f, 0xba, 0x23, 0x4a, 0x82, 0x93, 0x29, 0x73, 0x75, 0x38, 0x85,
0x64, 0x9c, 0xaa, 0x12, 0x6d, 0x7d, 0xcd, 0x52, 0x02, 0x91, 0x9f, 0xa9,
0xee, 0x4b, 0xfd, 0x68, 0x97, 0x40, 0xdc, 0x00, 0x61, 0x04, 0x14, 0x16,
0x39, 0xf9, 0x63, 0x66, 0x94, 0x03, 0xfa, 0x0b, 0xbf, 0xca, 0x5a, 0x39,
0x9f, 0x27, 0x5b, 0x3f, 0x69, 0x7a, 0xc9, 0xf7, 0x25, 0x7c, 0x84, 0x9e,
0x1d, 0x61, 0x5a, 0x24, 0x53, 0xf2, 0x4a, 0x9d, 0xe9, 0x05, 0x53, 0xfd,
0x12, 0x01, 0x2d, 0x9a, 0x69, 0x50, 0x74, 0x82, 0xa3, 0x45, 0x73, 0xdc,
0x34, 0x36, 0x31, 0x44, 0x07, 0x0c, 0xda, 0x13, 0xbe, 0x94, 0x37, 0x65,
0xa0, 0xab, 0x16, 0x52, 0x90, 0xe5, 0x8a, 0x03, 0xe5, 0x98, 0x79, 0x14,
0x79, 0xd5, 0x17, 0xee, 0xd4, 0xb8, 0xda, 0x77, 0x76, 0x03, 0x20, 0x2a,
0x7e, 0x3b, 0x76, 0x0b, 0x23, 0xb7, 0x72, 0x77, 0xb2, 0xeb, 0x00, 0x61,
0x04, 0x68, 0x18, 0x4d, 0x23, 0x23, 0xf4, 0x45, 0xb8, 0x81, 0x0d, 0xa4,
0x5d, 0x0b, 0x9e, 0x08, 0xfb, 0x45, 0xfb, 0x96, 0x29, 0x43, 0x2f, 0xab,
0x93, 0x04, 0x4c, 0x04, 0xb6, 0x5e, 0x27, 0xf5, 0x39, 0x66, 0x94, 0x15,
0x1d, 0xb1, 0x1c, 0x7c, 0x27, 0x6f, 0xa5, 0x19, 0x0c, 0x30, 0x12, 0xcc,
0x77, 0x7f, 0x10, 0xa9, 0x7c, 0xe4, 0x08, 0x77, 0x3c, 0xd3, 0x6f, 0xa4,
0xf4, 0xaf, 0xf1, 0x9d, 0x14, 0x1d, 0xd0, 0x02, 0x33, 0x50, 0x55, 0x00,
0x6a, 0x47, 0x96, 0xe1, 0x8b, 0x4e, 0x44, 0x41, 0xad, 0xb3, 0xea, 0x0d,
0x0d, 0xd5, 0x73, 0x8e, 0x62, 0x67, 0x8a, 0xb4, 0xe7, 0x5d, 0x17, 0xa9,
0x24};
ASSERT_EQ(Bytes(kExpectedPub, sizeof(kExpectedPub)),
Bytes(pub_key, pub_key_len));
}
TEST(TrustTokenTest, KeyGenExp2VOPRF) {
@ -66,6 +133,37 @@ TEST(TrustTokenTest, KeyGenExp2VOPRF) {
TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0x0001));
ASSERT_EQ(52u, priv_key_len);
ASSERT_EQ(101u, pub_key_len);
const uint8_t kKeygenSecret[] = "SEED";
ASSERT_TRUE(TRUST_TOKEN_derive_key_from_secret(
TRUST_TOKEN_experiment_v2_voprf(), priv_key, &priv_key_len,
TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE, pub_key, &pub_key_len,
TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0x0001, kKeygenSecret,
sizeof(kKeygenSecret) - 1));
const uint8_t kExpectedPriv[] = {
0x00, 0x00, 0x00, 0x01, 0x0b, 0xe2, 0xc4, 0x73, 0x92, 0xe7, 0xf8,
0x3e, 0xba, 0xab, 0x85, 0xa7, 0x77, 0xd7, 0x0a, 0x02, 0xc5, 0x36,
0xfe, 0x62, 0xa3, 0xca, 0x01, 0x75, 0xc7, 0x62, 0x19, 0xc7, 0xf0,
0x30, 0xc5, 0x14, 0x60, 0x13, 0x97, 0x4f, 0x63, 0x05, 0x37, 0x92,
0x7b, 0x76, 0x8e, 0x9f, 0xd0, 0x1a, 0x74, 0x44
};
ASSERT_EQ(Bytes(kExpectedPriv, sizeof(kExpectedPriv)),
Bytes(priv_key, priv_key_len));
const uint8_t kExpectedPub[] = {
0x00, 0x00, 0x00, 0x01, 0x04, 0x2c, 0x9c, 0x11, 0xc1, 0xe5, 0x52, 0x59,
0x0b, 0x6d, 0x88, 0x8b, 0x6e, 0x28, 0xe8, 0xc5, 0xa3, 0xbe, 0x48, 0x18,
0xf7, 0x1d, 0x31, 0xcf, 0xa2, 0x6e, 0x2a, 0xd6, 0xcb, 0x83, 0x26, 0x04,
0xbd, 0x93, 0x67, 0xe4, 0x53, 0xf6, 0x11, 0x7d, 0x45, 0xe9, 0xfe, 0x27,
0x33, 0x90, 0xdb, 0x1b, 0xfc, 0x9b, 0x31, 0x4d, 0x39, 0x1f, 0x1f, 0x8c,
0x43, 0x06, 0x70, 0x2c, 0x84, 0xdc, 0x23, 0x18, 0xc7, 0x6a, 0x58, 0xcf,
0x9e, 0xc1, 0xfa, 0xf2, 0x30, 0xdd, 0xad, 0x62, 0x24, 0xde, 0x11, 0xc1,
0xba, 0x8d, 0xc3, 0x4f, 0xfb, 0xe5, 0xa5, 0xd4, 0x37, 0xba, 0x3b, 0x70,
0xc0, 0xc3, 0xef, 0x20, 0x43
};
ASSERT_EQ(Bytes(kExpectedPub, sizeof(kExpectedPub)),
Bytes(pub_key, pub_key_len));
}
TEST(TrustTokenTest, KeyGenExp2PMB) {
@ -78,6 +176,73 @@ TEST(TrustTokenTest, KeyGenExp2PMB) {
TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0x0001));
ASSERT_EQ(292u, priv_key_len);
ASSERT_EQ(295u, pub_key_len);
const uint8_t kKeygenSecret[] = "SEED";
ASSERT_TRUE(TRUST_TOKEN_derive_key_from_secret(
TRUST_TOKEN_experiment_v2_pmb(), priv_key, &priv_key_len,
TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE, pub_key, &pub_key_len,
TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE, 0x0001, kKeygenSecret,
sizeof(kKeygenSecret) - 1));
const uint8_t kExpectedPriv[] = {
0x00, 0x00, 0x00, 0x01, 0x1b, 0x74, 0xdc, 0xf0, 0xa9, 0xa7, 0x6c, 0xfb,
0x41, 0xef, 0xfa, 0x65, 0x52, 0xc9, 0x86, 0x4e, 0xfb, 0x16, 0x9d, 0xea,
0x62, 0x3f, 0x47, 0xab, 0x1f, 0x1b, 0x05, 0xf2, 0x4f, 0x05, 0xfe, 0x64,
0xb7, 0xe8, 0xcd, 0x2a, 0x10, 0xfa, 0xa2, 0x48, 0x3f, 0x0e, 0x8b, 0x94,
0x39, 0xf1, 0xe7, 0x53, 0xe9, 0x50, 0x29, 0xe2, 0xb7, 0x0e, 0xc0, 0x94,
0xa9, 0xd3, 0xef, 0x64, 0x10, 0x1d, 0x08, 0xd0, 0x60, 0xcb, 0x6d, 0x97,
0x68, 0xc7, 0x04, 0x92, 0x07, 0xb2, 0x22, 0x83, 0xf7, 0xd9, 0x9b, 0x2c,
0xf2, 0x52, 0x34, 0x0c, 0x42, 0x31, 0x47, 0x41, 0x19, 0xb9, 0xee, 0xfc,
0x46, 0xbd, 0x14, 0xce, 0x42, 0xd7, 0x43, 0xc8, 0x32, 0x3b, 0x24, 0xed,
0xdc, 0x69, 0xa3, 0x8e, 0x29, 0x01, 0xbe, 0xae, 0x24, 0x39, 0x14, 0xa7,
0x52, 0xe5, 0xd5, 0xff, 0x9a, 0xc4, 0x15, 0x79, 0x29, 0x4c, 0x9b, 0x4e,
0xfc, 0x61, 0xf2, 0x12, 0x6f, 0x4f, 0xd3, 0x96, 0x28, 0xb0, 0x79, 0xf0,
0x4e, 0x6e, 0x7d, 0x56, 0x19, 0x1b, 0xc2, 0xd7, 0xf9, 0x3a, 0x58, 0x06,
0xe5, 0xec, 0xa4, 0x33, 0x14, 0x1c, 0x78, 0x0c, 0x83, 0x94, 0x34, 0x22,
0x5a, 0x8e, 0x2e, 0xa1, 0x72, 0x4a, 0x03, 0x35, 0xfe, 0x46, 0x92, 0x41,
0x6b, 0xe6, 0x4b, 0x3f, 0xf0, 0xe7, 0x0b, 0xb5, 0xf3, 0x66, 0x6c, 0xc6,
0x14, 0xcf, 0xce, 0x32, 0x0a, 0x2c, 0x28, 0xba, 0x4e, 0xb9, 0x75, 0x4a,
0xa9, 0x2d, 0xb0, 0x8c, 0xd0, 0x62, 0x52, 0x29, 0x1f, 0x12, 0xfd, 0xfb,
0xd3, 0x2a, 0x36, 0x0f, 0x89, 0x32, 0x86, 0x25, 0x56, 0xb9, 0xe7, 0x3c,
0xeb, 0xb4, 0x84, 0x41, 0x2b, 0xa8, 0xf3, 0xa5, 0x3d, 0xfe, 0x56, 0x94,
0x5b, 0x74, 0xb3, 0x5b, 0x27, 0x3f, 0xe7, 0xcf, 0xe4, 0xf8, 0x15, 0x95,
0x2a, 0xd2, 0x5f, 0x92, 0xb4, 0x6a, 0x89, 0xa5, 0x54, 0xbd, 0x27, 0x5e,
0xeb, 0x43, 0x07, 0x9b, 0x2b, 0x8b, 0x22, 0x59, 0x13, 0x4b, 0x9c, 0x56,
0xd8, 0x63, 0xd9, 0xe6, 0x85, 0x15, 0x2c, 0x82, 0x52, 0x40, 0x8f, 0xb1,
0xe7, 0x56, 0x07, 0x98
};
ASSERT_EQ(Bytes(kExpectedPriv, sizeof(kExpectedPriv)),
Bytes(priv_key, priv_key_len));
const uint8_t kExpectedPub[] = {
0x00, 0x00, 0x00, 0x01, 0x04, 0x48, 0xb1, 0x2d, 0xdd, 0x03, 0x32, 0xeb,
0x93, 0x31, 0x3d, 0x59, 0x74, 0xf0, 0xcf, 0xaa, 0xa5, 0x39, 0x5f, 0x53,
0xc4, 0x94, 0x98, 0xbe, 0x8f, 0x22, 0xd7, 0x30, 0xde, 0x1e, 0xb4, 0xf3,
0x32, 0x23, 0x90, 0x0b, 0xa6, 0x37, 0x4a, 0x4b, 0x44, 0xb3, 0x26, 0x52,
0x93, 0x7b, 0x4b, 0xa4, 0x79, 0xe8, 0x77, 0x6a, 0x19, 0x81, 0x2a, 0xdd,
0x91, 0xfb, 0x90, 0x8b, 0x24, 0xb5, 0xbe, 0x20, 0x2e, 0xe8, 0xbc, 0xd3,
0x83, 0x6c, 0xa8, 0xc5, 0xa1, 0x9a, 0x5b, 0x5e, 0x60, 0xda, 0x45, 0x2e,
0x31, 0x7f, 0x54, 0x0e, 0x14, 0x40, 0xd2, 0x4d, 0x40, 0x2e, 0x21, 0x79,
0xfc, 0x77, 0xdd, 0xc7, 0x2d, 0x04, 0xfe, 0xc6, 0xe3, 0xcf, 0x99, 0xef,
0x88, 0xab, 0x76, 0x86, 0x16, 0x14, 0xed, 0x72, 0x35, 0xa7, 0x05, 0x13,
0x9f, 0x2c, 0x53, 0xd5, 0xdf, 0x66, 0x75, 0x2e, 0x68, 0xdc, 0xd4, 0xc4,
0x00, 0x36, 0x08, 0x6d, 0xb7, 0x15, 0xf7, 0xe5, 0x32, 0x59, 0x81, 0x16,
0x57, 0xaa, 0x72, 0x06, 0xf0, 0xad, 0xd1, 0x85, 0xa0, 0x04, 0xd4, 0x11,
0x95, 0x1d, 0xac, 0x0b, 0x25, 0xbe, 0x59, 0xa2, 0xb3, 0x30, 0xee, 0x97,
0x07, 0x2a, 0x51, 0x15, 0xc1, 0x8d, 0xa8, 0xa6, 0x57, 0x9a, 0x4e, 0xbf,
0xd7, 0x2d, 0x35, 0x07, 0x6b, 0xd6, 0xc9, 0x3c, 0xe4, 0xcf, 0x0b, 0x14,
0x3e, 0x10, 0x51, 0x77, 0xd6, 0x84, 0x04, 0xbe, 0xd1, 0xd5, 0xa8, 0xf3,
0x9d, 0x1d, 0x4f, 0xc1, 0xc9, 0xf1, 0x0c, 0x6d, 0xb6, 0xcb, 0xe2, 0x05,
0x0b, 0x9c, 0x7a, 0x3a, 0x9a, 0x99, 0xe9, 0xa1, 0x93, 0xdc, 0x72, 0x2e,
0xef, 0xf3, 0x8d, 0xb9, 0x7b, 0xb0, 0x19, 0x24, 0x95, 0x0d, 0x68, 0xa7,
0xe0, 0xaa, 0x0b, 0xb1, 0xd1, 0xcc, 0x52, 0x14, 0xf9, 0x6c, 0x91, 0x59,
0xe4, 0xe1, 0x9b, 0xf9, 0x12, 0x39, 0xb1, 0x79, 0xbb, 0x21, 0x92, 0x00,
0xa4, 0x89, 0xf5, 0xbd, 0xd7, 0x89, 0x27, 0x40, 0xdc, 0xb1, 0x09, 0x38,
0x63, 0x91, 0x8c, 0xa5, 0x27, 0x27, 0x97, 0x39, 0x35, 0xfa, 0x1a, 0x8a,
0xa7, 0xe5, 0xc4, 0xd8, 0xbf, 0xe7, 0xbe
};
ASSERT_EQ(Bytes(kExpectedPub, sizeof(kExpectedPub)),
Bytes(pub_key, pub_key_len));
}
// Test that H in |TRUST_TOKEN_experiment_v1| was computed correctly.

@ -110,20 +110,18 @@ static int scalar_from_cbs(CBS *cbs, const EC_GROUP *group, EC_SCALAR *out) {
return 1;
}
static int voprf_generate_key(const VOPRF_METHOD *method, CBB *out_private,
CBB *out_public) {
static int voprf_calculate_key(const VOPRF_METHOD *method, CBB *out_private,
CBB *out_public, const EC_SCALAR *priv) {
const EC_GROUP *group = method->group;
EC_RAW_POINT pub;
EC_SCALAR priv;
EC_AFFINE pub_affine;
if (!ec_random_nonzero_scalar(group, &priv, kDefaultAdditionalData) ||
!ec_point_mul_scalar_base(group, &pub, &priv) ||
if (!ec_point_mul_scalar_base(group, &pub, priv) ||
!ec_jacobian_to_affine(group, &pub_affine, &pub)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
return 0;
}
if (!scalar_to_cbb(out_private, group, &priv) ||
if (!scalar_to_cbb(out_private, group, priv) ||
!cbb_add_point(out_public, group, &pub_affine)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_BUFFER_TOO_SMALL);
return 0;
@ -132,6 +130,46 @@ static int voprf_generate_key(const VOPRF_METHOD *method, CBB *out_private,
return 1;
}
static int voprf_generate_key(const VOPRF_METHOD *method, CBB *out_private,
CBB *out_public) {
EC_SCALAR priv;
if (!ec_random_nonzero_scalar(method->group, &priv, kDefaultAdditionalData)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
return 0;
}
return voprf_calculate_key(method, out_private, out_public, &priv);
}
static int voprf_derive_key_from_secret(const VOPRF_METHOD *method,
CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len) {
static const uint8_t kKeygenLabel[] = "TrustTokenVOPRFKeyGen";
EC_SCALAR priv;
int ok = 0;
CBB cbb;
CBB_zero(&cbb);
uint8_t *buf = NULL;
size_t len;
if (!CBB_init(&cbb, 0) ||
!CBB_add_bytes(&cbb, kKeygenLabel, sizeof(kKeygenLabel)) ||
!CBB_add_bytes(&cbb, secret, secret_len) ||
!CBB_finish(&cbb, &buf, &len) ||
!method->hash_to_scalar(method->group, &priv, buf, len)) {
OPENSSL_PUT_ERROR(TRUST_TOKEN, TRUST_TOKEN_R_KEYGEN_FAILURE);
goto err;
}
ok = voprf_calculate_key(method, out_private, out_public, &priv);
err:
CBB_cleanup(&cbb);
OPENSSL_free(buf);
return ok;
}
static int voprf_client_key_from_bytes(const VOPRF_METHOD *method,
TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len) {
@ -711,6 +749,17 @@ int voprf_exp2_generate_key(CBB *out_private, CBB *out_public) {
return voprf_generate_key(&voprf_exp2_method, out_private, out_public);
}
int voprf_exp2_derive_key_from_secret(CBB *out_private, CBB *out_public,
const uint8_t *secret,
size_t secret_len) {
if (!voprf_exp2_init_method()) {
return 0;
}
return voprf_derive_key_from_secret(&voprf_exp2_method, out_private,
out_public, secret, secret_len);
}
int voprf_exp2_client_key_from_bytes(TRUST_TOKEN_CLIENT_KEY *key,
const uint8_t *in, size_t len) {
if (!voprf_exp2_init_method()) {

@ -78,15 +78,30 @@ OPENSSL_EXPORT void TRUST_TOKEN_free(TRUST_TOKEN *token);
// to ensure success, these should be at least
// |TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE| and |TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE|.
//
// WARNING: This API is unstable and the serializations of these keys are
// subject to change. Keys generated with this function may not be persisted.
//
// This function returns one on success or zero on error.
OPENSSL_EXPORT int TRUST_TOKEN_generate_key(
const TRUST_TOKEN_METHOD *method, uint8_t *out_priv_key,
size_t *out_priv_key_len, size_t max_priv_key_len, uint8_t *out_pub_key,
size_t *out_pub_key_len, size_t max_pub_key_len, uint32_t id);
// TRUST_TOKEN_derive_key_from_secret deterministically derives a new Trust
// Token keypair labeled with |id| from an input |secret| and serializes the
// private and public keys, writing the private key to |out_priv_key| and
// setting |*out_priv_key_len| to the number of bytes written, and writing the
// public key to |out_pub_key| and setting |*out_pub_key_len| to the number of
// bytes written.
//
// At most |max_priv_key_len| and |max_pub_key_len| bytes are written. In order
// to ensure success, these should be at least
// |TRUST_TOKEN_MAX_PRIVATE_KEY_SIZE| and |TRUST_TOKEN_MAX_PUBLIC_KEY_SIZE|.
//
// This function returns one on success or zero on error.
OPENSSL_EXPORT int TRUST_TOKEN_derive_key_from_secret(
const TRUST_TOKEN_METHOD *method, uint8_t *out_priv_key,
size_t *out_priv_key_len, size_t max_priv_key_len, uint8_t *out_pub_key,
size_t *out_pub_key_len, size_t max_pub_key_len, uint32_t id,
const uint8_t *secret, size_t secret_len);
// Trust Token client implementation.
//

Loading…
Cancel
Save