#ifdef _WIN32 #ifndef _CONSOLE #include "stdafx.h" #endif #endif #include "rsalib1.h" CRSALib::CRSALib(short glob_pres) { global_precision = glob_pres; int i, j; for (i=0; i< 16; i++) for (j=0; j< MAX_UNIT_PRECISION; j++) moduli_buf[i][j]=0; moduli[0] = 0; for (i=1; i<16+1; i++) moduli[i] = &moduli_buf[ i-1][0]; for (i=0;i<16+1;i++) { msu_moduli[i] = 0; nmsu_moduli[i] = 0; } for (i=0; i< 16-1; i++) for (j=0; j< MAX_UNIT_PRECISION; j++) mpdbuf[i][j]=0; mpd[0] = 0; for (i=1; i < 16; i++) { mpd[i] = &mpdbuf[ i-1][0]; } } boolean CRSALib::mp_addc(register unitptr r1,register unitptr r2,register boolean carry) { register ulint x; short precision; precision = global_precision; while (precision--) { x = (ulint) *r1 + (ulint) *((r2)++) + (ulint) carry; *((r1)++) = (unit)x; carry = ((x & ((ulint) 1 << 16)) != 0L); } return(carry); } boolean CRSALib::mp_subb(register unitptr r1,register unitptr r2,register boolean borrow) { register ulint x; short precision; precision = global_precision; while (precision--) { x = (ulint) *r1 - (ulint) *((r2)++) - (ulint) borrow; *((r1)++) = (unit)x; borrow = ((x & ((ulint) 1 << 16)) != 0L); } return(borrow); } boolean CRSALib::mp_rotate_left(register unitptr r1,register boolean carry) { register short precision; register boolean nextcarry; precision = global_precision; while (precision--) { nextcarry = (((signedunit) *r1) < 0); *r1 <<= 1 ; if (carry) *r1 |= 1; carry = nextcarry; (++(r1)); } return(nextcarry); } boolean CRSALib::mp_rotate_right(register unitptr r1,register boolean carry) { register short precision; register boolean nextcarry; precision = global_precision; (r1) = ((r1)+(precision)-1); while (precision--) { nextcarry = *r1 & 1; *r1 >>= 1 ; if (carry) *r1 |= ((unit) 0x8000); carry = nextcarry; (--(r1)); } return(nextcarry); } short CRSALib::mp_compare(register unitptr r1,register unitptr r2) { register short precision; precision = global_precision; (r1) = ((r1)+(precision)-1); (r2) = ((r2)+(precision)-1); do { if (*r1 < *r2) return(-1); if (*((r1)--) > *((r2)--)) return(1); } while (--precision); return(0); } boolean CRSALib::mp_inc(register unitptr r) { register short precision; precision = global_precision; do { if ( ++(*r) ) return(0); ((r)++); } while (--precision); return(1); } boolean CRSALib::mp_dec(register unitptr r) { register short precision; precision = global_precision; do { if ( (signedunit) (--(*r)) != (signedunit) -1 ) return(0); ((r)++); } while (--precision); return(1); } void CRSALib::mp_neg(register unitptr r) { register short precision; precision = global_precision; mp_dec(r); do { *r = ~(*r); r++; } while (--precision); } void CRSALib::mp_move(register unitptr dst,register unitptr src) { register short precision; precision = global_precision; do { *dst++ = *src++; } while (--precision); } void CRSALib::mp_init(register unitptr r, word16 value) { register short precision; precision = global_precision; *((r)++) = value; precision--; while (precision--) *((r)++) = 0; } short CRSALib::significance(register unitptr r) { register short precision; precision = global_precision; (r) = ((r)+(precision)-1); do { if (*((r)--)) return(precision); } while (--precision); return(precision); } void CRSALib::unitfill0(unitptr r,word16 unitcount) { while (unitcount--) *r++ = 0; } int CRSALib::mp_udiv(register unitptr remainder,register unitptr quotient, register unitptr dividend,register unitptr divisor) { int bits; short dprec; register unit bitmask; if (( ((*(divisor))==(0)) && (significance(divisor)<=1) )) return(-1); mp_init(remainder,0); mp_init(quotient,0); { dprec = significance(dividend); if (!dprec) return(0); bits = ((dprec) << 4); (dividend) = ((dividend)+(dprec)-1); bitmask = ((unit) 0x8000); while (!(*(dividend) & bitmask)) { bitmask >>= 1; bits--; } }; (quotient) = ((quotient)+(dprec)-1); while (bits--) { mp_rotate_left(remainder,(boolean)((*(dividend) & bitmask)!=0)); if (mp_compare(remainder,divisor) >= 0) { mp_subb(remainder,divisor,(boolean)0); *(quotient) |= bitmask; } { if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((dividend)--); ((quotient)--); } }; } return(0); } int CRSALib::mp_div(register unitptr remainder,register unitptr quotient, register unitptr dividend,register unitptr divisor) { boolean dvdsign,dsign; int status; dvdsign = (((signedunit) (*((dividend)+(global_precision)-1)) < 0)!=0); dsign = (((signedunit) (*((divisor)+(global_precision)-1)) < 0)!=0); if (dvdsign) mp_neg(dividend); if (dsign) mp_neg(divisor); status = mp_udiv(remainder,quotient,dividend,divisor); if (dvdsign) mp_neg(dividend); if (dsign) mp_neg(divisor); if (status<0) return(status); if (dvdsign) mp_neg(remainder); if (dvdsign ^ dsign) mp_neg(quotient); return(status); } word16 CRSALib::mp_shortdiv(register unitptr quotient, register unitptr dividend,register word16 divisor) { int bits; short dprec; register unit bitmask; register word16 remainder; if (!divisor) return(-1); remainder=0; mp_init(quotient,0); { dprec = significance(dividend); if (!dprec) return(0); bits = ((dprec) << 4); (dividend) = ((dividend)+(dprec)-1); bitmask = ((unit) 0x8000); while (!(*(dividend) & bitmask)) { bitmask >>= 1; bits--; } }; (quotient) = ((quotient)+(dprec)-1); while (bits--) { remainder <<= 1; if ((*(dividend) & bitmask)) remainder++; if (remainder >= divisor) { remainder -= divisor; *(quotient) |= bitmask; } { if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((dividend)--); ((quotient)--); } }; } return(remainder); } int CRSALib::mp_mod(register unitptr remainder, register unitptr dividend,register unitptr divisor) { int bits; short dprec; register unit bitmask; if (( ((*(divisor))==(0)) && (significance(divisor)<=1) )) return(-1); mp_init(remainder,0); { dprec = significance(dividend); if (!dprec) return(0); bits = ((dprec) << 4); (dividend) = ((dividend)+(dprec)-1); bitmask = ((unit) 0x8000); while (!(*(dividend) & bitmask)) { bitmask >>= 1; bits--; } }; while (bits--) { mp_rotate_left(remainder,(boolean)((*(dividend) & bitmask)!=0)); if (mp_compare(remainder,divisor) >= 0) mp_subb(remainder,divisor,(boolean)0); { if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((dividend)--); } }; } return(0); } word16 CRSALib::mp_shortmod(register unitptr dividend,register word16 divisor) { int bits; short dprec; register unit bitmask; register word16 remainder; if (!divisor) return(-1); remainder=0; { dprec = significance(dividend); if (!dprec) return(0); bits = ((dprec) << 4); (dividend) = ((dividend)+(dprec)-1); bitmask = ((unit) 0x8000); while (!(*(dividend) & bitmask)) { bitmask >>= 1; bits--; } }; while (bits--) { remainder <<= 1; if ((*(dividend) & bitmask)) remainder++; if (remainder >= divisor) remainder -= divisor; { if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((dividend)--); } }; } return(remainder); } int CRSALib::mp_mult(register unitptr prod, register unitptr multiplicand,register unitptr multiplier) { int bits; register unit bitmask; short mprec; mp_init(prod,0); if (( ((*(multiplicand))==(0)) && (significance(multiplicand)<=1) )) return(0); mprec = significance(multiplier); if (!mprec) return(0); bits = ((mprec) << 4); (multiplier) = ((multiplier)+(mprec)-1); bitmask = ((unit) 0x8000); while (!(*(multiplier) & bitmask)) { bitmask >>= 1; bits--; } while (bits--) { mp_rotate_left(prod,(boolean)0); if ((*(multiplier) & bitmask)) { mp_addc(prod,multiplicand,(boolean)0); } if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((multiplier)--); } } return(0); } void CRSALib::mp_lshift_unit(register unitptr r1) { register short precision; register unitptr r2; precision = global_precision; (r1) = ((r1)+(precision)-1); r2 = r1; while (--precision) *((r1)--) = *(--(r2)); *r1 = 0; } void CRSALib::stage_mp_images(unitptr images[16],unitptr r) { short int i; images[0] = r; for (i=1; i<16; i++) { mp_move(images[i],images[i-1]); mp_rotate_left(images[i],(boolean)0); } } int CRSALib::stage_merritt_modulus(unitptr n) { short int i; unitptr msu; moduli[0] = n; msu = ((n)+(global_precision)-1); msu_moduli[0] = *((msu)--); nmsu_moduli[0] = *msu; for (i=1; i<16+1; i++) { mp_move(moduli[i],moduli[i-1]); mp_rotate_left(moduli[i],(boolean)0); msu = ((moduli[i])+(global_precision)-1); msu_moduli[i] = *((msu)--); nmsu_moduli[i] = *msu; } return(0); } int CRSALib::merritt_modmult(register unitptr prod, unitptr multiplicand,register unitptr multiplier) { register signedunit p_m; register unitptr msu_prod; register unitptr nmsu_prod; short mprec; stage_mp_images(mpd,multiplicand); msu_prod = ((prod)+(global_precision)-1); nmsu_prod = msu_prod; ((nmsu_prod)--); mp_init(prod,0); mprec = significance(multiplier); if (mprec==0) return(0); (multiplier) = ((multiplier)+(mprec)-1); while (mprec--) { mp_lshift_unit(prod); if (*multiplier & ((unit) 1 << (15))) mp_addc(prod,mpd[15],(boolean)0); if (*multiplier & ((unit) 1 << (14))) mp_addc(prod,mpd[14],(boolean)0); if (*multiplier & ((unit) 1 << (13))) mp_addc(prod,mpd[13],(boolean)0); if (*multiplier & ((unit) 1 << (12))) mp_addc(prod,mpd[12],(boolean)0); if (*multiplier & ((unit) 1 << (11))) mp_addc(prod,mpd[11],(boolean)0); if (*multiplier & ((unit) 1 << (10))) mp_addc(prod,mpd[10],(boolean)0); if (*multiplier & ((unit) 1 << (9))) mp_addc(prod,mpd[9],(boolean)0); if (*multiplier & ((unit) 1 << (8))) mp_addc(prod,mpd[8],(boolean)0); if (*multiplier & ((unit) 1 << (7))) mp_addc(prod,mpd[7],(boolean)0); if (*multiplier & ((unit) 1 << (6))) mp_addc(prod,mpd[6],(boolean)0); if (*multiplier & ((unit) 1 << (5))) mp_addc(prod,mpd[5],(boolean)0); if (*multiplier & ((unit) 1 << (4))) mp_addc(prod,mpd[4],(boolean)0); if (*multiplier & ((unit) 1 << (3))) mp_addc(prod,mpd[3],(boolean)0); if (*multiplier & ((unit) 1 << (2))) mp_addc(prod,mpd[2],(boolean)0); if (*multiplier & ((unit) 1 << (1))) mp_addc(prod,mpd[1],(boolean)0); if (*multiplier & ((unit) 1 << (0))) mp_addc(prod,mpd[0],(boolean)0); if (((p_m = *msu_prod-msu_moduli[16])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[16]) || ( (*nmsu_prod==nmsu_moduli[16]) && ((mp_compare(prod,moduli[16]) >= 0)) ))) ) mp_subb(prod,moduli[16],(boolean)0); if (((p_m = *msu_prod-msu_moduli[15])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[15]) || ( (*nmsu_prod==nmsu_moduli[15]) && ((mp_compare(prod,moduli[15]) >= 0)) ))) ) mp_subb(prod,moduli[15],(boolean)0); if (((p_m = *msu_prod-msu_moduli[14])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[14]) || ( (*nmsu_prod==nmsu_moduli[14]) && ((mp_compare(prod,moduli[14]) >= 0)) ))) ) mp_subb(prod,moduli[14],(boolean)0); if (((p_m = *msu_prod-msu_moduli[13])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[13]) || ( (*nmsu_prod==nmsu_moduli[13]) && ((mp_compare(prod,moduli[13]) >= 0)) ))) ) mp_subb(prod,moduli[13],(boolean)0); if (((p_m = *msu_prod-msu_moduli[12])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[12]) || ( (*nmsu_prod==nmsu_moduli[12]) && ((mp_compare(prod,moduli[12]) >= 0)) ))) ) mp_subb(prod,moduli[12],(boolean)0); if (((p_m = *msu_prod-msu_moduli[11])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[11]) || ( (*nmsu_prod==nmsu_moduli[11]) && ((mp_compare(prod,moduli[11]) >= 0)) ))) ) mp_subb(prod,moduli[11],(boolean)0); if (((p_m = *msu_prod-msu_moduli[10])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[10]) || ( (*nmsu_prod==nmsu_moduli[10]) && ((mp_compare(prod,moduli[10]) >= 0)) ))) ) mp_subb(prod,moduli[10],(boolean)0); if (((p_m = *msu_prod-msu_moduli[9])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[9]) || ( (*nmsu_prod==nmsu_moduli[9]) && ((mp_compare(prod,moduli[9]) >= 0)) ))) ) mp_subb(prod,moduli[9],(boolean)0); if (((p_m = *msu_prod-msu_moduli[8])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[8]) || ( (*nmsu_prod==nmsu_moduli[8]) && ((mp_compare(prod,moduli[8]) >= 0)) ))) ) mp_subb(prod,moduli[8],(boolean)0); if (((p_m = *msu_prod-msu_moduli[7])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[7]) || ( (*nmsu_prod==nmsu_moduli[7]) && ((mp_compare(prod,moduli[7]) >= 0)) ))) ) mp_subb(prod,moduli[7],(boolean)0); if (((p_m = *msu_prod-msu_moduli[6])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[6]) || ( (*nmsu_prod==nmsu_moduli[6]) && ((mp_compare(prod,moduli[6]) >= 0)) ))) ) mp_subb(prod,moduli[6],(boolean)0); if (((p_m = *msu_prod-msu_moduli[5])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[5]) || ( (*nmsu_prod==nmsu_moduli[5]) && ((mp_compare(prod,moduli[5]) >= 0)) ))) ) mp_subb(prod,moduli[5],(boolean)0); if (((p_m = *msu_prod-msu_moduli[4])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[4]) || ( (*nmsu_prod==nmsu_moduli[4]) && ((mp_compare(prod,moduli[4]) >= 0)) ))) ) mp_subb(prod,moduli[4],(boolean)0); if (((p_m = *msu_prod-msu_moduli[3])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[3]) || ( (*nmsu_prod==nmsu_moduli[3]) && ((mp_compare(prod,moduli[3]) >= 0)) ))) ) mp_subb(prod,moduli[3],(boolean)0); if (((p_m = *msu_prod-msu_moduli[2])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[2]) || ( (*nmsu_prod==nmsu_moduli[2]) && ((mp_compare(prod,moduli[2]) >= 0)) ))) ) mp_subb(prod,moduli[2],(boolean)0); if (((p_m = *msu_prod-msu_moduli[1])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[1]) || ( (*nmsu_prod==nmsu_moduli[1]) && ((mp_compare(prod,moduli[1]) >= 0)) ))) ) mp_subb(prod,moduli[1],(boolean)0); if (((p_m = *msu_prod-msu_moduli[0])>0) || ( (p_m==0) && ( (*nmsu_prod>nmsu_moduli[0]) || ( (*nmsu_prod==nmsu_moduli[0]) && ((mp_compare(prod,moduli[0]) >= 0)) ))) ) mp_subb(prod,moduli[0],(boolean)0); ((multiplier)--); } return(0); } void CRSALib::merritt_burn(void) { unitfill0(&(mpdbuf[0][0]),(16-1)*(MAX_UNIT_PRECISION)); unitfill0(&(moduli_buf[0][0]),(16)*(MAX_UNIT_PRECISION)); unitfill0(msu_moduli,16+1); unitfill0(nmsu_moduli,16+1); } int CRSALib::countbits(unitptr r) { int bits; short prec; register unit bitmask; { prec = significance(r); if (!prec) return(0); bits = ((prec) << 4); (r) = ((r)+(prec)-1); bitmask = ((unit) 0x8000); while (!(*(r) & bitmask)) { bitmask >>= 1; bits--; } }; return(bits); } int CRSALib::mp_modexp(register unitptr expout,register unitptr expin, register unitptr exponent,register unitptr modulus) { int bits; short oldprecision; register unit bitmask; unit product[(MAX_UNIT_PRECISION)]; short eprec; mp_init(expout,1); if (( ((*(exponent))==(0)) && (significance(exponent)<=1) )) { if (( ((*(expin))==(0)) && (significance(expin)<=1) )) return(-1); return(0); } if (( ((*(modulus))==(0)) && (significance(modulus)<=1) )) return(-2); if (((signedunit) (*((modulus)+(global_precision)-1)) < 0)) return(-2); if (mp_compare(expin,modulus) >= 0) return(-3); if (mp_compare(exponent,modulus) >= 0) return(-4); oldprecision = global_precision; (global_precision = ((((countbits(modulus)+(16+1))+15) >> 4))); if (stage_merritt_modulus(modulus)) { (global_precision = (oldprecision)); return(-5); } { eprec = significance(exponent); if (!eprec) return(0); bits = ((eprec) << 4); (exponent) = ((exponent)+(eprec)-1); bitmask = ((unit) 0x8000); while (!(*(exponent) & bitmask)) { bitmask >>= 1; bits--; } }; bits--; mp_move(expout,expin); { if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((exponent)--); } }; while (bits--) { merritt_modmult(product,expout,expout); mp_move(expout,product); if ((*(exponent) & bitmask)) { merritt_modmult(product,expout,expin); mp_move(expout,product); } if (!(bitmask >>= 1)) { bitmask = ((unit) 0x8000); ((exponent)--); } } mp_init(product,0); merritt_burn(); (global_precision = (oldprecision)); return(0); } int CRSALib::rsa_decrypt(unitptr M, unitptr C, unitptr d, unitptr p, unitptr q, unitptr u) { unit p2[(MAX_UNIT_PRECISION)]; unit q2[(MAX_UNIT_PRECISION)]; unit temp1[(MAX_UNIT_PRECISION)]; unit temp2[(MAX_UNIT_PRECISION)]; int status; mp_init(M,1); if (mp_compare(p,q) >= 0) { unitptr t; t = p; p = q; q = t; } mp_move(temp1,p); mp_dec(temp1); mp_mod(temp2,d,temp1); mp_mod(temp1,C,p); status = mp_modexp(p2,temp1,temp2,p); if (status < 0) return(status); mp_move(temp1,q); mp_dec(temp1); mp_mod(temp2,d,temp1); mp_mod(temp1,C,q); status = mp_modexp(q2,temp1,temp2,q); if (status < 0) return(status); if (mp_compare(p2,q2) == 0) mp_move(M,p2); else { if (mp_subb(q2,p2,(boolean)0)) mp_addc(q2,q,(boolean)0); mp_mult(temp1,q2,u); mp_mod(temp2,temp1,q); mp_mult(temp1,p,temp2); mp_addc(temp1,p2,(boolean)0); mp_move(M,temp1); } mp_init(p2,0); mp_init(q2,0); mp_init(temp1,0); mp_init(temp2,0); return(0); } int CRSALib::mp_sqrt(unitptr quotient,unitptr dividend) { register char next2bits; register unit dvdbitmask,qbitmask; unit remainder[(MAX_UNIT_PRECISION)],rjq[(MAX_UNIT_PRECISION)], divisor[(MAX_UNIT_PRECISION)]; unsigned int qbits,qprec,dvdbits,dprec,oldprecision; int notperfect; mp_init(quotient,0); if (((signedunit) (*((dividend)+(global_precision)-1)) < 0)) { mp_dec(quotient); return(-1); } { dprec = significance(dividend); if (!dprec) return(0); dvdbits = ((dprec) << 4); (dividend) = ((dividend)+(dprec)-1); dvdbitmask = ((unit) 0x8000); while (!(*(dividend) & dvdbitmask)) { dvdbitmask >>= 1; dvdbits--; } }; if (dvdbits==1) { mp_init(quotient,1); return(0); } qbits = (dvdbits+1) >> 1; qprec = (((qbits)+15) >> 4); (quotient) = ((quotient)+(qprec)-1); qbitmask = ((unit) 1 << ((qbits-1) & (16-1))) ; oldprecision = global_precision; (global_precision = ((((qbits+3)+15) >> 4))); *(quotient) |= qbitmask; { if (!(qbitmask >>= 1)) { qbitmask = ((unit) 0x8000); ((quotient)--); } }; mp_init(rjq,1); if (!(dvdbits & 1)) { next2bits = 2; { if (!(dvdbitmask >>= 1)) { dvdbitmask = ((unit) 0x8000); ((dividend)--); } }; dvdbits--; if ((*(dividend) & dvdbitmask)) next2bits++; { if (!(dvdbitmask >>= 1)) { dvdbitmask = ((unit) 0x8000); ((dividend)--); } }; dvdbits--; } else { next2bits = 1; { if (!(dvdbitmask >>= 1)) { dvdbitmask = ((unit) 0x8000); ((dividend)--); } }; dvdbits--; } mp_init(remainder,next2bits-1); while (dvdbits) { next2bits=0; if ((*(dividend) & dvdbitmask)) next2bits=2; { if (!(dvdbitmask >>= 1)) { dvdbitmask = ((unit) 0x8000); ((dividend)--); } }; dvdbits--; if ((*(dividend) & dvdbitmask)) next2bits++; if (!(dvdbitmask >>= 1)) { dvdbitmask = ((unit) 0x8000); ((dividend)--); } dvdbits--; mp_rotate_left(remainder,(boolean)((next2bits&2)!=0)); mp_rotate_left(remainder,(boolean)((next2bits&1)!=0)); mp_move(divisor,rjq); mp_rotate_left(divisor,0); mp_rotate_left(divisor,1); if (mp_compare(remainder,divisor) >= 0) { mp_subb(remainder,divisor,(boolean)0); *(quotient) |= qbitmask; mp_rotate_left(rjq,1); } else mp_rotate_left(rjq,0); if (!(qbitmask >>= 1)) { qbitmask = ((unit) 0x8000); ((quotient)--); } } notperfect = ( ((*(remainder))!=(0)) || (significance(remainder)>1) ); (global_precision = (oldprecision)); return(notperfect); }