New "i15" implementation of big integers (faster, and constant-time, on ARM Cortex M0/M0+); imported into EC, ECDSA, RSA.

This commit is contained in:
Thomas Pornin 2017-01-04 19:21:09 +01:00
parent 6dd8c51ba7
commit 28e4e120b8
29 changed files with 2993 additions and 326 deletions

792
src/ec/ec_prime_i15.c Normal file
View file

@ -0,0 +1,792 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* Parameters for supported curves:
* - field modulus p
* - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
* - b*R mod p (b is the second curve equation parameter)
*/
static const uint16_t P256_P[] = {
0x0111,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF,
0x7FFF, 0x0001
};
static const uint16_t P256_R2[] = {
0x0111,
0x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF,
0x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF,
0x4FFF, 0x0000
};
static const uint16_t P256_B[] = {
0x0111,
0x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993,
0x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16,
0x0187, 0x0000
};
static const uint16_t P384_P[] = {
0x0199,
0x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF,
0x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x7FFF, 0x01FF
};
static const uint16_t P384_R2[] = {
0x0199,
0x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010,
0x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000,
0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000
};
static const uint16_t P384_B[] = {
0x0199,
0x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB,
0x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2,
0x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09,
0x0452, 0x0084
};
static const uint16_t P521_P[] = {
0x022B,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
0x7FFF, 0x7FFF, 0x07FF
};
static const uint16_t P521_R2[] = {
0x022B,
0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000
};
static const uint16_t P521_B[] = {
0x022B,
0x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC,
0x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F,
0x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD,
0x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4,
0x1618, 0x27D7, 0x0465
};
typedef struct {
const uint16_t *p;
const uint16_t *b;
const uint16_t *R2;
uint16_t p0i;
size_t point_len;
} curve_params;
static inline const curve_params *
id_to_curve(int curve)
{
static const curve_params pp[] = {
{ P256_P, P256_B, P256_R2, 0x0001, 65 },
{ P384_P, P384_B, P384_R2, 0x0001, 97 },
{ P521_P, P521_B, P521_R2, 0x0001, 133 }
};
return &pp[curve - BR_EC_secp256r1];
}
#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
/*
* Type for a point in Jacobian coordinates:
* -- three values, x, y and z, in Montgomery representation
* -- affine coordinates are X = x / z^2 and Y = y / z^3
* -- for the point at infinity, z = 0
*/
typedef struct {
uint16_t c[3][I15_LEN];
} jacobian;
/*
* We use a custom interpreter that uses a dozen registers, and
* only six operations:
* MSET(d, a) copy a into d
* MADD(d, a) d = d+a (modular)
* MSUB(d, a) d = d-a (modular)
* MMUL(d, a, b) d = a*b (Montgomery multiplication)
* MINV(d, a, b) invert d modulo p; a and b are used as scratch registers
* MTZ(d) clear return value if d = 0
* Destination of MMUL (d) must be distinct from operands (a and b).
* There is no such constraint for MSUB and MADD.
*
* Registers include the operand coordinates, and temporaries.
*/
#define MSET(d, a) (0x0000 + ((d) << 8) + ((a) << 4))
#define MADD(d, a) (0x1000 + ((d) << 8) + ((a) << 4))
#define MSUB(d, a) (0x2000 + ((d) << 8) + ((a) << 4))
#define MMUL(d, a, b) (0x3000 + ((d) << 8) + ((a) << 4) + (b))
#define MINV(d, a, b) (0x4000 + ((d) << 8) + ((a) << 4) + (b))
#define MTZ(d) (0x5000 + ((d) << 8))
#define ENDCODE 0
/*
* Registers for the input operands.
*/
#define P1x 0
#define P1y 1
#define P1z 2
#define P2x 3
#define P2y 4
#define P2z 5
/*
* Alternate names for the first input operand.
*/
#define Px 0
#define Py 1
#define Pz 2
/*
* Temporaries.
*/
#define t1 6
#define t2 7
#define t3 8
#define t4 9
#define t5 10
#define t6 11
#define t7 12
/*
* Extra scratch registers available when there is no second operand (e.g.
* for "double" and "affine").
*/
#define t8 3
#define t9 4
#define t10 5
/*
* Doubling formulas are:
*
* s = 4*x*y^2
* m = 3*(x + z^2)*(x - z^2)
* x' = m^2 - 2*s
* y' = m*(s - x') - 8*y^4
* z' = 2*y*z
*
* If y = 0 (P has order 2) then this yields infinity (z' = 0), as it
* should. This case should not happen anyway, because our curves have
* prime order, and thus do not contain any point of order 2.
*
* If P is infinity (z = 0), then again the formulas yield infinity,
* which is correct. Thus, this code works for all points.
*
* Cost: 8 multiplications
*/
static const uint16_t code_double[] = {
/*
* Compute z^2 (in t1).
*/
MMUL(t1, Pz, Pz),
/*
* Compute x-z^2 (in t2) and then x+z^2 (in t1).
*/
MSET(t2, Px),
MSUB(t2, t1),
MADD(t1, Px),
/*
* Compute m = 3*(x+z^2)*(x-z^2) (in t1).
*/
MMUL(t3, t1, t2),
MSET(t1, t3),
MADD(t1, t3),
MADD(t1, t3),
/*
* Compute s = 4*x*y^2 (in t2) and 2*y^2 (in t3).
*/
MMUL(t3, Py, Py),
MADD(t3, t3),
MMUL(t2, Px, t3),
MADD(t2, t2),
/*
* Compute x' = m^2 - 2*s.
*/
MMUL(Px, t1, t1),
MSUB(Px, t2),
MSUB(Px, t2),
/*
* Compute z' = 2*y*z.
*/
MMUL(t4, Py, Pz),
MSET(Pz, t4),
MADD(Pz, t4),
/*
* Compute y' = m*(s - x') - 8*y^4. Note that we already have
* 2*y^2 in t3.
*/
MSUB(t2, Px),
MMUL(Py, t1, t2),
MMUL(t4, t3, t3),
MSUB(Py, t4),
MSUB(Py, t4),
ENDCODE
};
/*
* Addtions formulas are:
*
* u1 = x1 * z2^2
* u2 = x2 * z1^2
* s1 = y1 * z2^3
* s2 = y2 * z1^3
* h = u2 - u1
* r = s2 - s1
* x3 = r^2 - h^3 - 2 * u1 * h^2
* y3 = r * (u1 * h^2 - x3) - s1 * h^3
* z3 = h * z1 * z2
*
* If both P1 and P2 are infinity, then z1 == 0 and z2 == 0, implying that
* z3 == 0, so the result is correct.
* If either of P1 or P2 is infinity, but not both, then z3 == 0, which is
* not correct.
* h == 0 only if u1 == u2; this happens in two cases:
* -- if s1 == s2 then P1 and/or P2 is infinity, or P1 == P2
* -- if s1 != s2 then P1 + P2 == infinity (but neither P1 or P2 is infinity)
*
* Thus, the following situations are not handled correctly:
* -- P1 = 0 and P2 != 0
* -- P1 != 0 and P2 = 0
* -- P1 = P2
* All other cases are properly computed. However, even in "incorrect"
* situations, the three coordinates still are properly formed field
* elements.
*
* The returned flag is cleared if r == 0. This happens in the following
* cases:
* -- Both points are on the same horizontal line (same Y coordinate).
* -- Both points are infinity.
* -- One point is infinity and the other is on line Y = 0.
* The third case cannot happen with our curves (there is no valid point
* on line Y = 0 since that would be a point of order 2). If the two
* source points are non-infinity, then remains only the case where the
* two points are on the same horizontal line.
*
* This allows us to detect the "P1 == P2" case, assuming that P1 != 0 and
* P2 != 0:
* -- If the returned value is not the point at infinity, then it was properly
* computed.
* -- Otherwise, if the returned flag is 1, then P1+P2 = 0, and the result
* is indeed the point at infinity.
* -- Otherwise (result is infinity, flag is 0), then P1 = P2 and we should
* use the 'double' code.
*
* Cost: 16 multiplications
*/
static const uint16_t code_add[] = {
/*
* Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
*/
MMUL(t3, P2z, P2z),
MMUL(t1, P1x, t3),
MMUL(t4, P2z, t3),
MMUL(t3, P1y, t4),
/*
* Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
*/
MMUL(t4, P1z, P1z),
MMUL(t2, P2x, t4),
MMUL(t5, P1z, t4),
MMUL(t4, P2y, t5),
/*
* Compute h = u2 - u1 (in t2) and r = s2 - s1 (in t4).
*/
MSUB(t2, t1),
MSUB(t4, t3),
/*
* Report cases where r = 0 through the returned flag.
*/
MTZ(t4),
/*
* Compute u1*h^2 (in t6) and h^3 (in t5).
*/
MMUL(t7, t2, t2),
MMUL(t6, t1, t7),
MMUL(t5, t7, t2),
/*
* Compute x3 = r^2 - h^3 - 2*u1*h^2.
* t1 and t7 can be used as scratch registers.
*/
MMUL(P1x, t4, t4),
MSUB(P1x, t5),
MSUB(P1x, t6),
MSUB(P1x, t6),
/*
* Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
*/
MSUB(t6, P1x),
MMUL(P1y, t4, t6),
MMUL(t1, t5, t3),
MSUB(P1y, t1),
/*
* Compute z3 = h*z1*z2.
*/
MMUL(t1, P1z, P2z),
MMUL(P1z, t1, t2),
ENDCODE
};
/*
* Check that the point is on the curve. This code snippet assumes the
* following conventions:
* -- Coordinates x and y have been freshly decoded in P1 (but not
* converted to Montgomery coordinates yet).
* -- P2x, P2y and P2z are set to, respectively, R^2, b*R and 1.
*/
static const uint16_t code_check[] = {
/* Convert x and y to Montgomery representation. */
MMUL(t1, P1x, P2x),
MMUL(t2, P1y, P2x),
MSET(P1x, t1),
MSET(P1y, t2),
/* Compute x^3 in t1. */
MMUL(t2, P1x, P1x),
MMUL(t1, P1x, t2),
/* Subtract 3*x from t1. */
MSUB(t1, P1x),
MSUB(t1, P1x),
MSUB(t1, P1x),
/* Add b. */
MADD(t1, P2y),
/* Compute y^2 in t2. */
MMUL(t2, P1y, P1y),
/* Compare y^2 with x^3 - 3*x + b; they must match. */
MSUB(t1, t2),
MTZ(t1),
/* Set z to 1 (in Montgomery representation). */
MMUL(P1z, P2x, P2z),
ENDCODE
};
/*
* Conversion back to affine coordinates. This code snippet assumes that
* the z coordinate of P2 is set to 1 (not in Montgomery representation).
*/
static const uint16_t code_affine[] = {
/* Save z*R in t1. */
MSET(t1, P1z),
/* Compute z^3 in t2. */
MMUL(t2, P1z, P1z),
MMUL(t3, P1z, t2),
MMUL(t2, t3, P2z),
/* Invert to (1/z^3) in t2. */
MINV(t2, t3, t4),
/* Compute y. */
MSET(t3, P1y),
MMUL(P1y, t2, t3),
/* Compute (1/z^2) in t3. */
MMUL(t3, t2, t1),
/* Compute x. */
MSET(t2, P1x),
MMUL(P1x, t2, t3),
ENDCODE
};
static uint32_t
run_code(jacobian *P1, const jacobian *P2,
const curve_params *cc, const uint16_t *code)
{
uint32_t r;
uint16_t t[13][I15_LEN];
size_t u;
r = 1;
/*
* Copy the two operands in the dedicated registers.
*/
memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));
memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_t));
/*
* Run formulas.
*/
for (u = 0;; u ++) {
unsigned op, d, a, b;
op = code[u];
if (op == 0) {
break;
}
d = (op >> 8) & 0x0F;
a = (op >> 4) & 0x0F;
b = op & 0x0F;
op >>= 12;
switch (op) {
uint32_t ctl;
size_t plen;
unsigned char tp[(BR_MAX_EC_SIZE + 7) >> 3];
case 0:
memcpy(t[d], t[a], I15_LEN * sizeof(uint16_t));
break;
case 1:
ctl = br_i15_add(t[d], t[a], 1);
ctl |= NOT(br_i15_sub(t[d], cc->p, 0));
br_i15_sub(t[d], cc->p, ctl);
break;
case 2:
br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1));
break;
case 3:
br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
break;
case 4:
plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
br_i15_encode(tp, plen, cc->p);
tp[plen - 1] -= 2;
br_i15_modpow(t[d], tp, plen,
cc->p, cc->p0i, t[a], t[b]);
break;
default:
r &= ~br_i15_iszero(t[d]);
break;
}
}
/*
* Copy back result.
*/
memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t));
return r;
}
static void
set_one(uint16_t *x, const uint16_t *p)
{
size_t plen;
plen = (p[0] + 31) >> 4;
memset(x, 0, plen * sizeof *x);
x[0] = p[0];
x[1] = 0x0001;
}
static void
point_zero(jacobian *P, const curve_params *cc)
{
memset(P, 0, sizeof *P);
P->c[0][0] = P->c[1][0] = P->c[2][0] = cc->p[0];
}
static inline void
point_double(jacobian *P, const curve_params *cc)
{
run_code(P, P, cc, code_double);
}
static inline uint32_t
point_add(jacobian *P1, const jacobian *P2, const curve_params *cc)
{
return run_code(P1, P2, cc, code_add);
}
static void
point_mul(jacobian *P, const unsigned char *x, size_t xlen,
const curve_params *cc)
{
/*
* We do a simple double-and-add ladder with a 2-bit window
* to make only one add every two doublings. We thus first
* precompute 2P and 3P in some local buffers.
*
* We always perform two doublings and one addition; the
* addition is with P, 2P and 3P and is done in a temporary
* array.
*
* The addition code cannot handle cases where one of the
* operands is infinity, which is the case at the start of the
* ladder. We therefore need to maintain a flag that controls
* this situation.
*/
uint32_t qz;
jacobian P2, P3, Q, T, U;
memcpy(&P2, P, sizeof P2);
point_double(&P2, cc);
memcpy(&P3, P, sizeof P3);
point_add(&P3, &P2, cc);
point_zero(&Q, cc);
qz = 1;
while (xlen -- > 0) {
int k;
for (k = 6; k >= 0; k -= 2) {
uint32_t bits;
uint32_t bnz;
point_double(&Q, cc);
point_double(&Q, cc);
memcpy(&T, P, sizeof T);
memcpy(&U, &Q, sizeof U);
bits = (*x >> k) & (uint32_t)3;
bnz = NEQ(bits, 0);
CCOPY(EQ(bits, 2), &T, &P2, sizeof T);
CCOPY(EQ(bits, 3), &T, &P3, sizeof T);
point_add(&U, &T, cc);
CCOPY(bnz & qz, &Q, &T, sizeof Q);
CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
qz &= ~bnz;
}
x ++;
}
memcpy(P, &Q, sizeof Q);
}
/*
* Decode point into Jacobian coordinates. This function does not support
* the point at infinity. If the point is invalid then this returns 0, but
* the coordinates are still set to properly formed field elements.
*/
static uint32_t
point_decode(jacobian *P, const void *src, size_t len, const curve_params *cc)
{
/*
* Points must use uncompressed format:
* -- first byte is 0x04;
* -- coordinates X and Y use unsigned big-endian, with the same
* length as the field modulus.
*
* We don't support hybrid format (uncompressed, but first byte
* has value 0x06 or 0x07, depending on the least significant bit
* of Y) because it is rather useless, and explicitly forbidden
* by PKIX (RFC 5480, section 2.2).
*
* We don't support compressed format either, because it is not
* much used in practice (there are or were patent-related
* concerns about point compression, which explains the lack of
* generalised support). Also, point compression support would
* need a bit more code.
*/
const unsigned char *buf;
size_t plen, zlen;
uint32_t r;
jacobian Q;
buf = src;
point_zero(P, cc);
plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
if (len != 1 + (plen << 1)) {
return 0;
}
r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p);
r &= br_i15_decode_mod(P->c[1], buf + 1 + plen, plen, cc->p);
/*
* Check first byte.
*/
r &= EQ(buf[0], 0x04);
/* obsolete
r &= EQ(buf[0], 0x04) | (EQ(buf[0] & 0xFE, 0x06)
& ~(uint32_t)(buf[0] ^ buf[plen << 1]));
*/
/*
* Convert coordinates and check that the point is valid.
*/
zlen = ((cc->p[0] + 31) >> 4) * sizeof(uint16_t);
memcpy(Q.c[0], cc->R2, zlen);
memcpy(Q.c[1], cc->b, zlen);
set_one(Q.c[2], cc->p);
r &= ~run_code(P, &Q, cc, code_check);
return r;
}
/*
* Encode a point. This method assumes that the point is correct and is
* not the point at infinity. Encoded size is always 1+2*plen, where
* plen is the field modulus length, in bytes.
*/
static void
point_encode(void *dst, const jacobian *P, const curve_params *cc)
{
unsigned char *buf;
size_t plen;
jacobian Q, T;
buf = dst;
plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
buf[0] = 0x04;
memcpy(&Q, P, sizeof *P);
set_one(T.c[2], cc->p);
run_code(&Q, &T, cc, code_affine);
br_i15_encode(buf + 1, plen, Q.c[0]);
br_i15_encode(buf + 1 + plen, plen, Q.c[1]);
}
static const br_ec_curve_def *
id_to_curve_def(int curve)
{
switch (curve) {
case BR_EC_secp256r1:
return &br_secp256r1;
case BR_EC_secp384r1:
return &br_secp384r1;
case BR_EC_secp521r1:
return &br_secp521r1;
}
return NULL;
}
static const unsigned char *
api_generator(int curve, size_t *len)
{
const br_ec_curve_def *cd;
cd = id_to_curve_def(curve);
*len = cd->generator_len;
return cd->generator;
}
static const unsigned char *
api_order(int curve, size_t *len)
{
const br_ec_curve_def *cd;
cd = id_to_curve_def(curve);
*len = cd->order_len;
return cd->order;
}
static uint32_t
api_mul(unsigned char *G, size_t Glen,
const unsigned char *x, size_t xlen, int curve)
{
uint32_t r;
const curve_params *cc;
jacobian P;
cc = id_to_curve(curve);
r = point_decode(&P, G, Glen, cc);
point_mul(&P, x, xlen, cc);
if (Glen == cc->point_len) {
point_encode(G, &P, cc);
}
return r;
}
static uint32_t
api_muladd(unsigned char *A, const unsigned char *B, size_t len,
const unsigned char *x, size_t xlen,
const unsigned char *y, size_t ylen, int curve)
{
uint32_t r, t, z;
const curve_params *cc;
jacobian P, Q;
/*
* TODO: see about merging the two ladders. Right now, we do
* two independant point multiplications, which is a bit
* wasteful of CPU resources (but yields short code).
*/
cc = id_to_curve(curve);
r = point_decode(&P, A, len, cc);
r &= point_decode(&Q, B, len, cc);
point_mul(&P, x, xlen, cc);
point_mul(&Q, y, ylen, cc);
/*
* We want to compute P+Q. Since the base points A and B are distinct
* from infinity, and the multipliers are non-zero and lower than the
* curve order, then we know that P and Q are non-infinity. This
* leaves two special situations to test for:
* -- If P = Q then we must use point_double().
* -- If P+Q = 0 then we must report an error.
*/
t = point_add(&P, &Q, cc);
point_double(&Q, cc);
z = br_i15_iszero(P.c[2]);
/*
* If z is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
* have the following:
*
* z = 0, t = 0 return P (normal addition)
* z = 0, t = 1 return P (normal addition)
* z = 1, t = 0 return Q (a 'double' case)
* z = 1, t = 1 report an error (P+Q = 0)
*/
CCOPY(z & ~t, &P, &Q, sizeof Q);
point_encode(A, &P, cc);
r &= ~(z & t);
return r;
}
/* see bearssl_ec.h */
const br_ec_impl br_ec_prime_i15 = {
(uint32_t)0x03800000,
&api_generator,
&api_order,
&api_mul,
&api_muladd
};

