This is rsaglue1.c in view mode; [Download] [Up]
/* * rsaglue1.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, 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 MPILIB to perform the actual encryption and decryption. * It uses the same PKCS format as RSAREF, although it also accepts an older * format used in PGP 2.1. * * (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 "mpilib.h" #include "mpiio.h" #include "pgp.h" #include "rsaglue.h" #include "random.h" /* for cryptRandByte() */ /* No RSADSI credit for MPI version */ char signon_legalese[] = ""; /* These functions hide all the internal details of RSA-encrypted * keys and digests. They owe a lot of their heritage to * the preblock() and postunblock() routines in mpiio.c. */ /* 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 */ byte *p = (byte *)temp; /* * We are building the mpi in place, except for a possible * byte-order swap to little-endian at the end. Thus, we * need to fill the buffer with leading 0's in the unused * most significant byte positions. */ blocksize = countbytes(N) - 1; /* Bytes available for user data */ for (i = units2bytes(global_precision) - blocksize; i > 0; --i) *p++ = 0; /* * Both the PKCS and PGP 2.0 key formats add a type byte, and a * a framing byte of 0 to the user data. The remaining space * is filled with random padding. (PKCS requires that there be * at least 1 byte of padding.) */ i = blocksize - 2 - bytes; if (i < 1) /* Less than minimum padding? */ return -4; *p++ = CK_ENCRYPTED_BYTE; /* Type byte */ while (i) /* Non-zero random padding */ if ((*p = cryptRandByte())) ++p, --i; *p++ = 0; /* Framing byte */ memcpy(p, inbuf, bytes); /* User data */ mp_convert_order((byte *)temp); /* Convert buffer to MPI */ i = mp_modexp(outbuf, temp, E, N); /* Do the encryption */ if (i < 0) #ifdef MIT i == -1; #else i = -1; #endif Cleanup: mp_burn(temp); 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 * -4: Key too big * -5: Key too small */ { unit temp[MAX_UNIT_PRECISION]; unit DP[MAX_UNIT_PRECISION], DQ[MAX_UNIT_PRECISION]; 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; /* We are building the mpi in place, except for a possible * byte-order swap to little-endian at the end. Thus, we * need to fill the buffer with leading 0's in the unused * most significant byte positions. */ blocksize = countbytes(N) - 1; /* Space available for data */ for (i = units2bytes(global_precision) - blocksize; i > 0; --i) *p++ = 0; i = blocksize - 2 - bytes; /* Padding needed */ i -= sizeof(asn_array); /* Space for type encoding */ if (i < 0) { i = -4; /* Error code */ goto Cleanup; } *p++ = MD_ENCRYPTED_BYTE; /* Type byte */ memset(p, ~0, i); /* All 1's padding */ p += i; *p++ = 0; /* Zero framing byte */ memcpy(p, asn_array, sizeof(asn_array)); /* ASN data */ p += sizeof(asn_array); memcpy(p, inbuf, bytes); /* User data */ mp_convert_order((byte *)temp); i = mp_modexp_crt(outbuf, temp, P, Q, DP, DQ, U); /* Encrypt */ if (i < 0) i = -1; 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 */ { unit temp[MAX_UNIT_PRECISION]; unsigned int blocksize; int i; byte *front, *back; i = mp_modexp(temp, inbuf, E, N); if (i < 0) { mp_burn(temp); return -1; } mp_convert_order((byte *)temp); blocksize = countbytes(N) - 1; front = (byte *)temp; /* Points to start of block */ i = units2bytes(global_precision); back = front + i; /* Points to end of block */ i -= countbytes(N) - 1; /* Expected leading 0's */ /* * Strip off the padding. This handles both PKCS and PGP 2.0 * formats. If we're using RSAREF2, we use the padding-removal * code in RSAPublicDecrypt, which accepts only PKCS style. * Oh, well. */ if (i < 0) /* This shouldn't happen */ goto ErrorReturn; while (i--) /* Extra bytes should be 0 */ if (*front++) goto ErrorReturn; /* How to distinguish old PGP from PKCS formats. * The old PGP format ends in a trailing type byte, with * all 1's padding before that. The PKCS format ends in * 16 bytes of message digest, preceded by an ASN string * which is not all 1's. */ if (back[-1] == MD_ENCRYPTED_BYTE && back[-17] == 0xff && back[-18] == 0xff) { /* Old PGP format: Padding is at the end */ if (*--back != MD_ENCRYPTED_BYTE) goto ErrorReturn; if (*front++ != MD5_ALGORITHM_BYTE) { mp_burn(temp); return -7; } while (*--back == 0xff) /* Skip constant padding */ ; if (*back) /* It should end with a zero */ goto ErrorReturn; } else { /* PKCS format: padding at the beginning */ if (*front++ != MD_ENCRYPTED_BYTE) goto ErrorReturn; while (*front++ == 0xff) /* Skip constant padding */ ; if (front[-1]) /* First non-FF byte should be 0 */ goto ErrorReturn; /* Then comes the ASN header */ 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 */ { byte *back; 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 = mp_modexp_crt(temp, inbuf, P, Q, DP, DQ, U); mp_burn(DP); mp_burn(DQ); if (i < 0) { mp_burn(temp); return -1; } mp_convert_order((byte *)temp); front = (byte *)temp; /* Start of block */ i = units2bytes(global_precision); back = (byte *)front + i; /* End of block */ blocksize = countbytes(N) - 1; i -= blocksize; /* Expected # of leading 0's */ if (i < 0) /* This shouldn't happen */ goto Corrupted; while (i--) /* Extra bytes should be 0 */ if (*front++) goto Corrupted; /* How to distinguish old PGP from PKCS formats. * PGP packets have a trailing type byte (CK_ENCRYPTED_BYTE), * while PKCS formats have it leading. */ if (front[0] != CK_ENCRYPTED_BYTE && back[-1] == CK_ENCRYPTED_BYTE) { /* PGP 2.0 format - padding at the end */ if (back[-1] != CK_ENCRYPTED_BYTE) goto Corrupted; while (*--back) /* Skip non-zero random padding */ ; } else { /* PKCS format - padding at the beginning */ if (*front++ != CK_ENCRYPTED_BYTE) goto Corrupted; while (*front++) /* Skip non-zero random padding */ ; } if (back <= front) goto Corrupted; blocksize = back-front; memcpy(outbuf, front, blocksize); mp_burn(temp); return blocksize; Corrupted: mp_burn(temp); return -9; } /* rsa_private_decrypt */
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.