This is rsaglue2.c in view mode; [Download] [Up]
/* * 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 <string.h> /* for mem*() */ #include <assert.h> #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 <global.h> #include <rsaref.h> #include <rsa.h> /* * 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
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.