View file

@ -135,7 +135,7 @@ typedef struct {
/*
* We use a custom interpreter that uses a dozen registers, and
* only four operations:
* only six operations:
* MSET(d, a) copy a into d
* MADD(d, a) d = d+a (modular)
* MSUB(d, a) d = d-a (modular)

47
src/ec/ecdsa_i15_bits.c Normal file
View file

@ -0,0 +1,47 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see inner.h */
void
br_ecdsa_i15_bits2int(uint16_t *x,
const void *src, size_t len, uint32_t ebitlen)
{
uint32_t bitlen, hbitlen;
int sc;
bitlen = ebitlen - (ebitlen >> 4);
hbitlen = (uint32_t)len << 3;
if (hbitlen > bitlen) {
len = (bitlen + 7) >> 3;
sc = (int)((hbitlen - bitlen) & 7);
} else {
sc = 0;
}
br_i15_zero(x, ebitlen);
br_i15_decode(x, src, len);
br_i15_rshift(x, sc);
x[0] = ebitlen;
}

View file

@ -0,0 +1,45 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
/* see bearssl_ec.h */
size_t
br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig)
{
unsigned char rsig[(ORDER_LEN << 1) + 12];
size_t sig_len;
sig_len = br_ecdsa_i15_sign_raw(impl, hf, hash_value, sk, rsig);
if (sig_len == 0) {
return 0;
}
sig_len = br_ecdsa_raw_to_asn1(rsig, sig_len);
memcpy(sig, rsig, sig_len);
return sig_len;
}

