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 */
static int testsimpel(void) { const char str42[] = "2a"; MINT *t2; char *s; mp_madd(c42, c1, t0); testmcmp(c43, t0, "madd0"); mp_madd(t0, c1, t0); testmcmp(c44, t0, "madd1"); mp_msub(t0, c1, t0); testmcmp(c43, t0, "msub0"); mp_msub(t0, c1, t0); testmcmp(c42, t0, "msub1"); mp_move(c42, t0); testmcmp(c42, t0, "move0"); t2 = mp_xtom(str42); testmcmp(c42, t2, "xtom"); s = mp_mtox(t2); if (strcmp(str42, s) == 0) printf("ok %d - %s\n", ++tnr, "mtox0"); else printf("not ok %d - %s\n", ++tnr, "mtox0"); mp_mfree(t2); }
/* Converts a possibly-signed digit string into a large binary number. Returns assumed radix, derived from suffix 'h','o',b','.' */ int str2reg(unitptr reg, string digitstr) { unit temp[MAX_UNIT_PRECISION], base[MAX_UNIT_PRECISION]; int c, i; boolean minus = FALSE; short radix; /* base 2-16 */ mp_init(reg, 0); i = string_length(digitstr); if (i == 0) return (10); /* empty string, assume radix 10 */ c = digitstr[i - 1]; /* get last char in string */ switch (c) { /* classify radix select suffix character */ case '.': radix = 10; break; case 'H': case 'h': radix = 16; break; case 'O': case 'o': radix = 8; break; case 'B': /* caution! 'b' is a hex digit! */ case 'b': radix = 2; break; default: radix = 10; break; } mp_init(base, radix); if ((minus = (*digitstr == '-')) != 0) digitstr++; while ((c = *digitstr++) != 0) { if (c == ',') continue; /* allow commas in number */ c = ctox(c); if ((c < 0) || (c >= radix)) break; /* scan terminated by any non-digit */ mp_mult(temp, reg, base); mp_move(reg, temp); mp_init(temp, c); mp_add(reg, temp); } if (minus) mp_neg(reg); return (radix); } /* str2reg */
/* 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 */