#include "bee2/core/blob.h"
#include "bee2/core/err.h"
#include "bee2/core/mem.h"
#include "bee2/core/obj.h"
#include "bee2/core/util.h"
#include "bee2/crypto/bake.h"
#include "bee2/crypto/belt.h"
#include "bee2/math/gfp.h"
#include "bee2/math/ecp.h"
#include "bee2/math/ww.h"
#include "bee2/math/zz.h"
#include "crypto/bign/bign_lcl.h"
typedef struct
{
obj_hdr_t hdr;
ec_o* ec;
word* d;
word* Vct;
octet* R;
bign_params params[1];
bake_settings settings[1];
bake_cert cert[1];
octet K0[32];
octet K1[32];
octet K2[32];
octet data[];
} bake_bauth_t_o;
static size_t btokBAuthT_deep(
size_t n, size_t f_deep, size_t ec_d, size_t ec_deep);
size_t btokBAuthT_keep(size_t l)
{
const size_t n = W_OF_B(2 * l);
const size_t no = O_OF_B(2 * l);
return sizeof(bake_bauth_t_o) +
bignStart_keep(l, btokBAuthT_deep) +
3 * O_OF_W(n) + no / 2;
}
typedef struct
{
obj_hdr_t hdr;
ec_o* ec;
word* d;
word* u;
octet* V;
octet* R;
bign_params params[1];
bake_settings settings[1];
bake_cert cert[1];
octet K0[32];
octet data[];
} bake_bauth_ct_o;
static size_t btokBAuthCT_deep(
size_t n, size_t f_deep, size_t ec_d, size_t ec_deep);
size_t btokBAuthCT_keep(size_t l)
{
const size_t n = W_OF_B(2 * l);
const size_t no = O_OF_B(2 * l);
return sizeof(bake_bauth_ct_o) +
bignStart_keep(l, btokBAuthCT_deep) +
2 * O_OF_W(n) + no + no / 2;
}
err_t btokBAuthTStart(void* state, const bign_params* params,
const bake_settings* settings, const octet privkey[],
const bake_cert* cert)
{
err_t code;
bake_bauth_t_o* s = (bake_bauth_t_o*)state;
size_t n, no;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)) ||
!memIsValid(settings, sizeof(bake_settings)) ||
settings->kca != TRUE ||
!memIsNullOrValid(settings->helloa, settings->helloa_len) ||
!memIsNullOrValid(settings->hellob, settings->hellob_len))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
if (settings->rng == 0)
return ERR_BAD_RNG;
if (!memIsValid(privkey, params->l / 4) ||
!memIsValid(cert, sizeof(bake_cert)) ||
!memIsValid(cert->data, cert->len) ||
cert->val == 0)
return ERR_BAD_INPUT;
code = bignStart(s->data, params);
ERR_CALL_CHECK(code);
s->ec = (ec_o*)s->data;
n = s->ec->f->n, no = s->ec->f->no;
memCopy(s->params, params, sizeof(bign_params));
memCopy(s->settings, settings, sizeof(bake_settings));
s->d = objEnd(s->ec, word);
s->Vct = s->d + n;
s->R = (octet*)(s->Vct + 2 * n);
s->hdr.keep = sizeof(bake_bauth_t_o) + objKeep(s->ec) +
3 * O_OF_W(n) + no / 2;
s->hdr.p_count = 3;
s->hdr.o_count = 1;
wwFrom(s->d, privkey, no);
Q = objEnd(s, word);
stack = Q + 2 * n;
code = cert->val((octet*)Q, params, cert->data, cert->len);
ERR_CALL_CHECK(code);
if (!qrFrom(ecX(Q), (octet*)Q, s->ec->f, stack) ||
!qrFrom(ecY(Q, n), (octet*)Q + no, s->ec->f, stack) ||
!ecpIsOnA(Q, s->ec, stack))
return ERR_BAD_CERT;
memCopy(s->cert, cert, sizeof(bake_cert));
return code;
}
static size_t btokBAuthTStart_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(2 * n) +
utilMax(2,
f_deep,
ecpIsOnA_deep(n, f_deep));
}
err_t btokBAuthCTStart(void* state, const bign_params* params,
const bake_settings* settings, const octet privkey[],
const bake_cert* cert)
{
err_t code;
bake_bauth_ct_o* s = (bake_bauth_ct_o*)state;
size_t n, no;
word* Q;
void* stack;
if (!memIsValid(params, sizeof(bign_params)) ||
!memIsValid(settings, sizeof(bake_settings)) ||
settings->kca != TRUE ||
!memIsNullOrValid(settings->helloa, settings->helloa_len) ||
!memIsNullOrValid(settings->hellob, settings->hellob_len))
return ERR_BAD_INPUT;
if (!bignIsOperable(params))
return ERR_BAD_PARAMS;
if (settings->rng == 0)
return ERR_BAD_RNG;
if (!memIsValid(privkey, params->l / 4) ||
!memIsValid(cert, sizeof(bake_cert)) ||
!memIsValid(cert->data, cert->len) ||
cert->val == 0)
return ERR_BAD_INPUT;
code = bignStart(s->data, params);
ERR_CALL_CHECK(code);
s->ec = (ec_o*)s->data;
n = s->ec->f->n, no = s->ec->f->no;
memCopy(s->params, params, sizeof(bign_params));
memCopy(s->settings, settings, sizeof(bake_settings));
s->d = objEnd(s->ec, word);
s->u = s->d + n;
s->V = (octet*)(s->u + n);
s->R = s->V + no;
s->hdr.keep = sizeof(bake_bauth_ct_o) + objKeep(s->ec) +
3 * O_OF_W(n) + no + no / 2;
s->hdr.p_count = 4;
s->hdr.o_count = 1;
wwFrom(s->d, privkey, no);
Q = objEnd(s, word);
stack = Q + 2 * n;
code = cert->val((octet*)Q, params, cert->data, cert->len);
ERR_CALL_CHECK(code);
if (!qrFrom(ecX(Q), (octet*)Q, s->ec->f, stack) ||
!qrFrom(ecY(Q, n), (octet*)Q + no, s->ec->f, stack) ||
!ecpIsOnA(Q, s->ec, stack))
return ERR_BAD_CERT;
memCopy(s->cert, cert, sizeof(bake_cert));
return code;
}
static size_t btokBAuthCTStart_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(2 * n) +
utilMax(2,
f_deep,
ecpIsOnA_deep(n, f_deep));
}
err_t btokBAuthCTStep2(octet out[], const bake_cert* certt, void* state)
{
err_t code;
bake_bauth_ct_o* s = (bake_bauth_ct_o*)state;
size_t n, no;
octet hdr[16];
word* Vct;
word* Qt;
word* K;
void* stack;
if (!objIsOperable(s))
return ERR_BAD_INPUT;
n = s->ec->f->n, no = s->ec->f->no;
if (!memIsValid(out, 2 * no + no / 2 + 16))
return ERR_BAD_INPUT;
ASSERT(memIsDisjoint2(out, 2 * no + no / 2 + 16, s, objKeep(s)));
Vct = objEnd(s, word);
Qt = Vct + 2 * n;
K = Qt + 2 * n;
stack = K + 2 * n;
ASSERT(32 <= no);
code = certt->val((octet*)Qt, s->params, certt->data, certt->len);
ERR_CALL_CHECK(code);
if (!qrFrom(ecX(Qt), (octet*)Qt, s->ec->f, stack) ||
!qrFrom(ecY(Qt, n), (octet*)Qt + no, s->ec->f, stack) ||
!ecpIsOnA(Qt, s->ec, stack))
return ERR_BAD_CERT;
s->settings->rng(s->R, no / 2, s->settings->rng_state);
if (!zzRandNZMod(s->u, s->ec->order, n, s->settings->rng,
s->settings->rng_state))
return ERR_BAD_RNG;
if (!ecMulA(Vct, s->ec->base, s->ec, s->u, n, stack))
return ERR_BAD_PARAMS;
if (!ecMulA(K, Qt, s->ec, s->u, n, stack))
return ERR_BAD_PARAMS;
qrTo(s->V, ecX(Vct), s->ec->f, stack);
memCopy(out, s->V, no);
qrTo(out + no, ecY(Vct, n), s->ec->f, stack);
memSetZero(hdr, 16);
qrTo((octet*)K, ecX(K), s->ec->f, stack);
beltKWPWrap(out + 2 * no, s->R, no / 2, hdr, (octet*)K, 32);
return ERR_OK;
}
static size_t btokBAuthCTStep2_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(6 * n) +
utilMax(2,
f_deep,
ecMulA_deep(n, ec_d, ec_deep, n));
}
err_t btokBAuthTStep3(octet out[], const octet in[], void* state)
{
bake_bauth_t_o* s = (bake_bauth_t_o*)state;
size_t n, no;
octet hdr[16];
word* K;
octet* Rct;
octet* Y;
octet* block0;
octet* block1;
void* stack;
if (!objIsOperable(s))
return ERR_BAD_INPUT;
n = s->ec->f->n, no = s->ec->f->no;
if (!memIsValid(in, 2 * no + no / 2 + 16) ||
!memIsValid(out, (8u + s->settings->kcb) ? no / 2 : 0))
return ERR_BAD_INPUT;
ASSERT(memIsDisjoint2(out, (8u + s->settings->kcb) ?
no / 2 : 0, s, objKeep(s)));
K = objEnd(s, word);
Y = Rct = (octet*)K;
block0 = Y + 32;
block1 = block0 + 16;
stack = Y + MAX2(O_OF_W(2 * n), 32 + 16 + 16);
memCopy(s->Vct, in, 2 * no);
if (!qrFrom(ecX(s->Vct), in, s->ec->f, stack) ||
!qrFrom(ecY(s->Vct, n), in + no, s->ec->f, stack) ||
!ecpIsOnA(s->Vct, s->ec, stack))
return ERR_BAD_POINT;
if (!ecMulA(K, s->Vct, s->ec, s->d, n, stack))
return ERR_BAD_PARAMS;
memSetZero(hdr, 16);
qrTo((octet*)K, ecX(K), s->ec->f, stack);
if (beltKWPUnwrap(Rct, in + 2 * no, O_OF_B(s->params->l + 128), hdr,
(octet*)K, 32) != ERR_OK)
return ERR_AUTH;
beltHashStart(stack);
beltHashStepH(Rct, no / 2, stack);
if (s->settings->kcb)
{
s->settings->rng(s->R, 16, s->settings->rng_state);
beltHashStepH(s->R, 16, stack);
}
if (s->settings->helloa)
beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack);
if (s->settings->hellob)
beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack);
ASSERT(no >= 32);
beltHashStepG(Y, stack);
memSetZero(block0, 16);
memSet(block1, 0xFF, 16);
beltKRPStart(stack, Y, 32, block1);
beltKRPStepG(s->K0, 32, block0, stack);
if (s->settings->kcb)
{
block0[0] = 2;
beltKRPStepG(s->K2, 32, block0, stack);
}
block0[0] = 1;
beltKRPStepG(s->K1, 32, block0, stack);
block0[0] = 0;
beltMACStart(stack, s->K1, 32);
beltMACStepA(block0, 16, stack);
beltMACStepG(out, stack);
if (s->settings->kcb)
{
memCopy(out + 8, s->R, 16);
}
return ERR_OK;
}
static size_t btokBAuthTStep3_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return MAX2(O_OF_W(2 * n), 32 + 16 + 16) +
utilMax(5,
f_deep,
ecMulA_deep(n, ec_d, ec_deep, n),
beltHash_keep(),
beltKRP_keep(),
beltMAC_keep());
}
err_t btokBAuthCTStep4(octet out[], const octet in[], void* state)
{
bake_bauth_ct_o* s = (bake_bauth_ct_o*)state;
size_t n, no;
octet* Y;
octet* block0;
octet* block1;
octet* K1;
octet* K2;
word* t;
word* sct;
void* stack;
if (!objIsOperable(s))
return ERR_BAD_INPUT;
n = s->ec->f->n, no = s->ec->f->no;
if (!memIsValid(in, (8u + s->settings->kcb) ? no / 2 : 0) ||
!memIsValid(out, s->settings->kcb ? (8u + no + s->cert->len) : 0))
return ERR_BAD_INPUT;
ASSERT(memIsDisjoint2(out, s->settings->kcb ?
(8u + O_OF_B(2 * s->params->l) + s->cert->len) : 0, s, objKeep(s)));
block0 = objEnd(s, octet);
K1 = block0 + 16;
Y = K1 + 32;
t = (word*)Y;
sct = t + n / 2;
block1 = Y + 32;
K2 = (octet*)(sct + n + n / 2 + 1);
stack = K2 + 32;
beltHashStart(stack);
beltHashStepH(s->R, no / 2, stack);
if (s->settings->kcb)
beltHashStepH(in + 8, no / 2, stack);
if (s->settings->helloa)
beltHashStepH(s->settings->helloa, s->settings->helloa_len, stack);
if (s->settings->hellob)
beltHashStepH(s->settings->hellob, s->settings->hellob_len, stack);
ASSERT(no >= 32);
beltHashStepG(Y, stack);
memSetZero(block0, 16);
memSet(block1, 0xFF, 16);
beltKRPStart(stack, Y, 32, block1);
beltKRPStepG(s->K0, 32, block0, stack);
block0[0] = 1;
beltKRPStepG(K1, 32, block0, stack);
if (s->settings->kcb)
{
block0[0] = 2;
beltKRPStepG(K2, 32, block0, stack);
}
block0[0] = 0;
beltMACStart(stack, K1, 32);
beltMACStepA(block0, 16, stack);
if (!beltMACStepV(in, stack))
return ERR_AUTH;
if (s->settings->kcb)
{
beltHashStart(stack);
beltHashStepH(s->V, no, stack);
beltHashStepH(in + 8, 16, stack);
beltHashStepG2((octet*)t, no / 2, stack);
wwFrom(t, t, no / 2);
zzMul(sct, t, n / 2, s->d, n, stack);
sct[n + n / 2] = zzAdd2(sct + n / 2, s->d, n);
zzMod(sct, sct, n + n / 2 + 1, s->ec->order, n, stack);
zzSubMod(sct, s->u, sct, s->ec->order, n);
wwTo(out, no, sct);
memCopy(out + no, s->cert->data, s->cert->len);
block0[0] = 0;
beltCFBStart(stack, K2, 32, block0);
beltCFBStepE(out, no + s->cert->len, stack);
beltMACStart(stack, K1, 32);
beltMACStepA(out, no + s->cert->len, stack);
beltMACStepG(out + no + s->cert->len, stack);
}
return ERR_OK;
}
static size_t btokBAuthCTStep4_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return 16 + 32 + 32 + O_OF_W(2 * n + 1) +
utilMax(5,
f_deep,
ecMulA_deep(n, ec_d, ec_deep, n),
beltHash_keep(),
beltKRP_keep(),
beltMAC_keep());
}
err_t btokBAuthTStep5(const octet in[], size_t in_len, bake_certval_i val_ct,
void* state)
{
err_t code;
bake_bauth_t_o* s = (bake_bauth_t_o*)state;
size_t n, no;
word* Qct;
word* sct;
octet* V;
word* t;
octet* block0;
void* stack;
octet mac[8];
if (!objIsOperable(s))
return ERR_BAD_INPUT;
n = s->ec->f->n, no = s->ec->f->no;
if (!s->settings->kcb)
return ERR_BAD_LOGIC;
if (in_len < 8 + no || !memIsValid(in, in_len) || val_ct == 0)
return ERR_BAD_INPUT;
Qct = objEnd(s, word);
block0 = (octet*)Qct;
sct = Qct + 2 * n;
V = (octet*)(sct + n);
t = (word*)V;
stack = V + no;
beltMACStart(stack, s->K1, 32);
beltMACStepA(in, in_len - 8, stack);
beltMACStepG(mac, stack);
if (!beltMACStepV(in + in_len - 8, stack))
return ERR_AUTH;
in_len -= 8;
{
blob_t Zct;
if ((Zct = blobCreate(in_len)) == 0)
return ERR_OUTOFMEMORY;
memCopy(Zct, in, in_len);
memSet(block0, 0, 16);
beltCFBStart(stack, s->K2, 32, block0);
beltCFBStepD(Zct, in_len, stack);
wwFrom(sct, Zct, no);
if (wwCmp(sct, s->ec->order, n) >= 0)
{
blobClose(Zct);
return ERR_AUTH;
}
code = val_ct((octet*)Qct, s->params, (octet*)Zct + no, in_len - no);
ERR_CALL_HANDLE(code, blobClose(Zct));
if (!qrFrom(ecX(Qct), (octet*)Qct, s->ec->f, stack) ||
!qrFrom(ecY(Qct, n), (octet*)Qct + no, s->ec->f, stack) ||
!ecpIsOnA(Qct, s->ec, stack))
code = ERR_BAD_CERT;
blobClose(Zct);
ERR_CALL_CHECK(code);
}
beltHashStart(stack);
qrTo(V, ecX(s->Vct), s->ec->f, stack);
beltHashStepH(V, no, stack);
beltHashStepH(s->R, 16, stack);
beltHashStepG2((octet*)t, no / 2, stack);
wwFrom(t, t, no / 2);
t[n / 2] = 1;
if (!ecAddMulA(Qct, s->ec, stack, 2, s->ec->base, sct, n, Qct, t,
n / 2 + 1))
return ERR_BAD_PARAMS;
if (!wwEq(Qct, s->Vct, 2 * n))
return ERR_AUTH;
return ERR_OK;
}
static size_t btokBAuthTStep5_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return O_OF_W(3 * n + n / 2 + 1) +
utilMax(6,
beltHash_keep(),
beltMAC_keep(),
beltCFB_keep(),
f_deep,
ecpIsOnA_deep(n, f_deep),
ecAddMulA_deep(n, ec_d, ec_deep, 2, n, n / 2 + 1));
}
static size_t btokBAuthCT_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return utilMax(3,
btokBAuthCTStart_deep(n, f_deep, ec_d, ec_deep),
btokBAuthCTStep2_deep(n, f_deep, ec_d, ec_deep),
btokBAuthCTStep4_deep(n, f_deep, ec_d, ec_deep));
}
static size_t btokBAuthT_deep(size_t n, size_t f_deep, size_t ec_d,
size_t ec_deep)
{
return utilMax(3,
btokBAuthTStart_deep(n, f_deep, ec_d, ec_deep),
btokBAuthTStep3_deep(n, f_deep, ec_d, ec_deep),
btokBAuthTStep5_deep(n, f_deep, ec_d, ec_deep));
}
err_t btokBAuthCTStepG(octet key[32], void* state)
{
bake_bauth_ct_o* s = (bake_bauth_ct_o*)state;
if (!objIsOperable(s) ||
!memIsValid(key, 32))
return ERR_BAD_INPUT;
memCopy(key, s->K0, 32);
return ERR_OK;
}
err_t btokBAuthTStepG(octet key[32], void* state)
{
bake_bauth_t_o* s = (bake_bauth_t_o*)state;
if (!objIsOperable(s) ||
!memIsValid(key, 32))
return ERR_BAD_INPUT;
memCopy(key, s->K0, 32);
return ERR_OK;
}