184
src/ec/ecdsa_i15_sign_raw.c Normal file
View file

@ -0,0 +1,184 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
#define ORDER_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
/* see bearssl_ec.h */
size_t
br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
const br_hash_class *hf, const void *hash_value,
const br_ec_private_key *sk, void *sig)
{
/*
* IMPORTANT: this code is fit only for curves with a prime
* order. This is needed so that modular reduction of the X
* coordinate of a point can be done with a simple subtraction.
* We also rely on the last byte of the curve order to be distinct
* from 0 and 1.
*/
const br_ec_curve_def *cd;
uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], x[I15_LEN];
uint16_t m[I15_LEN], k[I15_LEN], t1[I15_LEN], t2[I15_LEN];
unsigned char tt[ORDER_LEN << 1];
unsigned char eU[POINT_LEN];
size_t hash_len, nlen, ulen;
uint16_t n0i;
uint32_t ctl;
br_hmac_drbg_context drbg;
/*
* If the curve is not supported, then exit with an error.
*/
if (((impl->supported_curves >> sk->curve) & 1) == 0) {
return 0;
}
/*
* Get the curve parameters (generator and order).
*/
switch (sk->curve) {
case BR_EC_secp256r1:
cd = &br_secp256r1;
break;
case BR_EC_secp384r1:
cd = &br_secp384r1;
break;
case BR_EC_secp521r1:
cd = &br_secp521r1;
break;
default:
return 0;
}
/*
* Get modulus.
*/
nlen = cd->order_len;
br_i15_decode(n, cd->order, nlen);
n0i = br_i15_ninv15(n[1]);
/*
* Get private key as an i15 integer. This also checks that the
* private key is well-defined (not zero, and less than the
* curve order).
*/
if (!br_i15_decode_mod(x, sk->x, sk->xlen, n)) {
return 0;
}
if (br_i15_iszero(x)) {
return 0;
}
/*
* Get hash length.
*/
hash_len = (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
/*
* Truncate and reduce the hash value modulo the curve order.
*/
br_ecdsa_i15_bits2int(m, hash_value, hash_len, n[0]);
br_i15_sub(m, n, br_i15_sub(m, n, 0) ^ 1);
/*
* RFC 6979 generation of the "k" value.
*
* The process uses HMAC_DRBG (with the hash function used to
* process the message that is to be signed). The seed is the
* concatenation of the encodings of the private key and
* the hash value (after truncation and modular reduction).
*/
br_i15_encode(tt, nlen, x);
br_i15_encode(tt + nlen, nlen, m);
br_hmac_drbg_init(&drbg, hf, tt, nlen << 1);
for (;;) {
br_hmac_drbg_generate(&drbg, tt, nlen);
br_ecdsa_i15_bits2int(k, tt, nlen, n[0]);
if (br_i15_iszero(k)) {
continue;
}
if (br_i15_sub(k, n, 0)) {
break;
}
}
/*
* Compute k*G and extract the X coordinate, then reduce it
* modulo the curve order. Since we support only curves with
* prime order, that reduction is only a matter of computing
* a subtraction.
*/
ulen = cd->generator_len;
memcpy(eU, cd->generator, ulen);
br_i15_encode(tt, nlen, k);
if (!impl->mul(eU, ulen, tt, nlen, sk->curve)) {
/*
* Point multiplication may fail here only if the
* EC implementation does not support the curve, or the
* private key is incorrect (x is a multiple of the curve
* order).
*/
return 0;
}
br_i15_zero(r, n[0]);
br_i15_decode(r, &eU[1], ulen >> 1);
r[0] = n[0];
br_i15_sub(r, n, br_i15_sub(r, n, 0) ^ 1);
/*
* Compute 1/k in double-Montgomery representation. We do so by
* first converting _from_ Montgomery representation (twice),
* then using a modular exponentiation.
*/
br_i15_from_monty(k, n, n0i);
br_i15_from_monty(k, n, n0i);
memcpy(tt, cd->order, nlen);
tt[nlen - 1] -= 2;
br_i15_modpow(k, tt, nlen, n, n0i, t1, t2);
/*
* Compute s = (m+xr)/k (mod n).
* The k[] array contains R^2/k (double-Montgomery representation);
* we thus can use direct Montgomery multiplications and conversions
* from Montgomery, avoiding any call to br_i15_to_monty() (which
* is slower).
*/
br_i15_from_monty(m, n, n0i);
br_i15_montymul(t1, x, r, n, n0i);
ctl = br_i15_add(t1, m, 1);
ctl |= br_i15_sub(t1, n, 0) ^ 1;
br_i15_sub(t1, n, ctl);
br_i15_montymul(s, t1, k, n, n0i);
/*
* Encode r and s in the signature.
*/
br_i15_encode(sig, nlen, r);
br_i15_encode((unsigned char *)sig + nlen, nlen, s);
return nlen << 1;
}

View file

@ -0,0 +1,48 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#define FIELD_LEN ((BR_MAX_EC_SIZE + 7) >> 3)
/* see bearssl_ec.h */
uint32_t
br_ecdsa_i15_vrfy_asn1(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk,
const void *sig, size_t sig_len)
{
/*
* We use a double-sized buffer because a malformed ASN.1 signature
* may trigger a size expansion when converting to "raw" format.
*/
unsigned char rsig[(FIELD_LEN << 2) + 24];
if (sig_len > ((sizeof rsig) >> 1)) {
return 0;
}
memcpy(rsig, sig, sig_len);
sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len);
return br_ecdsa_i15_vrfy_raw(impl, hash, hash_len, pk, rsig, sig_len);
}

166
src/ec/ecdsa_i15_vrfy_raw.c Normal file
View file

