X-Git-Url: http://www.wagner.pp.ru/gitweb/?a=blobdiff_plain;f=gost_gost2015.c;h=7d207d02a39e2e7e375acf1e954df04f1423530b;hb=39dc6de6a9474e10560ebfb0a9cecc05867b9c7b;hp=1ffa4281a234bf4fa858468ffd3aa71d78a1ae3d;hpb=97b3db1ebf985b73718faaae6c425782d526d44f;p=openssl-gost%2Fengine.git diff --git a/gost_gost2015.c b/gost_gost2015.c index 1ffa428..7d207d0 100644 --- a/gost_gost2015.c +++ b/gost_gost2015.c @@ -6,6 +6,8 @@ */ #include "gost_lcl.h" #include "gost_gost2015.h" +#include "gost_grasshopper_defines.h" +#include "gost_grasshopper_math.h" #include "e_gost_err.h" #include #include @@ -201,3 +203,288 @@ int init_zero_kdf_seed(unsigned char *kdf_seed) return is_zero_kdfseed ? RAND_bytes(kdf_seed, 8) : 1; } + +void gost_mgm128_init(mgm128_context *ctx, void *key, block128_f block, mul128_f mul_gf, int blen) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->block = block; + ctx->mul_gf = mul_gf; + ctx->key = key; + ctx->blocklen = blen; + + /* some precalculations place here + * + */ +} + +int gost_mgm128_setiv(mgm128_context *ctx, const unsigned char *iv, + size_t len) +{ + ctx->len.u[0] = 0; /* AAD length */ + ctx->len.u[1] = 0; /* message length */ + ctx->ares = 0; + ctx->mres = 0; + + ctx->ACi.u[0] = 0; + ctx->ACi.u[1] = 0; + ctx->sum.u[0] = 0; + ctx->sum.u[1] = 0; + + memcpy(ctx->nonce.c, iv, ctx->blocklen); + ctx->nonce.c[0] &= 0x7f; /* IV - random vector, but 1st bit should be 0 */ + return 1; +} + +int gost_mgm128_aad(mgm128_context *ctx, const unsigned char *aad, + size_t len) +{ + size_t i; + unsigned int n; + uint64_t alen = ctx->len.u[0]; + block128_f block = ctx->block; + mul128_f mul_gf = ctx->mul_gf; + void *key = ctx->key; + int bl = ctx->blocklen; + + if (ctx->len.u[1]) { + GOSTerr(GOST_F_GOST_MGM128_AAD, + GOST_R_BAD_ORDER); + return -2; + } + + if (alen == 0) { + ctx->nonce.c[0] |= 0x80; + (*block) (ctx->nonce.c, ctx->Zi.c, key); // Z_1 = E_K(1 || nonce) + } + + alen += len; + if (alen > ((ossl_uintmax_t)(1) << (bl * 4 - 3)) || // < 2^(n/2) (len stores in bytes) + (sizeof(len) == 8 && alen < len)) { + GOSTerr(GOST_F_GOST_MGM128_AAD, + GOST_R_DATA_TOO_LARGE); + return -1; + } + ctx->len.u[0] = alen; + + n = ctx->ares; + if (n) { + /* Finalize partial_data */ + while (n && len) { + ctx->ACi.c[n] = *(aad++); + --len; + n = (n + 1) % bl; + } + if (n == 0) { + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u); // H_i (x) A_i + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + } else { + ctx->ares = n; + return 0; + } + } + while (len >= bl) { + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, (uint64_t *)aad); // H_i (x) A_i + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + aad += bl; + len -= bl; + } + if (len) { + n = (unsigned int)len; + for (i = 0; i < len; ++i) + ctx->ACi.c[i] = aad[i]; + } + + ctx->ares = n; + return 0; +} + +int gost_mgm128_encrypt(mgm128_context *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + size_t i; + unsigned int n, mres; + uint64_t alen = ctx->len.u[0]; + uint64_t mlen = ctx->len.u[1]; + block128_f block = ctx->block; + mul128_f mul_gf = ctx->mul_gf; + void *key = ctx->key; + int bl = ctx->blocklen; + + if (mlen == 0) { + if (alen == 0) { + ctx->nonce.c[0] |= 0x80; + (*block) (ctx->nonce.c, ctx->Zi.c, key); // Z_1 = E_K(1 || nonce) + } + ctx->nonce.c[0] &= 0x7f; + (*block) (ctx->nonce.c, ctx->Yi.c, key); // Y_1 = E_K(0 || nonce) + } + + mlen += len; + + if (mlen > ((ossl_uintmax_t)(1) << (bl * 4 - 3)) || // < 2^(n/2) (len stores in bytes) + (sizeof(len) == 8 && mlen < len) || + (mlen + alen) > ((ossl_uintmax_t)(1) << (bl * 4 - 3))) { + GOSTerr(GOST_F_GOST_MGM128_ENCRYPT, + GOST_R_DATA_TOO_LARGE); + return -1; + } + ctx->len.u[1] = mlen; + + mres = ctx->mres; + + if (ctx->ares) { + /* First call to encrypt finalizes AAD */ + memset(ctx->ACi.c + ctx->ares, 0, bl - ctx->ares); + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u); // H_i (x) A_i + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + + ctx->ares = 0; + } + + n = mres % bl; + // TODO: replace with full blocks processing + for (i = 0; i < len; ++i) { + if (n == 0) { + (*block) (ctx->Yi.c, ctx->EKi.c, key); // E_K(Y_i) + inc_counter(ctx->Yi.c + bl / 2, bl / 2); // Y_i = incr_r(Y_{i-1}) + } + ctx->ACi.c[n] = out[i] = in[i] ^ ctx->EKi.c[n]; // C_i = P_i (xor) E_K(Y_i) + mres = n = (n + 1) % bl; + if (n == 0) { + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u); // H_i (x) C_i + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + } + } + + ctx->mres = mres; + return 0; +} + +int gost_mgm128_decrypt(mgm128_context *ctx, const unsigned char *in, + unsigned char *out, size_t len) +{ + size_t i; + unsigned int n, mres; + uint64_t alen = ctx->len.u[0]; + uint64_t mlen = ctx->len.u[1]; + block128_f block = ctx->block; + mul128_f mul_gf = ctx->mul_gf; + void *key = ctx->key; + int bl = ctx->blocklen; + + if (mlen == 0) { + ctx->nonce.c[0] &= 0x7f; + (*block) (ctx->nonce.c, ctx->Yi.c, key); // Y_1 = E_K(0 || nonce) + } + + mlen += len; + if (mlen > ((ossl_uintmax_t)(1) << (bl * 4 - 3)) || // < 2^(n/2) (len stores in bytes) + (sizeof(len) == 8 && mlen < len) || + (mlen + alen) > ((ossl_uintmax_t)(1) << (bl * 4 - 3))) { + GOSTerr(GOST_F_GOST_MGM128_DECRYPT, + GOST_R_DATA_TOO_LARGE); + return -1; + } + ctx->len.u[1] = mlen; + + mres = ctx->mres; + + if (ctx->ares) { + /* First call to encrypt finalizes AAD */ + memset(ctx->ACi.c + ctx->ares, 0, bl - ctx->ares); + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u); // H_i (x) A_i + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + + ctx->ares = 0; + } + + n = mres % bl; + // TODO: replace with full blocks processing + for (i = 0; i < len; ++i) { + uint8_t c; + if (n == 0) { + (*block) (ctx->Yi.c, ctx->EKi.c, key); // E_K(Y_i) + inc_counter(ctx->Yi.c + bl / 2, bl / 2); // Y_i = incr_r(Y_{i-1}) + } + ctx->ACi.c[n] = c = in[i]; + out[i] = c ^ ctx->EKi.c[n]; // P_i = C_i (xor) E_K(Y_i) + mres = n = (n + 1) % bl; + if (n == 0) { + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u); // H_i (x) C_i + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + } + } + + ctx->mres = mres; + return 0; +} + +int gost_mgm128_finish(mgm128_context *ctx, const unsigned char *tag, + size_t len) +{ + uint64_t alen = ctx->len.u[0] << 3; + uint64_t clen = ctx->len.u[1] << 3; + block128_f block = ctx->block; + mul128_f mul_gf = ctx->mul_gf; + void *key = ctx->key; + int bl = ctx->blocklen; + + if (ctx->mres || ctx->ares) { + /* First call to encrypt finalizes AAD/ENC */ + memset(ctx->ACi.c + ctx->ares + ctx->mres, 0, bl - (ctx->ares + ctx->mres)); + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->ACi.u); // H_i (x) [A_i or C_i] + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + inc_counter(ctx->Zi.c, bl / 2); // Z_{i+1} = incr_l(Z_i) + } + +#ifdef L_ENDIAN + alen = BSWAP64(alen); + clen = BSWAP64(clen); +#endif + if (bl == 16) { + ctx->len.u[0] = alen; + ctx->len.u[1] = clen; + } else { + // TODO: check for big-endian + ctx->len.u[0] = (alen >> 32) | clen; + ctx->len.u[1] = 0; + } + + (*block) (ctx->Zi.c, ctx->Hi.c, key); // H_i = E_K(Z_i) + mul_gf(ctx->mul.u, ctx->Hi.u, ctx->len.u); // H_i (x) (len(A) || len(C)) + grasshopper_plus128((grasshopper_w128_t*)ctx->sum.u, // acc XOR + (grasshopper_w128_t*)ctx->sum.u, (grasshopper_w128_t*)ctx->mul.u); + (*block) (ctx->sum.c, ctx->tag.c, key); // E_K(sum) + + if (tag && len <= sizeof(ctx->tag)) + return CRYPTO_memcmp(ctx->tag.c, tag, len); // MSB_S(E_K(sum)) + else + return -1; +} + +void gost_mgm128_tag(mgm128_context *ctx, unsigned char *tag, size_t len) +{ + gost_mgm128_finish(ctx, NULL, 0); + memcpy(tag, ctx->tag.c, + len <= sizeof(ctx->tag.c) ? len : sizeof(ctx->tag.c)); +}