--- pgp/src/rsaglue2.c 2018/04/24 16:40:44 1.1.1.1 +++ pgp/src/rsaglue2.c 2018/04/24 16:44:26 1.1.1.4 @@ -1,489 +1,497 @@ -/* - * rsaglue2.c - These functions wrap and unwrap message digests (MDs) and - * data encryption keys (DEKs) in padding and RSA-encrypt them into - * multi-precision integers. This layer was introduced to allow the - * transparent use of RSAREF for the encryption (where required by - * patent law) or Philip Zimmermann's mpi library (where permitted, such - * as Canada). - * - * This file uses RSAREF to perform the actual encryption and decryption. - * It must be linked with the RSAREF 2.0 library (rsaref.a, rsaref.lib, - * or whatever it's called on your system) to function. - * - * This code only accepts PKCS-style padding. Sorry, folks, but the - * RSAREF routines won't do it any other way. This will cause some - * older messages and signatures trouble. - * See pgformat.doc for a detailed description of the formats. - * - * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. - * The author assumes no liability for damages resulting from the use - * of this software, even if the damage results from defects in this - * software. No warranty is expressed or implied. - * - * Note that while most PGP source modules bear Philip Zimmermann's - * copyright notice, many of them have been revised or entirely written - * by contributors who frequently failed to put their names in their - * code. Code that has been incorporated into PGP from other authors - * was either originally published in the public domain or is used with - * permission from the various authors. - * - * PGP is available for free to the public under certain restrictions. - * See the PGP User's Guide (included in the release package) for - * important information about licensing, patent restrictions on - * certain algorithms, trademarks, copyrights, and export controls. - */ - -#include /* for mem*() */ -#include -#include "mpilib.h" -#include "mpiio.h" -#include "pgp.h" -#include "rsaglue.h" -#include "random.h" /* for cryptRandByte() */ -#include "language.h" /* for _LANG() */ - -char signon_legalese[] = _LANG("Distributed by the Massachusetts Institute of Technology. Uses RSAREF 2.0.\n"); - -#include -#include -#include -/* - * The functions we call in rsa.h are: - * - * int RSAPublicEncrypt PROTO_LIST - * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, - * R_RSA_PUBLIC_KEY *, R_RANDOM_STRUCT *)); - * int RSAPrivateEncrypt PROTO_LIST - * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, - * R_RSA_PRIVATE_KEY *)); - * int RSAPublicDecrypt PROTO_LIST - * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, - * R_RSA_PUBLIC_KEY *)); - * int RSAPrivateDecrypt PROTO_LIST - * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, - * R_RSA_PRIVATE_KEY *)); - */ - -/* Functions to convert to and from RSAREF's bignum formats */ - -void -rsaref2reg (unitptr to, byte *from, int frombytes) -/* Convert an RSAREF-style MSB-first array of bytes to an mpi-style - * native-byte-order integer. (global_precision units long.) - */ -{ - int tobytes; - - tobytes = units2bytes (global_precision); - if (tobytes > frombytes) { - memset(to, 0, tobytes - frombytes); - memcpy((byte *)to + tobytes - frombytes, from, frombytes); - } else { - memcpy((byte *)to, from + frombytes - tobytes, tobytes); - } -#ifndef HIGHFIRST - hiloswap((byte *)to, tobytes); -#endif -} /* rsaref2reg */ - -void -reg2rsaref (byte *to, int tobytes, unitptr from) -/* Convert the other way, mpi format to an array of bytes. */ -{ - int frombytes; - - frombytes = units2bytes(global_precision); - -#ifdef HIGHFIRST - if (tobytes > frombytes) { - memset(to, 0, tobytes-frombytes); - memcpy(to + tobytes - frombytes, (byte *)from, frombytes); - } else { - memcpy(to, (byte *)from + frombytes - tobytes, tobytes); - } -#else - if (tobytes > frombytes) { - memcpy(to, (byte *)from, frombytes); - memset(to + frombytes, 0, tobytes-frombytes); - } else { - memcpy(to, (byte *)from, tobytes); - } - hiloswap(to, tobytes); -#endif -} /* reg2rsaref */ - -int -make_RSA_PUBLIC_KEY(R_RSA_PUBLIC_KEY *rpk, unitptr e, unitptr n) -/* Given mpi's e and n, fill in an R_RSA_PUBLIC_KEY structure. - * Returns -3 on error (key too big), 0 on success - */ -{ - rpk->bits = countbits(n); - - if (rpk->bits > MAX_RSA_MODULUS_BITS) - return -3; - - reg2rsaref(rpk->modulus, MAX_RSA_MODULUS_LEN, n); - reg2rsaref(rpk->exponent, MAX_RSA_MODULUS_LEN, e); - return 0; -} /* make_RSA_PUBLIC_KEY */ - -/* Returns -1 on error, 0 on success */ -int -make_RSA_PRIVATE_KEY(R_RSA_PRIVATE_KEY *rpk, unitptr e, unitptr d, unitptr p, - unitptr q, unitptr dp, unitptr dq, unitptr u, unitptr n) -/* Given a number of necessary mpi's, fill in an R_RSA_PRIVATE_KEY structure. - * Returns -3 on error (key too big), 0 on success - */ -{ - rpk->bits = countbits(n); - - if (rpk->bits > MAX_RSA_MODULUS_BITS || - countbits(p) > MAX_RSA_PRIME_BITS || - countbits(q) > MAX_RSA_PRIME_BITS) - return -3; - - reg2rsaref(rpk->modulus, MAX_RSA_MODULUS_LEN, n); - reg2rsaref(rpk->publicExponent, MAX_RSA_MODULUS_LEN, e); - reg2rsaref(rpk->exponent, MAX_RSA_MODULUS_LEN, d); - /* The larger prime (p) first */ - reg2rsaref(rpk->prime[0], MAX_RSA_PRIME_LEN, q); - reg2rsaref(rpk->prime[1], MAX_RSA_PRIME_LEN, p); - /* d mod (p-1) and d mod (q-1) */ - reg2rsaref(rpk->primeExponent[0], MAX_RSA_PRIME_LEN, dq); - reg2rsaref(rpk->primeExponent[1], MAX_RSA_PRIME_LEN, dp); - /* 1/q mod p */ - reg2rsaref(rpk->coefficient, MAX_RSA_PRIME_LEN, u); - return 0; -} /* make_RSA_PRIVATE_KEY */ - -/* - * These functions hide all the internal details of RSA-encrypted - * keys and digests. - */ - -/* Abstract Syntax Notation One (ASN.1) Distinguished Encoding Rules (DER) - encoding for RSA/MD5, used in PKCS-format signatures. */ -static byte asn_array[] = { /* PKCS 01 block type 01 data */ - 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, - 0x02,0x05,0x05,0x00,0x04,0x10 }; -/* This many bytes from the end, there's a zero byte */ -#define ASN_ZERO_END 3 - -int -rsa_public_encrypt(unitptr outbuf, byteptr inbuf, short bytes, - unitptr E, unitptr N) -/* Encrypt a DEK with a public key. Returns 0 on success. - * <0 means there was an error. - * -1: Generic error - * -3: Key too big - * -4: Key too small - */ -{ - unit temp[MAX_UNIT_PRECISION]; - unsigned int blocksize; - int i; /* Temporary, and holds error codes */ - R_RSA_PUBLIC_KEY PubKey; - R_RANDOM_STRUCT Random; - - /* Fill in the R_RSA_PUBLIC_KEY structure as needed later. */ - i = make_RSA_PUBLIC_KEY(&PubKey, E, N); - if (i < 0) - return i; - - /* The RSAREF routines have their own random number generator - * to generate random padding. The following code seeds it - * from PGP's random number generator. - */ - R_RandomInit(&Random); - for (;;) { - /* Bytes needed is an unsigned int */ - R_GetRandomBytesNeeded(&blocksize, &Random); - if (!blocksize) - break; - if (blocksize > sizeof(temp)) - blocksize = sizeof(temp); - for (i = 0; i < blocksize; i++) - ((byte *)temp)[i] = cryptRandByte(); - R_RandomUpdate(&Random, (byte *)temp, blocksize); - - } - /* Pad and encrypt */ - i = RSAPublicEncrypt((byte *)temp, &blocksize, - inbuf, bytes, &PubKey, &Random); - R_RandomFinal(&Random); /* Clean up RSAREF's RNG */ - burn(Random); /* Just to be sure */ - - if (i) - i = (i == RE_LEN) ? -4 : -1; - - rsaref2reg(outbuf, (byte *)temp, blocksize); - -Cleanup: - mp_burn(temp); - burn(PubKey); - return i < 0 ? i : 0; -} /* rsa_public_encrypt */ - -int -rsa_private_encrypt(unitptr outbuf, byteptr inbuf, short bytes, - unitptr E, unitptr D, unitptr P, unitptr Q, unitptr U, unitptr N) -/* Encrypt a message digest with a private key. - * Returns <0 on error: - * -1: generic error - * -3: Key too big - * -4: Key too small - */ -{ - unit temp[MAX_UNIT_PRECISION]; - unit DP[MAX_UNIT_PRECISION], DQ[MAX_UNIT_PRECISION]; - R_RSA_PRIVATE_KEY PrivKey; - byte *p; - int i; - unsigned int blocksize; - - /* PGP doesn't store these coefficents, so we need to compute them. */ - mp_move(temp,P); - mp_dec(temp); - mp_mod(DP,D,temp); - mp_move(temp,Q); - mp_dec(temp); - mp_mod(DQ,D,temp); - - p = (byte *)temp; - - i = make_RSA_PRIVATE_KEY(&PrivKey, E, D, P, Q, DP, DQ, U, N); - if (i < 0) - goto Cleanup; - memcpy(p, asn_array, sizeof(asn_array)); /* ASN data */ - p += sizeof(asn_array); - memcpy(p, inbuf, bytes); /* User data */ - /* Pad and encrypt */ - i = RSAPrivateEncrypt((byte *)temp, &blocksize, - (byte *)temp, bytes+sizeof(asn_array), &PrivKey); - burn(PrivKey); - if (i) - i = (i == RE_LEN) ? -4 : -1; - - rsaref2reg(outbuf, (byte *)temp, blocksize); - -Cleanup: - burn(temp); - - return i; -} /* rsa_private_encrypt */ - -/* Remove a signature packet from an MPI */ -/* Thus, we expect constant padding and the MIC ASN sequence */ -int -rsa_public_decrypt(byteptr outbuf, unitptr inbuf, - unitptr E, unitptr N) -/* Decrypt a message digest using a public key. Returns the number of bytes - * extracted, or <0 on error. - * -1: Corrupted packet. - * -3: Key too big - * -4: Key too small - * -5: Maybe malformed RSA packet - * -7: Unknown conventional algorithm - * -9: Malformed RSA packet - */ -{ - R_RSA_PUBLIC_KEY PubKey; - unit temp[MAX_UNIT_PRECISION]; - unsigned int blocksize; - int i; - byte *front, *back; - - i = make_RSA_PUBLIC_KEY(&PubKey, E, N); - if (i < 0) - return i; - blocksize = countbytes(inbuf); - reg2rsaref((byte *)temp, blocksize, inbuf); - - i = RSAPublicDecrypt((byte *)temp, &blocksize, - (byte *)temp, blocksize, &PubKey); - burn(PubKey); - if (i) { - mp_burn(temp); - if (i == RE_LEN) - return -4; - if (i == RE_DATA) - return -5; - return -1; - } - front = (byte *)temp; - back = front+blocksize; - - if (memcmp(front, asn_array, sizeof(asn_array))) { - mp_burn(temp); - return -7; - } - front += sizeof(asn_array); - -/* We're done - copy user data to outbuf */ - if (back < front) - goto ErrorReturn; - blocksize = back-front; - memcpy(outbuf, front, blocksize); - mp_burn(temp); - return blocksize; -ErrorReturn: - mp_burn(temp); - return -9; -} /* rsa_public_decrypt */ - -/* We expect to find random padding and an encryption key */ -int -rsa_private_decrypt(byteptr outbuf, unitptr inbuf, - unitptr E, unitptr D, unitptr P, unitptr Q, unitptr U, unitptr N) -/* Decrypt an encryption key using a private key. Returns the number of bytes - * extracted, or <0 on error. - * -1: Generic error - * -3: Key too big - * -4: Key too small - * -5: Maybe malformed RSA - * -7: Unknown conventional algorithm - * -9: Malformed RSA packet - */ -{ - R_RSA_PRIVATE_KEY PrivKey; - byte *front; - unsigned int blocksize; - unit temp[MAX_UNIT_PRECISION]; - unit DP[MAX_UNIT_PRECISION], DQ[MAX_UNIT_PRECISION]; - int i; - - /* PGP doesn't store (d mod p-1) and (d mod q-1), so compute 'em */ - mp_move(temp,P); - mp_dec(temp); - mp_mod(DP,D,temp); - mp_move(temp,Q); - mp_dec(temp); - mp_mod(DQ,D,temp); - - i = make_RSA_PRIVATE_KEY(&PrivKey, E, D, P, Q, DP, DQ, U, N); - mp_burn(DP); - mp_burn(DQ); - mp_burn(temp); - - if (i < 0) - return i; - - blocksize = countbytes(inbuf); - reg2rsaref((byte *)temp, blocksize, inbuf); - i = RSAPrivateDecrypt((byte *)temp, &blocksize, - (byte *)temp, blocksize, &PrivKey); - burn(PrivKey); - if (i) { - if (i == RE_LEN) - return -4; - if (i == RE_DATA) - return -5; - return -1; - } - front = (byte *)temp; /* Start of block */ - - memcpy(outbuf, front, blocksize); - mp_burn(temp); - return blocksize; - -Corrupted: - mp_burn(temp); - return -9; -} /* rsa_private_decrypt */ - -/* - * Stub to replace RSAREF's NN_ModExp with a call to the mpilib's - * faster mp_modexp. (A bit over 3x faster on an IBM PC.) - * It's too bad that RSAREF's NN routines are pretty clean, while the - * mpilib is attractive only to the sort of people who like dead baby - * jokes. But the mpilib is pretty fast, especially on 16-bit machines, - * so this Bride of Frankenstein creation has reason for existence. - * - * If you comment out the following block of code, you get a (much slower) - * pure RSAREF version. - */ -#ifdef USEMPILIB - -/* - * The mpilib keeps numbers in native byte order, in arrays global_precision - * "units" long. RSAREF keeps numbers in little-endian arrays of 32-bit - * "digits". - */ -static void -nn2mpi(unit *mpi, word32 *nn, unsigned nndigits) -{ - /* nndigits must be <= global_precision */ - unsigned i; - word32 *p; - - assert((units2bytes(global_precision) & 3) == 0); - i = units2bytes(global_precision) >> 2; - if (nndigits > i) - nndigits = i; - i -= nndigits; - -#ifdef HIGHFIRST - p = (word32 *)(mpi+global_precision); - while (nndigits--) - *--p = *nn++; - while (i--) - *--p = 0; -#else - p = (word32 *)mpi; - while (nndigits--) - *p++ = *nn++; - while (i--) - *p++ = 0; -#endif -} - -static void -mpi2nn(word32 *nn, unsigned nndigits, unit *mpi) -{ - /* nndigits must be >= global_precision */ - unsigned i; - word32 *p; - - assert((units2bytes(global_precision) & 3) == 0); - i = units2bytes(global_precision) >> 2; - if (i > nndigits) - i = nndigits; - nndigits -= i; - -#ifdef HIGHFIRST - p = (word32 *)(mpi+global_precision); - while (i--) - *nn++ = *--p; -#else - p = (word32 *)mpi; - while (i--) - *nn++ = *p++; -#endif - while (nndigits--) - *nn++ = 0; -} - -void -NN_ModExp(word32 *result, word32 *base, word32 *exponent, unsigned expdigits, - word32 *modulus, unsigned moddigits) -{ - unit a[MAX_UNIT_PRECISION], b[MAX_UNIT_PRECISION]; - unit c[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION]; - int i; - unsigned oldprecision; - - oldprecision = global_precision; - set_precision(MAX_UNIT_PRECISION); - - nn2mpi(b, base, moddigits); - nn2mpi(c, exponent, expdigits); - nn2mpi(d, modulus, moddigits); - - i = mp_modexp(a, b, c, d); - assert(i == 0); - mpi2nn(result, moddigits, a); - set_precision(oldprecision); -} - -#endif +/* + * rsaglue2.c - These functions wrap and unwrap message digests (MDs) and + * data encryption keys (DEKs) in padding and RSA-encrypt them into + * multi-precision integers. This layer of abstraction was introduced + * to allow the transparent use of either the RSAREF Cryptographic + * Toolkit from RSA Data Security Inc for the RSA calculations (where + * the RSA patent applies), or, by using a different version of this + * rsaglue module, we can use Philip Zimmermann's mpi library for the + * RSA calculations. The rsaglue.c module from PGP version 2.3a performs + * the same functions as this module, but can be compiled to select the + * use of mpilib functions instead of RSAREF as the underlying math engine. + * That version of rsaglue.c would be suitable where the RSA patent does + * not apply, such as Canada. + * + * This file uses RSAREF to perform the actual encryption and decryption. + * It must be linked with the RSAREF library (rsaref.a, rsaref.lib, + * or whatever it's called on your system) to function. + * + * This code only accepts PKCS-style padding. Sorry, folks, but the + * RSAREF routines won't do it any other way. This will cause some + * older messages and signatures trouble. + * See pgformat.doc for a detailed description of the formats. + * + * (c) Copyright 1990-1994 by Philip Zimmermann. All rights reserved. + * The author assumes no liability for damages resulting from the use + * of this software, even if the damage results from defects in this + * software. No warranty is expressed or implied. + * + * Note that while most PGP source modules bear Philip Zimmermann's + * copyright notice, many of them have been revised or entirely written + * by contributors who frequently failed to put their names in their + * code. Code that has been incorporated into PGP from other authors + * was either originally published in the public domain or is used with + * permission from the various authors. + * + * PGP is available for free to the public under certain restrictions. + * See the PGP User's Guide (included in the release package) for + * important information about licensing, patent restrictions on + * certain algorithms, trademarks, copyrights, and export controls. + */ + +#include /* for mem*() */ +#include +#include "mpilib.h" +#include "mpiio.h" +#include "pgp.h" +#include "rsaglue.h" +#include "random.h" /* for cryptRandByte() */ +#include "language.h" /* for _LANG() */ + +char signon_legalese[] = _LANG("\ +Uses the RSAREF(tm) Toolkit, which is copyright RSA Data Security, Inc.\n\ +Distributed by the Massachusetts Institute of Technology.\n"); + +#include +#include +#include +/* + * The functions we call in rsa.h are: + * + * int RSAPublicEncrypt PROTO_LIST + * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, + * R_RSA_PUBLIC_KEY *, R_RANDOM_STRUCT *)); + * int RSAPrivateEncrypt PROTO_LIST + * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, + * R_RSA_PRIVATE_KEY *)); + * int RSAPublicDecrypt PROTO_LIST + * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, + * R_RSA_PUBLIC_KEY *)); + * int RSAPrivateDecrypt PROTO_LIST + * ((unsigned char *, unsigned int *, unsigned char *, unsigned int, + * R_RSA_PRIVATE_KEY *)); + */ + +/* Functions to convert to and from RSAREF's bignum formats */ + +void +rsaref2reg (unitptr to, byte *from, int frombytes) +/* Convert an RSAREF-style MSB-first array of bytes to an mpi-style + * native-byte-order integer. (global_precision units long.) + */ +{ + int tobytes; + + tobytes = units2bytes (global_precision); + if (tobytes > frombytes) { + memset(to, 0, tobytes - frombytes); + memcpy((byte *)to + tobytes - frombytes, from, frombytes); + } else { + memcpy((byte *)to, from + frombytes - tobytes, tobytes); + } +#ifndef HIGHFIRST + hiloswap((byte *)to, tobytes); +#endif +} /* rsaref2reg */ + +void +reg2rsaref (byte *to, int tobytes, unitptr from) +/* Convert the other way, mpi format to an array of bytes. */ +{ + int frombytes; + + frombytes = units2bytes(global_precision); + +#ifdef HIGHFIRST + if (tobytes > frombytes) { + memset(to, 0, tobytes-frombytes); + memcpy(to + tobytes - frombytes, (byte *)from, frombytes); + } else { + memcpy(to, (byte *)from + frombytes - tobytes, tobytes); + } +#else + if (tobytes > frombytes) { + memcpy(to, (byte *)from, frombytes); + memset(to + frombytes, 0, tobytes-frombytes); + } else { + memcpy(to, (byte *)from, tobytes); + } + hiloswap(to, tobytes); +#endif +} /* reg2rsaref */ + +int +make_RSA_PUBLIC_KEY(R_RSA_PUBLIC_KEY *rpk, unitptr e, unitptr n) +/* Given mpi's e and n, fill in an R_RSA_PUBLIC_KEY structure. + * Returns -3 on error (key too big), 0 on success + */ +{ + rpk->bits = countbits(n); + + if (rpk->bits > MAX_RSA_MODULUS_BITS) + return -3; + + reg2rsaref(rpk->modulus, MAX_RSA_MODULUS_LEN, n); + reg2rsaref(rpk->exponent, MAX_RSA_MODULUS_LEN, e); + return 0; +} /* make_RSA_PUBLIC_KEY */ + +/* Returns -1 on error, 0 on success */ +int +make_RSA_PRIVATE_KEY(R_RSA_PRIVATE_KEY *rpk, unitptr e, unitptr d, unitptr p, + unitptr q, unitptr dp, unitptr dq, unitptr u, unitptr n) +/* Given a number of necessary mpi's, fill in an R_RSA_PRIVATE_KEY structure. + * Returns -3 on error (key too big), 0 on success + */ +{ + rpk->bits = countbits(n); + + if (rpk->bits > MAX_RSA_MODULUS_BITS || + countbits(p) > MAX_RSA_PRIME_BITS || + countbits(q) > MAX_RSA_PRIME_BITS) + return -3; + + reg2rsaref(rpk->modulus, MAX_RSA_MODULUS_LEN, n); + reg2rsaref(rpk->publicExponent, MAX_RSA_MODULUS_LEN, e); + reg2rsaref(rpk->exponent, MAX_RSA_MODULUS_LEN, d); + /* The larger prime (p) first */ + reg2rsaref(rpk->prime[0], MAX_RSA_PRIME_LEN, q); + reg2rsaref(rpk->prime[1], MAX_RSA_PRIME_LEN, p); + /* d mod (p-1) and d mod (q-1) */ + reg2rsaref(rpk->primeExponent[0], MAX_RSA_PRIME_LEN, dq); + reg2rsaref(rpk->primeExponent[1], MAX_RSA_PRIME_LEN, dp); + /* 1/q mod p */ + reg2rsaref(rpk->coefficient, MAX_RSA_PRIME_LEN, u); + return 0; +} /* make_RSA_PRIVATE_KEY */ + +/* + * These functions hide all the internal details of RSA-encrypted + * keys and digests. + */ + +/* Abstract Syntax Notation One (ASN.1) Distinguished Encoding Rules (DER) + encoding for RSA/MD5, used in PKCS-format signatures. */ +static byte asn_array[] = { /* PKCS 01 block type 01 data */ + 0x30,0x20,0x30,0x0c,0x06,0x08,0x2a,0x86,0x48,0x86,0xf7,0x0d, + 0x02,0x05,0x05,0x00,0x04,0x10 }; +/* This many bytes from the end, there's a zero byte */ +#define ASN_ZERO_END 3 + +int +rsa_public_encrypt(unitptr outbuf, byteptr inbuf, short bytes, + unitptr E, unitptr N) +/* Encrypt a DEK with a public key. Returns 0 on success. + * <0 means there was an error. + * -1: Generic error + * -3: Key too big + * -4: Key too small + */ +{ + unit temp[MAX_UNIT_PRECISION]; + unsigned int blocksize; + int i; /* Temporary, and holds error codes */ + R_RSA_PUBLIC_KEY PubKey; + R_RANDOM_STRUCT Random; + + /* Fill in the R_RSA_PUBLIC_KEY structure as needed later. */ + i = make_RSA_PUBLIC_KEY(&PubKey, E, N); + if (i < 0) + return i; + + /* The RSAREF routines have their own random number generator + * to generate random padding. The following code seeds it + * from PGP's random number generator. + */ + R_RandomInit(&Random); + for (;;) { + /* Bytes needed is an unsigned int */ + R_GetRandomBytesNeeded(&blocksize, &Random); + if (!blocksize) + break; + if (blocksize > sizeof(temp)) + blocksize = sizeof(temp); + for (i = 0; i < blocksize; i++) + ((byte *)temp)[i] = cryptRandByte(); + R_RandomUpdate(&Random, (byte *)temp, blocksize); + + } + /* Pad and encrypt */ + i = RSAPublicEncrypt((byte *)temp, &blocksize, + inbuf, bytes, &PubKey, &Random); + R_RandomFinal(&Random); /* Clean up RSAREF's RNG */ + burn(Random); /* Just to be sure */ + + if (i) + i = (i == RE_LEN) ? -4 : -1; + + rsaref2reg(outbuf, (byte *)temp, blocksize); + +Cleanup: + mp_burn(temp); + burn(PubKey); + return i < 0 ? i : 0; +} /* rsa_public_encrypt */ + +int +rsa_private_encrypt(unitptr outbuf, byteptr inbuf, short bytes, + unitptr E, unitptr D, unitptr P, unitptr Q, unitptr U, unitptr N) +/* Encrypt a message digest with a private key. + * Returns <0 on error: + * -1: generic error + * -3: Key too big + * -4: Key too small + */ +{ + unit temp[MAX_UNIT_PRECISION]; + unit DP[MAX_UNIT_PRECISION], DQ[MAX_UNIT_PRECISION]; + R_RSA_PRIVATE_KEY PrivKey; + byte *p; + int i; + unsigned int blocksize; + + /* PGP doesn't store these coefficents, so we need to compute them. */ + mp_move(temp,P); + mp_dec(temp); + mp_mod(DP,D,temp); + mp_move(temp,Q); + mp_dec(temp); + mp_mod(DQ,D,temp); + + p = (byte *)temp; + + i = make_RSA_PRIVATE_KEY(&PrivKey, E, D, P, Q, DP, DQ, U, N); + if (i < 0) + goto Cleanup; + memcpy(p, asn_array, sizeof(asn_array)); /* ASN data */ + p += sizeof(asn_array); + memcpy(p, inbuf, bytes); /* User data */ + /* Pad and encrypt */ + i = RSAPrivateEncrypt((byte *)temp, &blocksize, + (byte *)temp, bytes+sizeof(asn_array), &PrivKey); + burn(PrivKey); + if (i) + i = (i == RE_LEN) ? -4 : -1; + + rsaref2reg(outbuf, (byte *)temp, blocksize); + +Cleanup: + burn(temp); + + return i; +} /* rsa_private_encrypt */ + +/* Remove a signature packet from an MPI */ +/* Thus, we expect constant padding and the MIC ASN sequence */ +int +rsa_public_decrypt(byteptr outbuf, unitptr inbuf, + unitptr E, unitptr N) +/* Decrypt a message digest using a public key. Returns the number of bytes + * extracted, or <0 on error. + * -1: Corrupted packet. + * -3: Key too big + * -4: Key too small + * -5: Maybe malformed RSA packet + * -7: Unknown conventional algorithm + * -9: Malformed RSA packet + */ +{ + R_RSA_PUBLIC_KEY PubKey; + unit temp[MAX_UNIT_PRECISION]; + unsigned int blocksize; + int i; + byte *front, *back; + + i = make_RSA_PUBLIC_KEY(&PubKey, E, N); + if (i < 0) + return i; + blocksize = countbytes(inbuf); + reg2rsaref((byte *)temp, blocksize, inbuf); + + i = RSAPublicDecrypt((byte *)temp, &blocksize, + (byte *)temp, blocksize, &PubKey); + burn(PubKey); + if (i) { + mp_burn(temp); + if (i == RE_LEN) + return -4; + if (i == RE_DATA) + return -5; + return -1; + } + front = (byte *)temp; + back = front+blocksize; + + if (memcmp(front, asn_array, sizeof(asn_array))) { + mp_burn(temp); + return -7; + } + front += sizeof(asn_array); + +/* We're done - copy user data to outbuf */ + if (back < front) + goto ErrorReturn; + blocksize = back-front; + memcpy(outbuf, front, blocksize); + mp_burn(temp); + return blocksize; +ErrorReturn: + mp_burn(temp); + return -9; +} /* rsa_public_decrypt */ + +/* We expect to find random padding and an encryption key */ +int +rsa_private_decrypt(byteptr outbuf, unitptr inbuf, + unitptr E, unitptr D, unitptr P, unitptr Q, unitptr U, unitptr N) +/* Decrypt an encryption key using a private key. Returns the number of bytes + * extracted, or <0 on error. + * -1: Generic error + * -3: Key too big + * -4: Key too small + * -5: Maybe malformed RSA + * -7: Unknown conventional algorithm + * -9: Malformed RSA packet + */ +{ + R_RSA_PRIVATE_KEY PrivKey; + byte *front; + unsigned int blocksize; + unit temp[MAX_UNIT_PRECISION]; + unit DP[MAX_UNIT_PRECISION], DQ[MAX_UNIT_PRECISION]; + int i; + + /* PGP doesn't store (d mod p-1) and (d mod q-1), so compute 'em */ + mp_move(temp,P); + mp_dec(temp); + mp_mod(DP,D,temp); + mp_move(temp,Q); + mp_dec(temp); + mp_mod(DQ,D,temp); + + i = make_RSA_PRIVATE_KEY(&PrivKey, E, D, P, Q, DP, DQ, U, N); + mp_burn(DP); + mp_burn(DQ); + mp_burn(temp); + + if (i < 0) + return i; + + blocksize = countbytes(inbuf); + reg2rsaref((byte *)temp, blocksize, inbuf); + i = RSAPrivateDecrypt((byte *)temp, &blocksize, + (byte *)temp, blocksize, &PrivKey); + burn(PrivKey); + if (i) { + if (i == RE_LEN) + return -4; + if (i == RE_DATA) + return -5; + return -1; + } + front = (byte *)temp; /* Start of block */ + + memcpy(outbuf, front, blocksize); + mp_burn(temp); + return blocksize; + +Corrupted: + mp_burn(temp); + return -9; +} /* rsa_private_decrypt */ + +/* + * Stub to replace RSAREF's NN_ModExp with a call to the mpilib's + * faster mp_modexp. (A bit over 3x faster on an IBM PC.) + * It's too bad that RSAREF's NN routines are pretty clean, while the + * mpilib is a hard-to-follow kludge. But the mpilib is pretty fast, + * especially on 16-bit machines, so the kludginess is forgivable. + * Note that we are still using RSAREF, but we are just using a faster + * modulo exponentiation routine. + * If you comment out the following block of code, you get a (much slower) + * pure RSAREF version. + */ +#ifdef USEMPILIB + +/* + * The mpilib keeps numbers in native byte order, in arrays global_precision + * "units" long. RSAREF keeps numbers in little-endian arrays of 32-bit + * "digits". + */ +static void +nn2mpi(unit *mpi, word32 *nn, unsigned nndigits) +{ + /* nndigits must be <= global_precision */ + unsigned i; + word32 *p; + + assert((units2bytes(global_precision) & 3) == 0); + i = units2bytes(global_precision) >> 2; + if (nndigits > i) + nndigits = i; + i -= nndigits; + +#ifdef HIGHFIRST + p = (word32 *)(mpi+global_precision); + while (nndigits--) + *--p = *nn++; + while (i--) + *--p = 0; +#else + p = (word32 *)mpi; + while (nndigits--) + *p++ = *nn++; + while (i--) + *p++ = 0; +#endif +} + +static void +mpi2nn(word32 *nn, unsigned nndigits, unit *mpi) +{ + /* nndigits must be >= global_precision */ + unsigned i; + word32 *p; + + assert((units2bytes(global_precision) & 3) == 0); + i = units2bytes(global_precision) >> 2; + if (i > nndigits) + i = nndigits; + nndigits -= i; + +#ifdef HIGHFIRST + p = (word32 *)(mpi+global_precision); + while (i--) + *nn++ = *--p; +#else + p = (word32 *)mpi; + while (i--) + *nn++ = *p++; +#endif + while (nndigits--) + *nn++ = 0; +} + +void +NN_ModExp(word32 *result, word32 *base, word32 *exponent, unsigned expdigits, + word32 *modulus, unsigned moddigits) +{ + unit a[MAX_UNIT_PRECISION], b[MAX_UNIT_PRECISION]; + unit c[MAX_UNIT_PRECISION], d[MAX_UNIT_PRECISION]; + int i; + unsigned oldprecision; + + oldprecision = global_precision; + set_precision(MAX_UNIT_PRECISION); + + nn2mpi(b, base, moddigits); + nn2mpi(c, exponent, expdigits); + nn2mpi(d, modulus, moddigits); + + i = mp_modexp(a, b, c, d); + assert(i == 0); + mpi2nn(result, moddigits, a); + set_precision(oldprecision); +} + +#endif