@ -0,0 +1,166 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
/* see bearssl_ec.h */
uint32_t
br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
const void *hash, size_t hash_len,
const br_ec_public_key *pk,
const void *sig, size_t sig_len)
{
/*
* IMPORTANT: this code is fit only for curves with a prime
* order. This is needed so that modular reduction of the X
* coordinate of a point can be done with a simple subtraction.
*/
const br_ec_curve_def *cd;
uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], t1[I15_LEN], t2[I15_LEN];
unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3];
unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3];
unsigned char eU[POINT_LEN];
size_t nlen, rlen, ulen;
uint16_t n0i;
uint32_t res;
/*
* If the curve is not supported, then report an error.
*/
if (((impl->supported_curves >> pk->curve) & 1) == 0) {
return 0;
}
/*
* Get the curve parameters (generator and order).
*/
switch (pk->curve) {
case BR_EC_secp256r1:
cd = &br_secp256r1;
break;
case BR_EC_secp384r1:
cd = &br_secp384r1;
break;
case BR_EC_secp521r1:
cd = &br_secp521r1;
break;
default:
return 0;
}
/*
* Signature length must be even.
*/
if (sig_len & 1) {
return 0;
}
rlen = sig_len >> 1;
/*
* Public key point must have the proper size for this curve.
*/
if (pk->qlen != cd->generator_len) {
return 0;
}
/*
* Get modulus; then decode the r and s values. They must be
* lower than the modulus, and s must not be null.
*/
nlen = cd->order_len;
br_i15_decode(n, cd->order, nlen);
n0i = br_i15_ninv15(n[1]);
if (!br_i15_decode_mod(r, sig, rlen, n)) {
return 0;
}
if (!br_i15_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) {
return 0;
}
if (br_i15_iszero(s)) {
return 0;
}
/*
* Invert s. We do that with a modular exponentiation; we use
* the fact that for all the curves we support, the least
* significant byte is not 0 or 1, so we can subtract 2 without
* any carry to process.
* We also want 1/s in Montgomery representation, which can be
* done by converting _from_ Montgomery representation before
* the inversion (because (1/s)*R = 1/(s/R)).
*/
br_i15_from_monty(s, n, n0i);
memcpy(tx, cd->order, nlen);
tx[nlen - 1] -= 2;
br_i15_modpow(s, tx, nlen, n, n0i, t1, t2);
/*
* Truncate the hash to the modulus length (in bits) and reduce
* it modulo the curve order. The modular reduction can be done
* with a subtraction since the truncation already reduced the
* value to the modulus bit length.
*/
br_ecdsa_i15_bits2int(t1, hash, hash_len, n[0]);
br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1);
/*
* Multiply the (truncated, reduced) hash value with 1/s, result in
* t2, encoded in ty.
*/
br_i15_montymul(t2, t1, s, n, n0i);
br_i15_encode(ty, nlen, t2);
/*
* Multiply r with 1/s, result in t1, encoded in tx.
*/
br_i15_montymul(t1, r, s, n, n0i);
br_i15_encode(tx, nlen, t1);
/*
* Compute the point x*Q + y*G.
*/
ulen = cd->generator_len;
memcpy(eU, pk->q, ulen);
res = impl->muladd(eU, cd->generator, ulen,
tx, nlen, ty, nlen, cd->curve);
/*
* Get the X coordinate, reduce modulo the curve order, and
* compare with the 'r' value.
*
* The modular reduction can be done with subtractions because
* we work with curves of prime order, so the curve order is
* close to the field order (Hasse's theorem).
*/
br_i15_zero(t1, n[0]);
br_i15_decode(t1, &eU[1], ulen >> 1);
t1[0] = n[0];
br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1);
res &= ~br_i15_sub(t1, r, 1);
res &= br_i15_iszero(t1);
return res;
}

View file

