Path: blob/main/contrib/bearssl/src/ec/ecdsa_i15_sign_raw.c
39488 views
/*1* Copyright (c) 2017 Thomas Pornin <[email protected]>2*3* Permission is hereby granted, free of charge, to any person obtaining4* a copy of this software and associated documentation files (the5* "Software"), to deal in the Software without restriction, including6* without limitation the rights to use, copy, modify, merge, publish,7* distribute, sublicense, and/or sell copies of the Software, and to8* permit persons to whom the Software is furnished to do so, subject to9* the following conditions:10*11* The above copyright notice and this permission notice shall be12* included in all copies or substantial portions of the Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,15* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF16* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND17* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS18* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN19* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN20* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE21* SOFTWARE.22*/2324#include "inner.h"2526#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)27#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))28#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)2930/* see bearssl_ec.h */31size_t32br_ecdsa_i15_sign_raw(const br_ec_impl *impl,33const br_hash_class *hf, const void *hash_value,34const br_ec_private_key *sk, void *sig)35{36/*37* IMPORTANT: this code is fit only for curves with a prime38* order. This is needed so that modular reduction of the X39* coordinate of a point can be done with a simple subtraction.40* We also rely on the last byte of the curve order to be distinct41* from 0 and 1.42*/43const br_ec_curve_def *cd;44uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], x[I15_LEN];45uint16_t m[I15_LEN], k[I15_LEN], t1[I15_LEN], t2[I15_LEN];46unsigned char tt[ORDER_LEN << 1];47unsigned char eU[POINT_LEN];48size_t hash_len, nlen, ulen;49uint16_t n0i;50uint32_t ctl;51br_hmac_drbg_context drbg;5253/*54* If the curve is not supported, then exit with an error.55*/56if (((impl->supported_curves >> sk->curve) & 1) == 0) {57return 0;58}5960/*61* Get the curve parameters (generator and order).62*/63switch (sk->curve) {64case BR_EC_secp256r1:65cd = &br_secp256r1;66break;67case BR_EC_secp384r1:68cd = &br_secp384r1;69break;70case BR_EC_secp521r1:71cd = &br_secp521r1;72break;73default:74return 0;75}7677/*78* Get modulus.79*/80nlen = cd->order_len;81br_i15_decode(n, cd->order, nlen);82n0i = br_i15_ninv15(n[1]);8384/*85* Get private key as an i15 integer. This also checks that the86* private key is well-defined (not zero, and less than the87* curve order).88*/89if (!br_i15_decode_mod(x, sk->x, sk->xlen, n)) {90return 0;91}92if (br_i15_iszero(x)) {93return 0;94}9596/*97* Get hash length.98*/99hash_len = (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;100101/*102* Truncate and reduce the hash value modulo the curve order.103*/104br_ecdsa_i15_bits2int(m, hash_value, hash_len, n[0]);105br_i15_sub(m, n, br_i15_sub(m, n, 0) ^ 1);106107/*108* RFC 6979 generation of the "k" value.109*110* The process uses HMAC_DRBG (with the hash function used to111* process the message that is to be signed). The seed is the112* concatenation of the encodings of the private key and113* the hash value (after truncation and modular reduction).114*/115br_i15_encode(tt, nlen, x);116br_i15_encode(tt + nlen, nlen, m);117br_hmac_drbg_init(&drbg, hf, tt, nlen << 1);118for (;;) {119br_hmac_drbg_generate(&drbg, tt, nlen);120br_ecdsa_i15_bits2int(k, tt, nlen, n[0]);121if (br_i15_iszero(k)) {122continue;123}124if (br_i15_sub(k, n, 0)) {125break;126}127}128129/*130* Compute k*G and extract the X coordinate, then reduce it131* modulo the curve order. Since we support only curves with132* prime order, that reduction is only a matter of computing133* a subtraction.134*/135br_i15_encode(tt, nlen, k);136ulen = impl->mulgen(eU, tt, nlen, sk->curve);137br_i15_zero(r, n[0]);138br_i15_decode(r, &eU[1], ulen >> 1);139r[0] = n[0];140br_i15_sub(r, n, br_i15_sub(r, n, 0) ^ 1);141142/*143* Compute 1/k in double-Montgomery representation. We do so by144* first converting _from_ Montgomery representation (twice),145* then using a modular exponentiation.146*/147br_i15_from_monty(k, n, n0i);148br_i15_from_monty(k, n, n0i);149memcpy(tt, cd->order, nlen);150tt[nlen - 1] -= 2;151br_i15_modpow(k, tt, nlen, n, n0i, t1, t2);152153/*154* Compute s = (m+xr)/k (mod n).155* The k[] array contains R^2/k (double-Montgomery representation);156* we thus can use direct Montgomery multiplications and conversions157* from Montgomery, avoiding any call to br_i15_to_monty() (which158* is slower).159*/160br_i15_from_monty(m, n, n0i);161br_i15_montymul(t1, x, r, n, n0i);162ctl = br_i15_add(t1, m, 1);163ctl |= br_i15_sub(t1, n, 0) ^ 1;164br_i15_sub(t1, n, ctl);165br_i15_montymul(s, t1, k, n, n0i);166167/*168* Encode r and s in the signature.169*/170br_i15_encode(sig, nlen, r);171br_i15_encode((unsigned char *)sig + nlen, nlen, s);172return nlen << 1;173}174175176