--- pgp/src/mpiio.c 2018/04/24 16:38:42 1.1.1.2 +++ pgp/src/mpiio.c 2018/04/24 16:39:25 1.1.1.3 @@ -39,6 +39,11 @@ #include "mpiio.h" #include "pgp.h" +static void puthexbyte(byte b); /* Put out byte in ASCII hex via putchar. */ +static +void puthexw16(word16 w); /* Put out 16-bit word in hex, high byte first. */ +static +void putstr(string s); /* Put out null-terminated ASCII string via putchar. */ /*----------------- Following procedures relate to I/O ------------------*/ @@ -120,19 +125,19 @@ int str2reg(unitptr reg,string digitstr) separately compiled. */ -void putstr(string s) +static void putstr(string s) /* Put out null-terminated ASCII string via putchar. */ { while (*s) putchar(*s++); } /* putstr */ -void puthexbyte(byte b) +static void puthexbyte(byte b) /* Put out byte in ASCII hex via putchar. */ { static char *nibs = "0123456789ABCDEF"; putchar(nibs[b >> 4]); putchar(nibs[b & 0x0F]); } /* puthexbyte */ -void puthexw16(word16 w) +static void puthexw16(word16 w) /* Put out 16-bit word in hex, high byte first. */ { puthexbyte((byte)(w >> 8)); puthexbyte((byte)(w & 0xFF)); @@ -329,13 +334,9 @@ word16 fetch_word16(byte *buf) buf points to external-format byteorder array. */ { word16 w0,w1; -#ifdef XLOWFIRST - w0 = *buf++; - w1 = *buf++; -#else +/* Assume MSB external byte ordering */ w1 = *buf++; w0 = *buf++; -#endif return(w0 + (w1<<8)); } /* fetch_word16 */ @@ -346,15 +347,10 @@ byte *put_word16(word16 w, byte *buf) buf points to external-format byteorder array. */ { -#ifdef XLOWFIRST - buf[0] = w & 0xff; - w = w>>8; - buf[1] = w & 0xff; -#else +/* Assume MSB external byte ordering */ buf[1] = w & 0xff; w = w>>8; buf[0] = w & 0xff; -#endif return(buf+2); } /* put_word16 */ @@ -364,17 +360,11 @@ word32 fetch_word32(byte *buf) buf points to external-format byteorder array. */ { word32 w0,w1,w2,w3; -#ifdef XLOWFIRST - w0 = *buf++; - w1 = *buf++; - w2 = *buf++; - w3 = *buf++; -#else +/* Assume MSB external byte ordering */ w3 = *buf++; w2 = *buf++; w1 = *buf++; w0 = *buf++; -#endif return(w0 + (w1<<8) + (w2<<16) + (w3<<24)); } /* fetch_word32 */ @@ -385,15 +375,7 @@ byte *put_word32(word32 w, byte *buf) buf points to external-format byteorder array. */ { -#ifdef XLOWFIRST - buf[0] = w & 0xff; - w = w>>8; - buf[1] = w & 0xff; - w = w>>8; - buf[2] = w & 0xff; - w = w>>8; - buf[3] = w & 0xff; -#else +/* Assume MSB external byte ordering */ buf[3] = w & 0xff; w = w>>8; buf[2] = w & 0xff; @@ -401,7 +383,6 @@ byte *put_word32(word32 w, byte *buf) buf[1] = w & 0xff; w = w>>8; buf[0] = w & 0xff; -#endif return(buf+4); } /* put_word32 */ @@ -436,13 +417,9 @@ short mpi2reg(register unitptr r,registe return(-1); /* precision overflow -- error return */ } zero_bytes = units2bytes(global_precision) - bytecount; -#ifdef XLOWFIRST - fill0(buf2+bytecount,zero_bytes); /* fill trailing zero bytes */ - i = 0; /* assumes LSB first */ -#else +/* Assume MSB external byte ordering */ fill0(buf2,zero_bytes); /* fill leading zero bytes */ i = zero_bytes; /* assumes MSB first */ -#endif while (bytecount--) buf2[i++] = *buf++; mp_convert_order(buf2); /* convert to INTERNAL byte order */ @@ -477,9 +454,8 @@ short reg2mpi(register byteptr buf,regis buf2 = buf1; mp_move((unitptr)buf2,r); mp_convert_order(buf2); /* convert to EXTERNAL byteorder */ -#ifndef XLOWFIRST +/* Assume MSB external byte ordering */ buf2 += units2bytes(global_precision) - bytecount; -#endif buf = put_word16(bitcount, buf); /* store bitcount in external byteorder */ while (bytecount--) *buf++ = *buf2++; @@ -523,6 +499,13 @@ void dump_unit_array(string s, unitptr r #endif /* ifdef DEBUG */ +/* ASN encoding for RSA/MD5 for PKCS compatibility */ +static unsigned char 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 }; +/* Count from end for zero */ +#define ASN_ZERO_END 3 + /* ** short preblock(outreg, inbuf, bytecount, modulus, randompad) ** @@ -537,6 +520,84 @@ void dump_unit_array(string s, unitptr r ** assume that random padding is only used for conventional keys. ** */ + +#ifdef PKCS_COMPAT +/* Version for compatibility with PKCS */ + +short preblock(unitptr outreg, byteptr inbuf, short bytecount, + unitptr modulus, byteptr randompad) +/* Converts plaintext block into form suitable for RSA encryption. + inbuf contains the pointer to the data to be blocked. To the + extent that it can be said to have a byte order, it should be + prepared MSB first. + Converts to an MPI in INTERNAL byte order. + Returns # of bytes remaining to process. Note that the same buffer + address may be used for both outreg and inbuf. + randompad is a pointer to a buffer of random pad bytes to use for + padding material, or NULL iff we want to use constant padding. +*/ +{ byte out[MAX_BYTE_PRECISION]; + short byte_precision,leading_zeros,remaining,blocksize,padding; + boolean mic_flag = (randompad==0); + int i,j; + + /* Our strategy is to fill the buffer in MSB-first order, then + * to call convert_order which will make it proper for an MPI. + */ + byte_precision = units2bytes(global_precision); + leading_zeros = byte_precision - countbytes(modulus) + 1; + blocksize = byte_precision - leading_zeros; + /* note that blocksize includes data plus pad bytes, if any */ + + padding = blocksize - 2 - (mic_flag?sizeof(asn_array):0) - bytecount; + + /* Remaining is # of bytes we can't do. If it's negative it's the + * number more we could have done. + */ + remaining = 1 - padding; /* Padding must be >= 1 */ + + if (remaining>0) /* Just do a part of it */ + { bytecount -= remaining; + padding = 1; + } + + /* Start filling array, MSB first */ + i = 0; + + while (leading_zeros--) + out[i++] = 0; + + /* Now we've gotten to the "mpi" part of the number */ + + /* Now the type byte */ + out[i++] = mic_flag ? MD_ENCRYPTED_BYTE : CK_ENCRYPTED_BYTE; + + /* Now padding: use either 0xff or values from randompad */ + while (padding--) + out[i++] = mic_flag ? 0xff : *randompad++; + + /* A zero to separate things */ + out [i++] = 0; + + /* Now ASN stuff if MIC (signature) */ + if (mic_flag) + for (j=0; j=0) bytecount = blocksize; - padsize = blocksize - bytecount; /* bytes of padding */ i = 0; -#ifndef XLOWFIRST +/* Assume MSB external byte ordering */ while (leading_zeros--) /* assumes MSB first */ out[i++] = 0; -#endif + while (bytecount--) /* copy user data */ out[i++] = *inbuf++; out [i++] = 0; /* Always start with a 0 for padding */ +/* Assume MSB external byte ordering */ /* Pad with either 0xff or values from randompad */ -#ifdef XLOWFIRST - while (i < blocksize - 1) -#else while (i < byte_precision - 1) -#endif out[i++] = randompad ? *randompad++ : 0xff; /* End with type byte, which we deduce from randompad */ @@ -584,15 +640,12 @@ short preblock(unitptr outreg, byteptr i /* End of padding logic */ -#ifdef XLOWFIRST - while (leading_zeros--) /* assumes LSB first */ - out[i++] = 0; -#endif mp_move(outreg,(unitptr)out); mp_burn((unitptr)out); /* burn the evidence on the stack */ mp_convert_order((byte *)outreg); /* convert outreg to INTERNAL byte order */ return(remaining); /* less than 0 if there was padding */ } /* preblock */ +#endif /* PKCS_COMPAT */ short postunblock(byteptr outbuf, unitptr inreg, unitptr modulus) @@ -602,8 +655,10 @@ short postunblock(byteptr outbuf, unitpt Note that outbuf must be at least as large as inreg. The same buffer address may be used for both outbuf and inreg. Returns positive bytecount of plaintext, or negative error status. + -1 is bad packet; -2 is unrecognized digest algorithm. */ -{ short i,byte_precision,leading_zeros,bytecount,blocksize; +{ short i,j,byte_precision,leading_zeros,bytecount; + short blocksize; boolean constpad; byte_precision = units2bytes(global_precision); @@ -614,39 +669,80 @@ short postunblock(byteptr outbuf, unitpt mp_move((unitptr)outbuf,inreg); mp_convert_order(outbuf); /* convert to EXTERNAL byte order */ + /* Determine if it is the PKCS format or the older format. + * PKCS keys must be >= 48 bytes (384 bits). DEK keys have a 2 + * as the MSB. Pre-PKCS keys and PKCS MICs have 1 there. PKCS + * MICs have a 0 at a certain point in the ASN string, a point + * where non-PKCS strings have non-zero padding. That's how we + * tell. + */ + if (byte_precision < 48 || + (outbuf[leading_zeros] == 1 && + (outbuf[byte_precision-1]==1 || outbuf[byte_precision-1]==2) && + outbuf[byte_precision-16-ASN_ZERO_END] != 0)) + { /* Pre-2.3 format */ /* Check high byte, make sure it's legal, figure out padding type */ -#ifdef XLOWFIRST - i = blocksize - 1; -#else +/* Assume MSB external byte ordering */ i = byte_precision - 1; -#endif if (outbuf[i] == MD_ENCRYPTED_BYTE) constpad = 1; else if (outbuf[i] == CK_ENCRYPTED_BYTE) constpad = 0; else - return(-1); + return(-2); /* Scan down for the 0 byte that ends padding */ while (--i > 0 && outbuf[i]) if (constpad && outbuf[i] != 0xff) return(-1); -#ifdef XLOWFIRST - bytecount = i; -#else +/* Assume MSB external byte ordering */ bytecount = i - leading_zeros; if (leading_zeros) for (i = 0; i < bytecount; ++i) outbuf[i] = outbuf[i+leading_zeros]; -#endif /* Zero out high part of buffer to make it look nice */ while (i < byte_precision) outbuf[i++] = 0; + } + else + { /* PKCS compatible format */ + /* Determine which type it is */ + i = leading_zeros; + if (outbuf[i] == MD_ENCRYPTED_BYTE) + constpad = 1; + else if (outbuf[i] == CK_ENCRYPTED_BYTE) + constpad = 0; + else + return(-1); + + /* Scan for the 0 byte that ends padding */ + while (++i