@ -532,11 +532,30 @@ MAX(uint32_t x, uint32_t y)
* (old) platforms where the default MUL31 is not. Unfortunately, it is
* also substantially slower, and yields larger code, on more modern
* platforms, which is why it is deactivated by default.
*
* MUL31_lo() must do some extra work because on some platforms, the
* _signed_ multiplication may return early if the top bits are 1.
* Simply truncating (casting) the output of MUL31() would not be
* sufficient, because the compiler may notice that we keep only the low
* word, and then replace automatically the unsigned multiplication with
* a signed multiplication opcode.
*/
#define MUL31(x, y) ((uint64_t)((x) | (uint32_t)0x80000000) \
* (uint64_t)((y) | (uint32_t)0x80000000) \
- ((uint64_t)(x) << 31) - ((uint64_t)(y) << 31) \
- ((uint64_t)1 << 62))
static inline uint32_t
MUL31_lo(uint32_t x, uint32_t y)
{
uint32_t xl, xh;
uint32_t yl, yh;
xl = (x & 0xFFFF) | (uint32_t)0x80000000;
xh = (x >> 16) | (uint32_t)0x80000000;
yl = (y & 0xFFFF) | (uint32_t)0x80000000;
yh = (y >> 16) | (uint32_t)0x80000000;
return (xl * yl + ((xl * yh + xh * yl) << 16)) & (uint32_t)0x7FFFFFFF;
}
#else
@ -544,8 +563,10 @@ MAX(uint32_t x, uint32_t y)
* Multiply two 31-bit integers, with a 62-bit result. This default
* implementation assumes that the basic multiplication operator
* yields constant-time code.
* The MUL31_lo() macro returns only the low 31 bits of the product.
*/
#define MUL31(x, y) ((uint64_t)(x) * (uint64_t)(y))
#define MUL31(x, y) ((uint64_t)(x) * (uint64_t)(y))
#define MUL31_lo(x, y) (((uint32_t)(x) * (uint32_t)(y)) & (uint32_t)0x7FFFFFFF)
#endif
@ -558,7 +579,7 @@ MAX(uint32_t x, uint32_t y)
*/
#if BR_CT_MUL15
#define MUL15(x, y) (((uint32_t)(x) | (uint32_t)0x80000000) \
* ((uint32_t)(x) | (uint32_t)0x80000000) \
* ((uint32_t)(y) | (uint32_t)0x80000000) \
& (uint32_t)0x3FFFFFFF)
#else
#define MUL15(x, y) ((uint32_t)(x) * (uint32_t)(y))
@ -1046,6 +1067,53 @@ void br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b);
/* ==================================================================== */
static inline void
br_i15_zero(uint16_t *x, uint16_t bit_len)
{
*x ++ = bit_len;
memset(x, 0, ((bit_len + 15) >> 4) * sizeof *x);
}
uint32_t br_i15_iszero(const uint16_t *x);
uint16_t br_i15_ninv15(uint16_t x);
uint32_t br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl);
uint32_t br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl);
void br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m);
void br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y,
const uint16_t *m, uint16_t m0i);
void br_i15_to_monty(uint16_t *x, const uint16_t *m);
void br_i15_modpow(uint16_t *x, const unsigned char *e, size_t elen,
const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2);
void br_i15_encode(void *dst, size_t len, const uint16_t *x);
uint32_t br_i15_decode_mod(uint16_t *x,
const void *src, size_t len, const uint16_t *m);
void br_i15_rshift(uint16_t *x, int count);
uint32_t br_i15_bit_length(uint16_t *x, size_t xlen);
void br_i15_decode(uint16_t *x, const void *src, size_t len);
void br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i);
void br_i15_decode_reduce(uint16_t *x,
const void *src, size_t len, const uint16_t *m);
void br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m);
void br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b);
/* ==================================================================== */
static inline size_t
br_digest_size(const br_hash_class *digest_class)
{
@ -1343,6 +1411,29 @@ unsigned br_aes_ct64_keysched(uint64_t *comp_skey,
void br_aes_ct64_skey_expand(uint64_t *skey,
unsigned num_rounds, const uint64_t *comp_skey);
/* ==================================================================== */
/*
* RSA.
*/
/*
* Apply proper PKCS#1 v1.5 padding (for signatures). 'hash_oid' is
* the encoded hash function OID, or NULL.
*/
uint32_t br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid,
const unsigned char *hash, size_t hash_len,
uint32_t n_bitlen, unsigned char *x);
/*
* Check PKCS#1 v1.5 padding (for signatures). 'hash_oid' is the encoded
* hash function OID, or NULL. The provided 'sig' value is _after_ the
* modular exponentiation, i.e. it should be the padded hash. On
* success, the hashed message is extracted.
*/
uint32_t br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len,
const unsigned char *hash_oid, size_t hash_len,
unsigned char *hash_out);
/* ==================================================================== */
/*
* Elliptic curves.
@ -1364,6 +1455,8 @@ extern const br_ec_curve_def br_secp256r1;
extern const br_ec_curve_def br_secp384r1;
extern const br_ec_curve_def br_secp521r1;
#if 0
/* obsolete */
/*
* Type for the parameters for a "prime curve":
* coordinates are in GF(p), with p prime
@ -1383,6 +1476,7 @@ extern const br_ec_prime_i31_curve br_ec_prime_i31_secp384r1;
extern const br_ec_prime_i31_curve br_ec_prime_i31_secp521r1;
#define BR_EC_I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
#endif
/*
* Decode some bytes as an i31 integer, with truncation (corresponding
@ -1394,6 +1488,16 @@ extern const br_ec_prime_i31_curve br_ec_prime_i31_secp521r1;
void br_ecdsa_i31_bits2int(uint32_t *x,
const void *src, size_t len, uint32_t ebitlen);
/*
* Decode some bytes as an i15 integer, with truncation (corresponding
* to the 'bits2int' operation in RFC 6979). The target ENCODED bit
* length is provided as last parameter. The resulting value will have
* this declared bit length, and consists the big-endian unsigned decoding
* of exactly that many bits in the source (capped at the source length).
*/
void br_ecdsa_i15_bits2int(uint16_t *x,
const void *src, size_t len, uint32_t ebitlen);
/* ==================================================================== */
/*
* SSL/TLS support functions.

479
src/int/i15_core.c Normal file
View file

@ -0,0 +1,479 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* This file contains the core "big integer" functions for the i15
* implementation, that represents integers as sequences of 15-bit
* words.
*/
/* see inner.h */
uint32_t
br_i15_iszero(const uint16_t *x)
{
uint32_t z;
size_t u;
z = 0;
for (u = (x[0] + 15) >> 4; u > 0; u --) {
z |= x[u];
}
return ~(z | -z) >> 31;
}
/* see inner.h */
uint16_t
br_i15_ninv15(uint16_t x)
{
uint32_t y;
y = 2 - x;
y = MUL15(y, 2 - MUL15(x, y));
y = MUL15(y, 2 - MUL15(x, y));
y = MUL15(y, 2 - MUL15(x, y));
return MUX(x & 1, -y, 0) & 0x7FFF;
}
/* see inner.h */
uint32_t
br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl)
{
uint32_t cc;
size_t u, m;
cc = 0;
m = (a[0] + 31) >> 4;
for (u = 1; u < m; u ++) {
uint32_t aw, bw, naw;
aw = a[u];
bw = b[u];
naw = aw + bw + cc;
cc = naw >> 15;
a[u] = MUX(ctl, naw & 0x7FFF, aw);
}
return cc;
}
/* see inner.h */
uint32_t
br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl)
{
uint32_t cc;
size_t u, m;
cc = 0;
m = (a[0] + 31) >> 4;
for (u = 1; u < m; u ++) {
uint32_t aw, bw, naw;
aw = a[u];
bw = b[u];
naw = aw - bw - cc;
cc = naw >> 31;
a[u] = MUX(ctl, naw & 0x7FFF, aw);
}
return cc;
}
/*
* Constant-time division. The divisor must not be larger than 16 bits,
* and the quotient must fit on 17 bits.
*/
static uint32_t
divrem16(uint32_t x, uint32_t d, uint32_t *r)
{
int i;
uint32_t q;
q = 0;
d <<= 16;
for (i = 16; i >= 0; i --) {
uint32_t ctl;
ctl = LE(d, x);
q |= ctl << i;
x -= (-ctl) & d;
d >>= 1;
}
if (r != NULL) {
*r = x;
}
return q;
}
/* see inner.h */
void
br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m)
{
/*
* Constant-time: we accept to leak the exact bit length of the
* modulus m.
*/
unsigned m_bitlen, mblr;
size_t u, mlen;
uint32_t hi, a0, a, b, q;
uint32_t cc, tb, over, under;
/*
* Simple case: the modulus fits on one word.
*/
m_bitlen = m[0];
if (m_bitlen == 0) {
return;
}
if (m_bitlen <= 15) {
uint32_t rem;
divrem16(((uint32_t)x[1] << 15) | z, m[1], &rem);
x[1] = rem;
return;
}
mlen = (m_bitlen + 15) >> 4;
mblr = m_bitlen & 15;
/*
* Principle: we estimate the quotient (x*2^15+z)/m by
* doing a 30/15 division with the high words.
*
* Let:
* w = 2^15
* a = (w*a0 + a1) * w^N + a2
* b = b0 * w^N + b2
* such that:
* 0 <= a0 < w
* 0 <= a1 < w
* 0 <= a2 < w^N
* w/2 <= b0 < w
* 0 <= b2 < w^N
* a < w*b
* I.e. the two top words of a are a0:a1, the top word of b is
* b0, we ensured that b0 is "full" (high bit set), and a is
* such that the quotient q = a/b fits on one word (0 <= q < w).
*
* If a = b*q + r (with 0 <= r < q), then we can estimate q by
* using a division on the top words:
* a0*w + a1 = b0*u + v (with 0 <= v < b0)
* Then the following holds:
* 0 <= u <= w
* u-2 <= q <= u
*/
hi = x[mlen];
if (mblr == 0) {
a0 = x[mlen];
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
x[1] = z;
a = (a0 << 15) + x[mlen];
b = m[mlen];
} else {
a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr);
memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
x[1] = z;
a = (a0 << 15) | (((x[mlen] << (15 - mblr))
| (x[mlen - 1] >> mblr)) & 0x7FFF);
b = (m[mlen] << (15 - mblr)) | (m[mlen - 1] >> mblr);
}
q = divrem16(a, b, NULL);
/*
* We computed an estimate for q, but the real one may be q,
* q-1 or q-2; moreover, the division may have returned a value
* 8000 or even 8001 if the two high words were identical, and
* we want to avoid values beyond 7FFF. We thus adjust q so
* that the "true" multiplier will be q+1, q or q-1, and q is
* in the 0000..7FFF range.
*/
q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31));
/*
* We subtract q*m from x (x has an extra high word of value 'hi').
* Since q may be off by 1 (in either direction), we may have to
* add or subtract m afterwards.
*
* The 'tb' flag will be true (1) at the end of the loop if the
* result is greater than or equal to the modulus (not counting
* 'hi' or the carry).
*/
cc = 0;
tb = 1;
for (u = 1; u <= mlen; u ++) {
uint32_t mw, zl, xw, nxw;
mw = m[u];
zl = MUL15(mw, q) + cc;
cc = zl >> 15;
zl &= 0x7FFF;
xw = x[u];
nxw = xw - zl;
cc += nxw >> 31;
nxw &= 0x7FFF;
x[u] = nxw;
tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
}
/*
* If we underestimated q, then either cc < hi (one extra bit
* beyond the top array word), or cc == hi and tb is true (no
* extra bit, but the result is not lower than the modulus).
*
* If we overestimated q, then cc > hi.
*/
over = GT(cc, hi);
under = ~over & (tb | LT(cc, hi));
br_i15_add(x, m, over);
br_i15_sub(x, m, under);
}
/* see inner.h */
void
br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y,
const uint16_t *m, uint16_t m0i)
{
size_t len, len4, u, v;
uint32_t dh;
len = (m[0] + 15) >> 4;
len4 = len & ~(size_t)3;
br_i15_zero(d, m[0]);
dh = 0;
for (u = 0; u < len; u ++) {
uint32_t f, xu, r, zh;
xu = x[u + 1];
f = MUL15(d[1] + MUL15(x[u + 1], y[1]), m0i) & 0x7FFF;
r = 0;
for (v = 0; v < len4; v += 4) {
uint32_t z;
z = d[v + 1] + MUL15(xu, y[v + 1])
+ MUL15(f, m[v + 1]) + r;
r = z >> 15;
d[v + 0] = z & 0x7FFF;
z = d[v + 2] + MUL15(xu, y[v + 2])
+ MUL15(f, m[v + 2]) + r;
r = z >> 15;
d[v + 1] = z & 0x7FFF;
z = d[v + 3] + MUL15(xu, y[v + 3])
+ MUL15(f, m[v + 3]) + r;
r = z >> 15;
d[v + 2] = z & 0x7FFF;
z = d[v + 4] + MUL15(xu, y[v + 4])
+ MUL15(f, m[v + 4]) + r;
r = z >> 15;
d[v + 3] = z & 0x7FFF;
}
for (; v < len; v ++) {
uint32_t z;
z = d[v + 1] + MUL15(xu, y[v + 1])
+ MUL15(f, m[v + 1]) + r;
r = z >> 15;
d[v + 0] = z & 0x7FFF;
}
zh = dh + r;
d[len] = zh & 0x7FFF;
dh = zh >> 31;
}
/*
* Restore the bit length (it was overwritten in the loop above).
*/
d[0] = m[0];
/*
* d[] may be greater than m[], but it is still lower than twice
* the modulus.
*/
br_i15_sub(d, m, NEQ(dh, 0) | NOT(br_i15_sub(d, m, 0)));
}
/* see inner.h */
void
br_i15_to_monty(uint16_t *x, const uint16_t *m)
{
unsigned k;
for (k = (m[0] + 15) >> 4; k > 0; k --) {
br_i15_muladd_small(x, 0, m);
}
}
/* see inner.h */
void
br_i15_modpow(uint16_t *x,
const unsigned char *e, size_t elen,
const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2)
{
size_t mlen;
unsigned k;
mlen = ((m[0] + 31) >> 4) * sizeof m[0];
memcpy(t1, x, mlen);
br_i15_to_monty(t1, m);
br_i15_zero(x, m[0]);
x[1] = 1;
for (k = 0; k < ((unsigned)elen << 3); k ++) {
uint32_t ctl;
ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
br_i15_montymul(t2, x, t1, m, m0i);
CCOPY(ctl, x, t2, mlen);
br_i15_montymul(t2, t1, t1, m, m0i);
memcpy(t1, t2, mlen);
}
}
/* see inner.h */
void
br_i15_encode(void *dst, size_t len, const uint16_t *x)
{
unsigned char *buf;
size_t u, xlen;
uint32_t acc;
int acc_len;
xlen = (x[0] + 15) >> 4;
if (xlen == 0) {
memset(dst, 0, len);
return;
}
u = 1;
acc = 0;
acc_len = 0;
buf = dst;
while (len -- > 0) {
if (acc_len < 8) {
if (u <= xlen) {
acc += (uint32_t)x[u ++] << acc_len;
}
acc_len += 15;
}
buf[len] = (unsigned char)acc;
acc >>= 8;
acc_len -= 8;
}
}
/* see inner.h */
uint32_t
br_i15_decode_mod(uint16_t *x, const void *src, size_t len, const uint16_t *m)
{
/*
* Two-pass algorithm: in the first pass, we determine whether the
* value fits; in the second pass, we do the actual write.
*
* During the first pass, 'r' contains the comparison result so
* far:
* 0x00000000 value is equal to the modulus
* 0x00000001 value is greater than the modulus
* 0xFFFFFFFF value is lower than the modulus
*
* Since we iterate starting with the least significant bytes (at
* the end of src[]), each new comparison overrides the previous
* except when the comparison yields 0 (equal).
*
* During the second pass, 'r' is either 0xFFFFFFFF (value fits)
* or 0x00000000 (value does not fit).
*
* We must iterate over all bytes of the source, _and_ possibly
* some extra virutal bytes (with value 0) so as to cover the
* complete modulus as well. We also add 4 such extra bytes beyond
* the modulus length because it then guarantees that no accumulated
* partial word remains to be processed.
*/
const unsigned char *buf;
size_t mlen, tlen;
int pass;
uint32_t r;
buf = src;
mlen = (m[0] + 15) >> 4;
tlen = (mlen << 1);
if (tlen < len) {
tlen = len;
}
tlen += 4;
r = 0;
for (pass = 0; pass < 2; pass ++) {
size_t u, v;
uint32_t acc;
int acc_len;
v = 1;
acc = 0;
acc_len = 0;
for (u = 0; u < tlen; u ++) {
uint32_t b;
if (u < len) {
b = buf[len - 1 - u];
} else {
b = 0;
}
acc |= (b << acc_len);
acc_len += 8;
if (acc_len >= 15) {
uint32_t xw;
xw = acc & (uint32_t)0x7FFF;
acc_len -= 15;
acc = b >> (8 - acc_len);
if (v <= mlen) {
if (pass) {
x[v] = r & xw;
} else {
uint32_t cc;
cc = (uint32_t)CMP(xw, m[v]);
r = MUX(EQ(cc, 0), r, cc);
}
} else {
if (!pass) {
r = MUX(EQ(xw, 0), r, 1);
}
}
v ++;
}
}
/*
* When we reach this point at the end of the first pass:
* r is either 0, 1 or -1; we want to set r to 0 if it
* is equal to 0 or 1, and leave it to -1 otherwise.
*
* When we reach this point at the end of the second pass:
* r is either 0 or -1; we want to leave that value
* untouched. This is a subcase of the previous.
*/
r >>= 1;
r |= (r << 1);
}
x[0] = m[0];
return r & (uint32_t)1;
}

