123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471 |
- /*
- * Copyright (c) 1995 Colin Plumb. All rights reserved.
- * For licensing and other legal details, see the file legal.c.
- *
- * rsaglue.c - The interface between bignum math and RSA operations.
- * This layer's primary reason for existence is to allow adaptation
- * to other RSA math libraries for legal reasons.
- */
- #include "first.h"
- #include "bn.h"
- #include "keys.h"
- #include "random.h"
- #include "rsaglue.h"
- #include "usuals.h"
- /*#define BNDEBUG 1*/
- #if BNDEBUG
- /* Some debugging hooks which have been left in for now. */
- #include "bn/bnprint.h"
- #define bndPut(prompt, bn) bnPrint(stdout, prompt, bn, "\n")
- #define bndPrintf printf
- #else
- #define bndPut(prompt, bn) ((void)(prompt),(void)(bn))
- #define bndPrintf(x) (void)0
- #endif
- /*
- * This returns TRUE if the key is too big, returning the
- * maximum number of bits that the library can accept. It
- * is used if you want to use something icky from RSADSI, whose
- * code is known to have satatic limits on key sizes. (BSAFE 2.1
- * advertises 2048-bit key sizes. It lies. It's talking about
- * conventional RC4 keys, whicah are useless to make anything like
- * that large. RSA keys are limited to 1024 bits.
- */
- int
- rsaKeyTooBig(struct PubKey const *pub, struct SecKey const *sec)
- {
- (void)pub;
- (void)sec;
- return 0; /* Never too big! */
- }
- /*
- * Fill the given bignum, from bytes high-1 through low (where 0 is
- * the least significant byte), with non-zero random data.
- */
- static int
- randomPad(struct BigNum *bn, unsigned high, unsigned low)
- {
- unsigned i, l;
- byte padding[64]; /* This can be any size (>0) whatsoever */
- high -= low;
- while (high) {
- l = high < sizeof(padding) ? high : sizeof(padding);
- randBytes(padding, l);
- for (i = 0; i < l; i++) { /* Replace all zero bytes */
- while(padding[i] == 0)
- randBytes(padding+i, 1);
- }
- high -= l;
- if (bnInsertBigBytes(bn, padding, high+low, l) < 0)
- return RSAGLUE_NOMEM;
- }
- memset(padding, 0, sizeof(padding));
- return 0;
- }
- /*
- * Fill the given bignum, from bytes high-1 through low (where 0 is
- * the least significant byte), with all ones (0xFF) data.
- */
- static int
- onesPad(struct BigNum *bn, unsigned high, unsigned low)
- {
- unsigned l;
- static byte const padding[] = {
- 255,255,255,255,255,255,255,255,
- 255,255,255,255,255,255,255,255
- };
- high -= low;
- while (high) {
- l = high < sizeof(padding) ? high : sizeof(padding);
- high -= l;
- if (bnInsertBigBytes(bn, padding, high+low, l) < 0)
- return RSAGLUE_NOMEM;
- }
- return 0;
- }
- /*
- * Wrap a PKCS type 2 wrapper around some data and RSA encrypt it.
- * If the modulus is n bytes long, with the most significant byte
- * being n-1 and the least significant, 0, the wrapper looks like:
- *
- * Position Value Function
- * n-1 0 This is needed to ensure that the padded number
- * is less than the modulus.
- * n-2 2 The padding type (non-zero random).
- * n-3..len+1 ??? Non-zero random padding bytes to "salt" the
- * output and prevent duplicate plaintext attacks.
- * len 0 Zero byte to mark the end of the padding
- * len-1..0 data Supplied payload data.
- *
- * There really should be several bytes of padding, although this
- * routine will not fail to encrypt unless it will not fit, even
- * with no padding bytes.
- */
- static byte const encryptedType = 2;
- int
- rsaPublicEncrypt(struct BigNum *bn, byte const *in, unsigned len,
- struct PubKey const *pub)
- {
- unsigned bytes = (bnBits(&pub->n)+7)/8;
- if (len+3 > bytes)
- return RSAGLUE_TOOSMALL; /* Won't fit! */
- /* Set the entire number to 0 to start */
- (void)bnSetQ(bn, 0);
- if (bnInsertBigBytes(bn, &encryptedType, bytes-2, 1) < 0)
- return RSAGLUE_NOMEM;
- if (randomPad(bn, bytes-2, len+1) < 0)
- return RSAGLUE_NOMEM;
- if (bnInsertBigBytes(bn, in, 0, len) < 0)
- return RSAGLUE_NOMEM;
- bndPrintf("RSA encrypting.\n");
- bndPut("plaintext = ", bn);
- return bnExpMod(bn, bn, &pub->e, &pub->n);
- }
- /*
- * This performs a modular exponentiation using the Chinese Remainder
- * Algorithm when the modulus is known to have two relatively prime
- * factors n = p * q, and u = p^-1 (mod q) has been precomputed.
- *
- * The chinese remainder algorithm lets a computation mod n be performed
- * mod p and mod q, and the results combined. Since it takes
- * (considerably) more than twice as long to perform modular exponentiation
- * mod n as it does to perform it mod p and mod q, time is saved.
- *
- * If x is the desired result, let xp and xq be the values of x mod p
- * and mod q, respectively. Obviously, x = xp + p * k for some k.
- * Taking this mod q, xq == xp + p*k (mod q), so p*k == xq-xp (mod q)
- * and k == p^-1 * (xq-xp) (mod q), so k = u * (xq-xp mod q) mod q.
- * After that, x = xp + p * k.
- *
- * Another savings comes from reducing the exponent d modulo phi(p)
- * and phi(q). Here, we assume that p and q are prime, so phi(p) = p-1
- * and phi(q) = q-1.
- */
- static int
- bnExpModCRA(struct BigNum *x, struct BigNum const *d,
- struct BigNum const *p, struct BigNum const *q, struct BigNum const *u)
- {
- struct BigNum xp, xq, k;
- int i;
- bndPrintf("Performing CRA\n");
- bndPut("x = ", x);
- bndPut("p = ", p);
- bndPut("q = ", q);
- bndPut("d = ", d);
- bndPut("u = ", u);
- bnBegin(&xp);
- bnBegin(&xq);
- bnBegin(&k);
- /* Compute xp = (x mod p) ^ (d mod p-1) mod p */
- if (bnCopy(&xp, p) < 0) /* First, use xp to hold p-1 */
- goto fail;
- (void)bnSubQ(&xp, 1); /* p > 1, so subtracting is safe. */
- if (bnMod(&k, d, &xp) < 0) /* Use k to hold the exponent */
- goto fail;
- bndPut("d mod p-1 = ", &k);
- if (bnMod(&xp, x, p) < 0) /* Now xp = (x mod p) */
- goto fail;
- bndPut("x mod p = ", &xp);
- if (bnExpMod(&xp, &xp, &k, p) < 0) /* xp = (x mod p)^k mod p */
- goto fail;
- bndPut("xp = x^d mod p = ", &xp);
- /* Compute xq = (x mod q) ^ (d mod q-1) mod q */
- if (bnCopy(&xq, q) < 0) /* First, use xq to hold q-1 */
- goto fail;
- (void)bnSubQ(&xq, 1); /* q > 1, so subtracting is safe. */
- if (bnMod(&k, d, &xq) < 0) /* Use k to hold the exponent */
- goto fail;
- bndPut("d mod q-1 = ", &k);
- if (bnMod(&xq, x, q) < 0) /* Now xq = (x mod q) */
- goto fail;
- bndPut("x mod q = ", &xq);
- if (bnExpMod(&xq, &xq, &k, q) < 0) /* xq = (x mod q)^k mod q */
- goto fail;
- bndPut("xq = x^d mod q = ", &xq);
- i = bnSub(&xq, &xp);
- bndPut("xq - xp = ", &xq);
- bndPrintf(("With sign %d\n", i));
- if (i < 0)
- goto fail;
- if (i) {
- /*
- * Borrow out - xq-xp is negative, so bnSub returned
- * xp-xq instead, the negative of the true answer.
- * Add q back (which is subtracting from the negative)
- * until the sign flips again. If p is much greater
- * than q, this step could take annoyingly long.
- * PGP requires that p < q, so it'll only happen once.
- * You could get this stuck in a very lengthy loop by
- * feeding this function a p >> q, but it seems fair
- * to assume that secret keys are not constructed
- * maliciously.
- *
- * If this becomes a concern, you can fix it up with a
- * bnMod. (But watch out for the case that the correct
- * answer is zero!)
- */
- do {
- i = bnSub(&xq, q);
- bndPut("xq - xp mod q = ", &xq);
- if (i < 0)
- goto fail;
- } while (!i);
- }
- /* Compute k = xq * u mod q */
- if (bnMul(&k, u, &xq) < 0)
- goto fail;
- bndPut("(xq-xp) * u = ", &k);
- if (bnMod(&k, &k, q) < 0)
- goto fail;
- bndPut("k = (xq-xp)*u % q = ", &k);
- #if BNDEBUG /* @@@ DEBUG - do it the slow way for comparison */
- if (bnMul(&xq, p, q) < 0)
- goto fail;
- bndPut("n = p*q = ", &xq);
- if (bnExpMod(x, x, d, &xq) < 0)
- goto fail;
- if (bnCopy(&xq, x) < 0)
- goto fail;
- bndPut("x^d mod n = ", &xq);
- #endif
- /* Now x = k * p + xp is the final answer */
- if (bnMul(x, &k, p) < 0)
- goto fail;
- bndPut("k * p = ", x);
- if (bnAdd(x, &xp) < 0)
- goto fail;
- bndPut("k*p + xp = ", x);
- #if BNDEBUG
- if (bnCmp(x, &xq) != 0) {
- bndPrintf(("Nasty!!!\n"));
- goto fail;
- }
- bnSetQ(&k, 17);
- bnMul(&xp, p, q);
- bnExpMod(&xq, &xq, &k, &xp);
- bndPut("x^17 mod n = ", &xq);
- #endif
- bnEnd(&xp);
- bnEnd(&xq);
- bnEnd(&k);
- return 0;
- fail:
- bnEnd(&xp);
- bnEnd(&xq);
- bnEnd(&k);
- return RSAGLUE_NOMEM;
- }
- /*
- * This does an RSA signing operation, which is very similar, except
- * that the padding differs. The type is 1, and the padding is all 1's
- * (hex 0xFF).
- *
- * To summarize, the format is:
- *
- * Position Value Function
- * n-1 0 This is needed to ensure that the padded number
- * is less than the modulus.
- * n-2 1 The padding type (all ones).
- * n-3..len+1 255 All ones padding to ensure signatures are rare.
- * len 0 Zero byte to mark the end of the padding
- * len-1..0 data The payload
- *
- *
- * The reason for the all 1's padding is an extra consistency check.
- * A randomly invented signature will not decrypt to have the long
- * run of ones necessary for acceptance.
- *
- * Oh... the public key isn't needed to decrypt, but it's passed in
- * because a different glue library may need it for some reason.
- */
- static const byte signedType = 1;
- int
- rsaPrivateEncrypt(struct BigNum *bn, byte const *in, unsigned len,
- struct PubKey const *pub, struct SecKey const *sec)
- {
- unsigned bytes = (bnBits(&pub->n)+7)/8;
- /* Set the entire number to 0 to start */
- (void)bnSetQ(bn, 0);
- if (len+3 > bytes)
- return RSAGLUE_TOOSMALL; /* Won't fit */
- if (bnInsertBigBytes(bn, &signedType, bytes-2, 1) < 0)
- return RSAGLUE_NOMEM;
- if (onesPad(bn, bytes-2, len+1) < 0)
- return RSAGLUE_NOMEM;
- if (bnInsertBigBytes(bn, in, 0, len) < 0)
- return RSAGLUE_NOMEM;
- bndPrintf(("RSA signing.\n"));
- bndPut("plaintext = ", bn);
- return bnExpModCRA(bn, &sec->d, &sec->p, &sec->q, &sec->u);
- }
- /*
- * Searches bytes, beginning with start-1 and progressing to 0,
- * until one that is not 0xff is found. The idex of the last 0xff
- * byte is returned (or start if start-1 is not 0xff.)
- */
- static unsigned
- bnSearchNonOneFromHigh(struct BigNum const *bn, unsigned start)
- {
- byte buf[16]; /* Size is arbitrary */
- unsigned l;
- unsigned i;
- while (start) {
- l = start < sizeof(buf) ? start : sizeof(buf);
- start -= l;
- bnExtractBigBytes(bn, buf, start, l);
- for (i = 0; i < l; i++) {
- if (buf[i] != 0xff) {
- memset(buf, 0, sizeof(buf));
- return start + l - i;
- }
- }
- }
- /* Nothing found */
- memset(buf, 0, sizeof(buf));
- return 0;
- }
- /*
- * Decrypt a message with a public key.
- * These destroy (actually, replace with a decrypted version) the
- * input bignum bn.
- *
- * Performs an RSA signature check. Returns a prefix of the unwrapped
- * data in the given buf. Returns the length of the untruncated
- * data, which may exceed "len". Returns <0 on error.
- */
- int
- rsaPublicDecrypt(byte *buf, unsigned len, struct BigNum *bn,
- struct PubKey const *pub)
- {
- byte tmp[1];
- unsigned bytes;
- bndPrintf(("RSA signature checking.\n"));
- if (bnExpMod(bn, bn, &pub->e, &pub->n) < 0)
- return RSAGLUE_NOMEM;
- bndPut("decrypted = ", bn);
- bytes = (bnBits(&pub->n)+7)/8;
- bnExtractBigBytes(bn, tmp, bytes-2, 2);
- if (tmp[0] != 0 || tmp[1] != signedType) {
- memset(tmp, 0, 2);
- return RSAGLUE_CORRUPT;
- }
- bytes = bnSearchNonOneFromHigh(bn, bytes-2);
- if (bytes < 1)
- return RSAGLUE_CORRUPT;
- bytes--;
- bnExtractBigBytes(bn, tmp, bytes, 1);
- if (tmp[0] != 0) {
- tmp[0] = 0;
- return RSAGLUE_CORRUPT;
- }
- /* Note: tmp isn't sensitive any more because its a constant! */
- /* Success! Return the data */
- if (len > bytes)
- len = bytes;
- bnExtractBigBytes(bn, buf, bytes-len, len);
- return bytes;
- }
- /*
- * Searches bytes, beginning with start-1 and progressing to 0,
- * until finding one that is zero, or the end of the array.
- * The index of the last non-zero byte is returned (0 if the array
- * is all non-zero, or start if start-1 is zero).
- */
- static unsigned
- bnSearchZeroFromHigh(struct BigNum const *bn, unsigned start)
- {
- byte buf[16]; /* Size is arbitrary */
- unsigned l;
- unsigned i;
- while (start) {
- l = start < sizeof(buf) ? start : sizeof(buf);
- start -= l;
- bnExtractBigBytes(bn, buf, start, l);
- for (i = 0; i < l; i++) {
- if (buf[i] == 0) {
- memset(buf, 0, sizeof(buf));
- return start + l - i;
- }
- }
- }
- /* Nothing found */
- memset(buf, 0, sizeof(buf));
- return 0;
- }
- /*
- * Performs an RSA decryption. Returns a prefix of the unwrapped
- * data in the given buf. Returns the length of the untruncated
- * data, which may exceed "len". Returns <0 on error.
- */
- int
- rsaPrivateDecrypt(byte *buf, unsigned len, struct BigNum *bn,
- struct PubKey const *pub, struct SecKey const *sec)
- {
- unsigned bytes;
- byte tmp[2];
- bndPrintf(("RSA decrypting\n"));
- if (bnExpModCRA(bn, &sec->d, &sec->p, &sec->q, &sec->u) < 0)
- return RSAGLUE_NOMEM;
- bndPut("decrypted = ", bn);
- bytes = (bnBits(&pub->n)+7)/8;
- bnExtractBigBytes(bn, tmp, bytes-2, 2);
- if (tmp[0] != 0 || tmp[1] != 2) {
- memset(tmp, 0, 2);
- return RSAGLUE_CORRUPT;
- }
- bytes = bnSearchZeroFromHigh(bn, bytes-2);
- if (bytes-- == 0)
- return RSAGLUE_CORRUPT;
- if (len > bytes)
- len = bytes;
- bnExtractBigBytes(bn, buf, bytes-len, len);
- return bytes;
- }
|