136
src/int/i15_ext1.c Normal file
View file

@ -0,0 +1,136 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* This file contains some additional functions for "i15" big integers.
* These functions are needed to support ECDSA.
*/
/* see inner.h */
void
br_i15_rshift(uint16_t *x, int count)
{
size_t u, len;
unsigned r;
len = (x[0] + 15) >> 4;
if (len == 0) {
return;
}
r = x[1] >> count;
for (u = 2; u <= len; u ++) {
unsigned w;
w = x[u];
x[u - 1] = ((w << (15 - count)) | r) & 0x7FFF;
r = w >> count;
}
x[len] = r;
}
/* see inner.h */
uint32_t
br_i15_bit_length(uint16_t *x, size_t xlen)
{
uint32_t tw, twk;
tw = 0;
twk = 0;
while (xlen -- > 0) {
uint32_t w, c;
c = EQ(tw, 0);
w = x[xlen];
tw = MUX(c, w, tw);
twk = MUX(c, (uint32_t)xlen, twk);
}
return (twk << 4) + BIT_LENGTH(tw);
}
/* see inner.h */
void
br_i15_decode(uint16_t *x, const void *src, size_t len)
{
const unsigned char *buf;
size_t v;
uint32_t acc;
int acc_len;
buf = src;
v = 1;
acc = 0;
acc_len = 0;
while (len -- > 0) {
uint32_t b;
b = buf[len];
acc |= (b << acc_len);
acc_len += 8;
if (acc_len >= 15) {
x[v ++] = acc & 0x7FFF;
acc_len -= 15;
acc >>= 15;
}
}
if (acc_len != 0) {
x[v ++] = acc;
}
x[0] = br_i15_bit_length(x + 1, v - 1);
}
/* see inner.h */
void
br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i)
{
size_t len, u, v;
len = (m[0] + 15) >> 4;
for (u = 0; u < len; u ++) {
uint32_t f, cc;
f = MUL15(x[1], m0i) & 0x7FFF;
cc = 0;
for (v = 0; v < len; v ++) {
uint32_t z;
z = (uint32_t)x[v + 1] + MUL15(f, m[v + 1]) + cc;
cc = z >> 15;
if (v != 0) {
x[v] = z & 0x7FFF;
}
}
x[len] = cc;
}
/*
* We may have to do an extra subtraction, but only if the
* value in x[] is indeed greater than or equal to that of m[],
* which is why we must do two calls (first call computes the
* carry, second call performs the subtraction only if the carry
* is 0).
*/
br_i15_sub(x, m, NOT(br_i15_sub(x, m, 0)));
}

173
src/int/i15_ext2.c Normal file
View file

@ -0,0 +1,173 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/*
* This file contains some additional functions for "i15" big integers.
* These functions are needed to support RSA.
*/
/* see inner.h */
void
br_i15_decode_reduce(uint16_t *x,
const void *src, size_t len, const uint16_t *m)
{
uint32_t m_ebitlen, m_rbitlen;
size_t mblen, k;
const unsigned char *buf;
uint32_t acc;
int acc_len;
/*
* Get the encoded bit length.
*/
m_ebitlen = m[0];
/*
* Special case for an invalid (null) modulus.
*/
if (m_ebitlen == 0) {
x[0] = 0;
return;
}
/*
* Clear the destination.
*/
br_i15_zero(x, m_ebitlen);
/*
* First decode directly as many bytes as possible. This requires
* computing the actual bit length.
*/
m_rbitlen = m_ebitlen >> 4;
m_rbitlen = (m_ebitlen & 15) + (m_rbitlen << 4) - m_rbitlen;
mblen = (m_rbitlen + 7) >> 3;
k = mblen - 1;
if (k >= len) {
br_i15_decode(x, src, len);
x[0] = m_ebitlen;
return;
}
buf = src;
br_i15_decode(x, buf, k);
x[0] = m_ebitlen;
/*
* Input remaining bytes, using 15-bit words.
*/
acc = 0;
acc_len = 0;
while (k < len) {
uint32_t v;
v = buf[k ++];
acc = (acc << 8) | v;
acc_len += 8;
if (acc_len >= 15) {
br_i15_muladd_small(x, acc >> (acc_len - 15), m);
acc_len -= 15;
acc &= ~((uint32_t)-1 << acc_len);
}
}
/*
* We may have some bits accumulated. We then perform a shift to
* be able to inject these bits as a full 15-bit word.
*/
if (acc_len != 0) {
acc = (acc | (x[1] << acc_len)) & 0x7FFF;
br_i15_rshift(x, 15 - acc_len);
br_i15_muladd_small(x, acc, m);
}
}
/* see inner.h */
void
br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m)
{
uint32_t m_bitlen, a_bitlen;
size_t mlen, alen, u;
m_bitlen = m[0];
mlen = (m_bitlen + 15) >> 4;
x[0] = m_bitlen;
if (m_bitlen == 0) {
return;
}
/*
* If the source is shorter, then simply copy all words from a[]
* and zero out the upper words.
*/
a_bitlen = a[0];
alen = (a_bitlen + 15) >> 4;
if (a_bitlen < m_bitlen) {
memcpy(x + 1, a + 1, alen * sizeof *a);
for (u = alen; u < mlen; u ++) {
x[u + 1] = 0;
}
return;
}
/*
* The source length is at least equal to that of the modulus.
* We must thus copy N-1 words, and input the remaining words
* one by one.
*/
memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
x[mlen] = 0;
for (u = 1 + alen - mlen; u > 0; u --) {
br_i15_muladd_small(x, a[u], m);
}
}
/* see inner.h */
void
br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b)
{
size_t alen, blen, u;
alen = (a[0] + 15) >> 4;
blen = (b[0] + 15) >> 4;
d[0] = a[0] + b[0];
for (u = 0; u < blen; u ++) {
uint32_t f;
size_t v;
uint32_t cc;
f = b[1 + u];
cc = 0;
for (v = 0; v < alen; v ++) {
uint32_t z;
z = (uint32_t)d[1 + u + v] + MUL15(f, a[1 + v]) + cc;
cc = z >> 15;
d[1 + u + v] = z & 0x7FFF;
}
d[1 + u + alen] = cc;
}
}

View file

@ -35,7 +35,7 @@ br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i)
uint32_t f;
uint64_t cc;
f = (x[1] * m0i) & 0x7FFFFFFF;
f = MUL31_lo(x[1], m0i);
cc = 0;
for (v = 0; v < len; v ++) {
uint64_t z;

View file

@ -41,7 +41,7 @@ br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
uint64_t r, zh;
xu = x[u + 1];
f = ((d[1] + x[u + 1] * y[1]) * m0i) & 0x7FFFFFFF;
f = MUL31_lo((d[1] + MUL31_lo(x[u + 1], y[1])), m0i);
r = 0;
for (v = 0; v < len4; v += 4) {

View file

@ -75,7 +75,7 @@ br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
*
* If a = b*q + r (with 0 <= r < q), we can estimate q by
* doing an Euclidean division on the top words:
* a0*w+a1 = b0*u + v (with 0 <= v < w)
* a0*w+a1 = b0*u + v (with 0 <= v < b0)
* Then the following holds:
* 0 <= u <= w
* u-2 <= q <= u

View file

@ -0,0 +1,37 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see bearssl_rsa.h */
uint32_t
br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid,
const unsigned char *hash, size_t hash_len,
const br_rsa_private_key *sk, unsigned char *x)
{
if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
return 0;
}
return br_rsa_i15_private(x, sk);
}

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see bearssl_rsa.h */
uint32_t
br_rsa_i15_pkcs1_vrfy(const unsigned char *x, size_t xlen,
const unsigned char *hash_oid, size_t hash_len,
const br_rsa_public_key *pk, unsigned char *hash_out)
{
unsigned char sig[BR_MAX_RSA_SIZE >> 3];
if (xlen > (sizeof sig)) {
return 0;
}
memcpy(sig, x, xlen);
if (!br_rsa_i15_public(sig, xlen, pk)) {
return 0;
}
return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
}

146
src/rsa/rsa_i15_priv.c Normal file
View file

@ -0,0 +1,146 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
#define U (1 + ((BR_MAX_RSA_FACTOR + 14) / 15))
/* see bearssl_rsa.h */
uint32_t
br_rsa_i15_private(unsigned char *x, const br_rsa_private_key *sk)
{
const unsigned char *p, *q;
size_t plen, qlen;
uint16_t tmp[6 * U];
uint16_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
uint16_t p0i, q0i;
size_t xlen;
/*
* All our temporary buffers are from the tmp[] array.
*
* The mp, mq, s1, s2, t1 and t2 buffers are large enough to
* contain a RSA factor. The t3 buffer can contain a complete
* RSA modulus. t3 shares its storage space with s2, s1 and t1,
* in that order (this is important, see below).
*/
mq = tmp;
mp = tmp + U;
t2 = tmp + 2 * U;
s2 = tmp + 3 * U;
s1 = tmp + 4 * U;
t1 = tmp + 5 * U;
t3 = s2;
/*
* Compute the actual lengths (in bytes) of p and q, and check
* that they fit within our stack buffers.
*/
p = sk->p;
plen = sk->plen;
while (plen > 0 && *p == 0) {
p ++;
plen --;
}
q = sk->q;
qlen = sk->qlen;
while (qlen > 0 && *q == 0) {
q ++;
qlen --;
}
if (plen > (BR_MAX_RSA_FACTOR >> 3)
|| qlen > (BR_MAX_RSA_FACTOR >> 3))
{
return 0;
}
/*
* Decode p and q.
*/
br_i15_decode(mp, p, plen);
br_i15_decode(mq, q, qlen);
/*
* Compute signature length (in bytes).
*/
xlen = (sk->n_bitlen + 7) >> 3;
/*
* Compute s1 = x^dp mod p.
*/
p0i = br_i15_ninv15(mp[1]);
br_i15_decode_reduce(s1, x, xlen, mp);
br_i15_modpow(s1, sk->dp, sk->dplen, mp, p0i, t1, t2);
/*
* Compute s2 = x^dq mod q.
*/
q0i = br_i15_ninv15(mq[1]);
br_i15_decode_reduce(s2, x, xlen, mq);
br_i15_modpow(s2, sk->dq, sk->dqlen, mq, q0i, t1, t2);
/*
* Compute:
* h = (s1 - s2)*(1/q) mod p
* s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
* unclear about whether p may be lower than q (some existing,
* widely deployed implementations of RSA don't tolerate p < q),
* but we want to support that occurrence, so we need to use the
* reduction function.
*
* Since we use br_i15_decode_reduce() for iq (purportedly, the
* inverse of q modulo p), we also tolerate improperly large
* values for this parameter.
*/
br_i15_reduce(t2, s2, mp);
br_i15_add(s1, mp, br_i15_sub(s1, t2, 1));
br_i15_to_monty(s1, mp);
br_i15_decode_reduce(t1, sk->iq, sk->iqlen, mp);
br_i15_montymul(t2, s1, t1, mp, p0i);
/*
* h is now in t2. We compute the final result:
* s = s2 + q*h
* All these operations are non-modular.
*
* We need mq, s2 and t2. We use the t3 buffer as destination.
* The buffers mp, s1 and t1 are no longer needed. Moreover,
* the first step is to copy s2 into the destination buffer t3.
* We thus arranged for t3 to actually share space with s2, and
* to be followed by the space formerly used by s1 and t1.
*/
br_i15_mulacc(t3, mq, t2);
/*
* Encode the result. Since we already checked the value of xlen,
* we can just use it right away.
*/
br_i15_encode(x, xlen, t3);
/*
* The only error conditions remaining at that point are invalid
* values for p and q (even integers).
*/
return p0i & q0i & 1;
}

78
src/rsa/rsa_i15_pub.c Normal file
View file

@ -0,0 +1,78 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see bearssl_rsa.h */
uint32_t
br_rsa_i15_public(unsigned char *x, size_t xlen,
const br_rsa_public_key *pk)
{
const unsigned char *n;
size_t nlen;
uint16_t m[1 + ((BR_MAX_RSA_SIZE + 14) / 15)];
uint16_t a[1 + ((BR_MAX_RSA_SIZE + 14) / 15)];
uint16_t t1[1 + ((BR_MAX_RSA_SIZE + 14) / 15)];
uint16_t t2[1 + ((BR_MAX_RSA_SIZE + 14) / 15)];
uint16_t m0i;
uint32_t r;
/*
* Get the actual length of the modulus, and see if it fits within
* our stack buffer. We also check that the length of x[] is valid.
*/
n = pk->n;
nlen = pk->nlen;
while (nlen > 0 && *n == 0) {
n ++;
nlen --;
}
if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
return 0;
}
br_i15_decode(m, n, nlen);
m0i = br_i15_ninv15(m[1]);
/*
* Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
* an odd integer.
*/
r = m0i & 1;
/*
* Decode x[] into a[]; we also check that its value is proper.
*/
r &= br_i15_decode_mod(a, x, xlen, m);
/*
* Compute the modular exponentiation.
*/
br_i15_modpow(a, pk->e, pk->elen, m, m0i, t1, t2);
/*
* Encode the result.
*/
br_i15_encode(x, xlen, a);
return r;
}

View file

@ -30,75 +30,8 @@ br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid,
const unsigned char *hash, size_t hash_len,
const br_rsa_private_key *sk, unsigned char *x)
{
size_t u, x3, xlen;
/*
* Padded hash value has format:
* 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
*
* with the following rules:
*
* -- Total length is equal to the modulus length (unsigned
* encoding).
*
* -- There must be at least eight bytes of value 0xFF.
*
* -- x4 is equal to the hash length (hash_len).
*
* -- x3 is equal to the encoded OID value length (hash_oid[0]).
*
* -- x2 = x3 + 4.
*
* -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
*
* Note: the "05 00" is optional (signatures with and without
* that sequence exist in practice), but notes in PKCS#1 seem to
* indicate that the presence of that sequence (specifically,
* an ASN.1 NULL value for the hash parameters) may be slightly
* more "standard" than the opposite.
*/
xlen = (sk->n_bitlen + 7) >> 3;
if (hash_oid == NULL) {
if (xlen < hash_len + 11) {
return 0;
}
x[0] = 0x00;
x[1] = 0x01;
u = xlen - hash_len;
memset(x + 2, 0xFF, u - 3);
x[u - 1] = 0x00;
} else {
x3 = hash_oid[0];
/*
* Check that there is enough room for all the elements,
* including at least eight bytes of value 0xFF.
*/
if (xlen < (x3 + hash_len + 21)) {
return 0;
}
x[0] = 0x00;
x[1] = 0x01;
u = xlen - x3 - hash_len - 11;
memset(x + 2, 0xFF, u - 2);
x[u] = 0x00;
x[u + 1] = 0x30;
x[u + 2] = x3 + hash_len + 8;
x[u + 3] = 0x30;
x[u + 4] = x3 + 4;
x[u + 5] = 0x06;
memcpy(x + u + 6, hash_oid, x3 + 1);
u += x3 + 7;
x[u ++] = 0x05;
x[u ++] = 0x00;
x[u ++] = 0x04;
x[u ++] = hash_len;
if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
return 0;
}
memcpy(x + u, hash, hash_len);
/*
* Do the actual computation.
*/
return br_rsa_i31_private(x, sk);
}

View file

@ -30,97 +30,14 @@ br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen,
const unsigned char *hash_oid, size_t hash_len,
const br_rsa_public_key *pk, unsigned char *hash_out)
{
static const unsigned char pad1[] = {
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char sig[BR_MAX_RSA_SIZE >> 3];
unsigned char pad2[43];
size_t u, x2, x3, pad_len, zlen;
if (xlen > (sizeof sig) || xlen < 11) {
if (xlen > (sizeof sig)) {
return 0;
}
memcpy(sig, x, xlen);
if (!br_rsa_i31_public(sig, xlen, pk)) {
return 0;
}
/*
* Expected format:
* 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH
*
* with the following rules:
*
* -- Total length is that of the modulus and the signature
* (this was already verified by br_rsa_i31_public()).
*
* -- There are at least eight bytes of value 0xFF.
*
* -- x4 is equal to the hash length (hash_len).
*
* -- x3 is equal to the encoded OID value length (so x3 is the
* first byte of hash_oid[]).
*
* -- If the "05 00" is present, then x2 == x3 + 4; otherwise,
* x2 == x3 + 2.
*
* -- x1 == x2 + x4 + 4.
*
* So the total length after the last "FF" is either x3 + x4 + 11
* (with the "05 00") or x3 + x4 + 9 (without the "05 00").
*/
/*
* Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes.
* The comparaison is valid because we made sure that the signature
* is at least 11 bytes long.
*/
if (memcmp(sig, pad1, sizeof pad1) != 0) {
return 0;
}
for (u = sizeof pad1; u < xlen; u ++) {
if (sig[u] != 0xFF) {
break;
}
}
/*
* Remaining length is xlen - u bytes (including the 00 just
* after the last FF). This must be equal to one of the two
* possible values (depending on whether the "05 00" sequence is
* present or not).
*/
if (hash_oid == NULL) {
if (xlen - u != hash_len + 1 || sig[u] != 0x00) {
return 0;
}
} else {
x3 = hash_oid[0];
pad_len = x3 + 9;
memset(pad2, 0, pad_len);
zlen = xlen - u - hash_len;
if (zlen == pad_len) {
x2 = x3 + 2;
} else if (zlen == pad_len + 2) {
x2 = x3 + 4;
pad_len = zlen;
pad2[pad_len - 4] = 0x05;
} else {
return 0;
}
pad2[1] = 0x30;
pad2[2] = x2 + hash_len + 4;
pad2[3] = 0x30;
pad2[4] = x2;
pad2[5] = 0x06;
memcpy(pad2 + 6, hash_oid, x3 + 1);
pad2[pad_len - 2] = 0x04;
pad2[pad_len - 1] = hash_len;
if (memcmp(pad2, sig + u, pad_len) != 0) {
return 0;
}
}
memcpy(hash_out, sig + xlen - hash_len, hash_len);
return 1;
return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
}

View file

@ -30,75 +30,8 @@ br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid,
const unsigned char *hash, size_t hash_len,
const br_rsa_private_key *sk, unsigned char *x)
{
size_t u, x3, xlen;
/*
* Padded hash value has format:
* 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
*
* with the following rules:
*
* -- Total length is equal to the modulus length (unsigned
* encoding).
*
* -- There must be at least eight bytes of value 0xFF.
*
* -- x4 is equal to the hash length (hash_len).
*
* -- x3 is equal to the encoded OID value length (hash_oid[0]).
*
* -- x2 = x3 + 4.
*
* -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
*
* Note: the "05 00" is optional (signatures with and without
* that sequence exist in practice), but notes in PKCS#1 seem to
* indicate that the presence of that sequence (specifically,
* an ASN.1 NULL value for the hash parameters) may be slightly
* more "standard" than the opposite.
*/
xlen = (sk->n_bitlen + 7) >> 3;
if (hash_oid == NULL) {
if (xlen < hash_len + 11) {
return 0;
}
x[0] = 0x00;
x[1] = 0x01;
u = xlen - hash_len;
memset(x + 2, 0xFF, u - 3);
x[u - 1] = 0x00;
} else {
x3 = hash_oid[0];
/*
* Check that there is enough room for all the elements,
* including at least eight bytes of value 0xFF.
*/
if (xlen < (x3 + hash_len + 21)) {
return 0;
}
x[0] = 0x00;
x[1] = 0x01;
u = xlen - x3 - hash_len - 11;
memset(x + 2, 0xFF, u - 2);
x[u] = 0x00;
x[u + 1] = 0x30;
x[u + 2] = x3 + hash_len + 8;
x[u + 3] = 0x30;
x[u + 4] = x3 + 4;
x[u + 5] = 0x06;
memcpy(x + u + 6, hash_oid, x3 + 1);
u += x3 + 7;
x[u ++] = 0x05;
x[u ++] = 0x00;
x[u ++] = 0x04;
x[u ++] = hash_len;
if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
return 0;
}
memcpy(x + u, hash, hash_len);
/*
* Do the actual computation.
*/
return br_rsa_i32_private(x, sk);
}

View file

@ -30,97 +30,14 @@ br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen,
const unsigned char *hash_oid, size_t hash_len,
const br_rsa_public_key *pk, unsigned char *hash_out)
{
static const unsigned char pad1[] = {
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char sig[BR_MAX_RSA_SIZE >> 3];
unsigned char pad2[43];
size_t u, x2, x3, pad_len, zlen;
if (xlen > (sizeof sig) || xlen < 11) {
if (xlen > (sizeof sig)) {
return 0;
}
memcpy(sig, x, xlen);
if (!br_rsa_i32_public(sig, xlen, pk)) {
return 0;
}
/*
* Expected format:
* 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH
*
* with the following rules:
*
* -- Total length is that of the modulus and the signature
* (this was already verified by br_rsa_i32_public()).
*
* -- There are at least eight bytes of value 0xFF.
*
* -- x4 is equal to the hash length (hash_len).
*
* -- x3 is equal to the encoded OID value length (so x3 is the
* first byte of hash_oid[]).
*
* -- If the "05 00" is present, then x2 == x3 + 4; otherwise,
* x2 == x3 + 2.
*
* -- x1 == x2 + x4 + 4.
*
* So the total length after the last "FF" is either x3 + x4 + 11
* (with the "05 00") or x3 + x4 + 9 (without the "05 00").
*/
/*
* Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes.
* The comparaison is valid because we made sure that the signature
* is at least 11 bytes long.
*/
if (memcmp(sig, pad1, sizeof pad1) != 0) {
return 0;
}
for (u = sizeof pad1; u < xlen; u ++) {
if (sig[u] != 0xFF) {
break;
}
}
/*
* Remaining length is xlen - u bytes (including the 00 just
* after the last FF). This must be equal to one of the two
* possible values (depending on whether the "05 00" sequence is
* present or not).
*/
if (hash_oid == NULL) {
if (xlen - u != hash_len + 1 || sig[u] != 0x00) {
return 0;
}
} else {
x3 = hash_oid[0];
pad_len = x3 + 9;
memset(pad2, 0, pad_len);
zlen = xlen - u - hash_len;
if (zlen == pad_len) {
x2 = x3 + 2;
} else if (zlen == pad_len + 2) {
x2 = x3 + 4;
pad_len = zlen;
pad2[pad_len - 4] = 0x05;
} else {
return 0;
}
pad2[1] = 0x30;
pad2[2] = x2 + hash_len + 4;
pad2[3] = 0x30;
pad2[4] = x2;
pad2[5] = 0x06;
memcpy(pad2 + 6, hash_oid, x3 + 1);
pad2[pad_len - 2] = 0x04;
pad2[pad_len - 1] = hash_len;
if (memcmp(pad2, sig + u, pad_len) != 0) {
return 0;
}
}
memcpy(hash_out, sig + xlen - hash_len, hash_len);
return 1;
return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
}

100
src/rsa/rsa_pkcs1_sig_pad.c Normal file
View file

@ -0,0 +1,100 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see inner.h */
uint32_t
br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid,
const unsigned char *hash, size_t hash_len,
uint32_t n_bitlen, unsigned char *x)
{
size_t u, x3, xlen;
/*
* Padded hash value has format:
* 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
*
* with the following rules:
*
* -- Total length is equal to the modulus length (unsigned
* encoding).
*
* -- There must be at least eight bytes of value 0xFF.
*
* -- x4 is equal to the hash length (hash_len).
*
* -- x3 is equal to the encoded OID value length (hash_oid[0]).
*
* -- x2 = x3 + 4.
*
* -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
*
* Note: the "05 00" is optional (signatures with and without
* that sequence exist in practice), but notes in PKCS#1 seem to
* indicate that the presence of that sequence (specifically,
* an ASN.1 NULL value for the hash parameters) may be slightly
* more "standard" than the opposite.
*/
xlen = (n_bitlen + 7) >> 3;
if (hash_oid == NULL) {
if (xlen < hash_len + 11) {
return 0;
}
x[0] = 0x00;
x[1] = 0x01;
u = xlen - hash_len;
memset(x + 2, 0xFF, u - 3);
x[u - 1] = 0x00;
} else {
x3 = hash_oid[0];
/*
* Check that there is enough room for all the elements,
* including at least eight bytes of value 0xFF.
*/
if (xlen < (x3 + hash_len + 21)) {
return 0;
}
x[0] = 0x00;
x[1] = 0x01;
u = xlen - x3 - hash_len - 11;
memset(x + 2, 0xFF, u - 2);
x[u] = 0x00;
x[u + 1] = 0x30;
x[u + 2] = x3 + hash_len + 8;
x[u + 3] = 0x30;
x[u + 4] = x3 + 4;
x[u + 5] = 0x06;
memcpy(x + u + 6, hash_oid, x3 + 1);
u += x3 + 7;
x[u ++] = 0x05;
x[u ++] = 0x00;
x[u ++] = 0x04;
x[u ++] = hash_len;
}
memcpy(x + u, hash, hash_len);
return 1;
}

View file

@ -0,0 +1,121 @@
/*
* Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "inner.h"
/* see bearssl_rsa.h */
uint32_t
br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len,
const unsigned char *hash_oid, size_t hash_len,
unsigned char *hash_out)
{
static const unsigned char pad1[] = {
0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
unsigned char pad2[43];
size_t u, x2, x3, pad_len, zlen;
if (sig_len < 11) {
return 0;
}
/*
* Expected format:
* 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH
*
* with the following rules:
*
* -- Total length is that of the modulus and the signature
* (this was already verified by br_rsa_i31_public()).
*
* -- There are at least eight bytes of value 0xFF.
*
* -- x4 is equal to the hash length (hash_len).
*
* -- x3 is equal to the encoded OID value length (so x3 is the
* first byte of hash_oid[]).
*
* -- If the "05 00" is present, then x2 == x3 + 4; otherwise,
* x2 == x3 + 2.
*
* -- x1 == x2 + x4 + 4.
*
* So the total length after the last "FF" is either x3 + x4 + 11
* (with the "05 00") or x3 + x4 + 9 (without the "05 00").
*/
/*
* Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes.
* The comparaison is valid because we made sure that the signature
* is at least 11 bytes long.
*/
if (memcmp(sig, pad1, sizeof pad1) != 0) {
return 0;
}
for (u = sizeof pad1; u < sig_len; u ++) {
if (sig[u] != 0xFF) {
break;
}
}
/*
* Remaining length is sig_len - u bytes (including the 00 just
* after the last FF). This must be equal to one of the two
* possible values (depending on whether the "05 00" sequence is
* present or not).
*/
if (hash_oid == NULL) {
if (sig_len - u != hash_len + 1 || sig[u] != 0x00) {
return 0;
}
} else {
x3 = hash_oid[0];
pad_len = x3 + 9;
memset(pad2, 0, pad_len);
zlen = sig_len - u - hash_len;
if (zlen == pad_len) {
x2 = x3 + 2;
} else if (zlen == pad_len + 2) {
x2 = x3 + 4;
pad_len = zlen;
pad2[pad_len - 4] = 0x05;
} else {
return 0;
}
pad2[1] = 0x30;
pad2[2] = x2 + hash_len + 4;
pad2[3] = 0x30;
pad2[4] = x2;
pad2[5] = 0x06;
memcpy(pad2 + 6, hash_oid, x3 + 1);
pad2[pad_len - 2] = 0x04;
pad2[pad_len - 1] = hash_len;
if (memcmp(pad2, sig + u, pad_len) != 0) {
return 0;
}
}
memcpy(hash_out, sig + sig_len - hash_len, hash_len);
return 1;
}