#include "mycrypt.h" #ifdef MDH /* This holds the key settings. ***MUST*** be organized by size from smallest to largest. */ static const struct { int size; char *name, *base, *prime; } sets[] = { #ifdef DH768 { 96, "DH-768", "2", "2893527720709661239493896562339544088620375736490408468011883030469939904368" "0860923364582982212457078989335831907131881773994018526277492109945959747917" "8279025394653904396221302707492255957231214118178743427870878320796645901947" "9487" }, #endif #ifdef DH1024 { 128, "DH-1024", "2", "3477431594398766260792527967974222231775354473882066076071816639030459075912" "0194047822362172211817327089848758298713770865641434468581617942085516098634" "0457973820182883508387588163122354089264395604796675278966117567294812714812" "7968205965648764507160662831267200108590414847865290564578963676831229604111" "36319" }, #endif #ifdef DH1280 { 160, "DH-1280", "2", "2618298020488323341377089635550383393554460131909411928885489146533597039863" "5379029297773089246854323581071445272213255646852180580463169755159411503866" "4190218001872082125570169842848154404911652982668791288605239288293106162305" "7236093554796242806887062958692596037823904832542385180840218330924392268465" "0197244314233248991982159235832322194332167923655574170280697353556560854901" "280047" }, #endif #ifdef DH1536 { 192, "DH-1536", "3", "2992593690703251306835100868059076484222548092264611010748654597096560864537" "1704684310938824733433085888971827086341295918925237859522548192211945291282" "1170570153374563548621496076860061698150233114892317627457427359445435608693" "5625000902194809114890745455404045166957722404567939575618007347432055137282" "3291711752537781447636541738638119983678441628437171377508654097130147131310" "9209393805685590941710151477648542896503595482724205166251069428524927527085" "2602467" }, #endif #ifdef DH1792 { 224, "DH-1792", "2", "3210090394251532205679207425273650879078185529033544241951292722086520015900" "0402371844205168176419829949232601235193754977706171541009393172204470047690" "6659627844880912479392592056697278305733615369406596661203184035142652643118" "1379603333858737848321053048184938839622944591194935387992479717305577175500" "2554620614907177847128950276247571809502831255425929468853285490357704941968" "3407102520889651917659577334897408316217748346860775479727332331727022096550" "7718799868459391361770854814013613619048768630587629568449528005570971478547" "34960319" }, #endif #ifdef DH2048 { 256, "DH-2048", "2", "4726642895635639316469736509812041897640060270607231273592407174543853221823" "7979333351774907308168340693326687317443721193266215155735814510792148768576" "4984911991227443513994894535335532038333186916782632419417062569961974604240" "2901241901263467186228353234265630967717360250949841797609150915436003989316" "5037637034737020327399910409885798185771003505320583967737293415979917317338" "9858373857347474783642420203804168920566508414708692945275435973492502995396" "8243060517332102902655554683247304860032703684578197028928889831788842751736" "4945316709081173840186150794397479045034008257793436817683392375274635794835" "245695887" }, #endif #ifdef DH2560 { 320, "DH-2560", "3", "4364638085059577685748948703943497396233464406019459611612544400721432981520" "4010567649104824811014627875285783993051576616744140702150122992472133564455" "7342265864606569000117714935185566842453630868849121480179691838399545644365" "5711067577313173717585579907818806913366955847993133136872874688941488237617" "8558298254958618375680644901754262226787427510387748147553499120184991222267" "0102069951687572917937634467778042874315463238062009202992087620963771759666" "4482665328580794026699200252242206134194410697184828373996126449788399252071" "0987084027819404215874884544513172913711709852902888677006373648742061314404" "5836803985635654192482395882603511950547826439092832800532152534003936926017" "6124466061356551464456206233957889787267447285030586700468858762515271223502" "75750995227" }, #endif #ifdef DH3072 { 384, "DH-3072", "2", "1142416747335183639807830604262436227795642944052113706188970261176634876069" "2206243140413411077394583180726863277012016602279290144126785129569474909173" "5847898223419867427192303319460727303195559844849117167970588759054009995043" "0587724584911968750902323279027363746682105257685923245298206183100977078603" "1785669030271542286603956118755585683996118896215213488875253101894663403069" "6777459483058938495054342017637452328957807119724320113448575216910178963168" "6140320644942133224365885545343578400651720289418164056243357539082138421096" "0117518650374602256601091379644034244332285065935413233557998331562749140202" "9658442193362989700115138825649355387042894469683222814519074873620465114612" "2132979989735099337056069750580968643878203623537213701573130477907243026098" "6460269894522159103008260495503005267165927542949439526272736586626709581721" "0321895327263896436255906801057848442461527026701693042037830722750891947548" "89511973916207" }, #endif #ifdef DH4096 { 512, "DH-4096", "3", "1214855636816562637502584060163403830270705000634713483015101384881871978446" "8012247985361554068958233050354675916325310675478909486951171720769542207270" "7568804875102242119871203284889005635784597424656074834791863005085393369779" "2254955890439720297560693579400297062396904306270145886830719309296352765295" "7121830407731464190228751653827780070401099576097395898755908857011261979060" "6362013395489321661267883850754077713843779770560245371955901763398648664952" "3611975865005712371194067612263330335590526176087004421363598470302731349138" "7732059014477046821815179040647356365184624522427916765417252923789255682968" "5801015185232631677751193503753101741391050692192245066693320227848902452126" "3798482237150056835746454842662048692127173834433089016107854491097456725016" "3277096631997382384421648431471327891537255132571679155551620949708535844479" "9312548860769600816980737473671129700747381225627224548940589847029717873802" "9484459690836250560495461579533254473316340608217876781986188705928270735695" "7528308255279638383554197625162460286802809880204019145518254873499903069763" "0409310938445143881325121105159739212749146489879740678917545306796007200859" "0614886532333015881171367104445044718144312416815712216611576221546455968770" "801413440778423979" }, #endif { 0, NULL, NULL, NULL } }; static int is_valid_idx(int n) { int x; for (x = 0; sets[x].size; x++); if ((n < 0) || (n >= x)) { return 0; } return 1; } int dh_test(void) { mp_int p, g, tmp; int x, res, primality; if (mp_init_multi(&p, &g, &tmp, NULL) != MP_OKAY) { goto error; } for (x = 0; sets[x].size; x++) { #if 0 printf("dh_test():testing size %d-bits\n", sets[x].size * 8); #endif /* see if g^((p-1)/2) == 1 mod p. */ if (mp_read_radix(&g, sets[x].base, 10) != MP_OKAY) { goto error; } if (mp_read_radix(&p, sets[x].prime, 10) != MP_OKAY) { goto error; } /* ensure p is prime */ if ((res = is_prime(&p, &primality)) != CRYPT_OK) { goto done; } if (primality == 0) { res = CRYPT_FAIL_TESTVECTOR; goto done; } if (mp_sub_d(&p, 1, &tmp) != MP_OKAY) { goto error; } if (mp_div_2(&tmp, &tmp) != MP_OKAY) { goto error; } /* ensure (p-1)/2 is prime */ if ((res = is_prime(&tmp, &primality)) != CRYPT_OK) { goto done; } if (primality == 0) { res = CRYPT_FAIL_TESTVECTOR; goto done; } /* now see if g^((p-1)/2) mod p is in fact 1 */ if (mp_exptmod(&g, &tmp, &p, &tmp) != MP_OKAY) { goto error; } if (mp_cmp_d(&tmp, 1)) { res = CRYPT_FAIL_TESTVECTOR; goto done; } } res = CRYPT_OK; goto done; error: res = CRYPT_MEM; done: mp_clear_multi(&tmp, &g, &p, NULL); return res; } void dh_sizes(int *low, int *high) { int x; _ARGCHK(low != NULL); _ARGCHK(high != NULL); *low = INT_MAX; *high = 0; for (x = 0; sets[x].size; x++) { if (*low > sets[x].size) *low = sets[x].size; if (*high < sets[x].size) *high = sets[x].size; } } int dh_get_size(dh_key *key) { _ARGCHK(key != NULL); if (is_valid_idx(key->idx)) return sets[key->idx].size; else return INT_MAX; /* large value that would cause dh_make_key() to fail */ } int dh_make_key(prng_state *prng, int wprng, int keysize, dh_key *key) { unsigned char buf[768]; unsigned long x; mp_int p, g; int res, errno; _ARGCHK(key != NULL); /* good prng? */ if ((errno = prng_is_valid(wprng)) != CRYPT_OK) { return errno; } /* find key size */ for (x = 0; (keysize > sets[x].size) && (sets[x].size); x++); #ifdef FAST_PK keysize = MIN(sets[x].size, 32); #else keysize = sets[x].size; #endif if (sets[x].size == 0) { return CRYPT_INVALID_KEYSIZE; } key->idx = x; /* make up random string */ buf[0] = 0; if (prng_descriptor[wprng].read(buf+1, keysize, prng) != (unsigned long)keysize) { return CRYPT_ERROR_READPRNG; } /* init parameters */ if (mp_init_multi(&g, &p, &key->x, &key->y, NULL) != MP_OKAY) { return CRYPT_MEM; } if (mp_read_radix(&g, sets[x].base, 10) != MP_OKAY) { goto error2; } if (mp_read_radix(&p, sets[x].prime, 10) != MP_OKAY) { goto error2; } /* load the x value */ mp_read_raw(&key->x, buf, keysize+1); if (mp_exptmod(&g, &key->x, &p, &key->y) != MP_OKAY) { goto error2; } key->type = PK_PRIVATE; /* free up ram */ res = CRYPT_OK; goto done2; error2: res = CRYPT_MEM; mp_clear_multi(&key->x, &key->y, NULL); done2: mp_clear_multi(&p, &g, NULL); zeromem(buf, sizeof(buf)); return res; } void dh_free(dh_key *key) { _ARGCHK(key != NULL); mp_clear_multi(&key->x, &key->y, NULL); } #define OUTPUT_BIGNUM(num, buf2, y, z) \ { \ z = mp_raw_size(num); \ STORE32L(z, buf2+y); \ y += 4; \ mp_toraw(num, buf2+y); \ y += z; \ } #define INPUT_BIGNUM(num, in, x, y) \ { \ /* load value */ \ LOAD32L(x, in+y); \ y += 4; \ \ /* sanity check... */ \ if (x > 1024) { \ errno = CRYPT_ERROR; \ goto error; \ } \ \ /* load it */ \ if (mp_read_raw(num, (unsigned char *)in+y, x) != MP_OKAY) {\ return CRYPT_MEM; \ goto error; \ } \ y += x; \ } int dh_export(unsigned char *out, unsigned long *outlen, int type, dh_key *key) { unsigned char buf2[1536]; unsigned long y, z; _ARGCHK(out != NULL); _ARGCHK(outlen != NULL); _ARGCHK(key != NULL); if (type == PK_PRIVATE && key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* header */ y = PACKET_SIZE; /* header */ buf2[y++] = type; buf2[y++] = sets[key->idx].size / 8; /* export y */ OUTPUT_BIGNUM(&key->y, buf2, y, z); if (type == PK_PRIVATE) { /* export x */ OUTPUT_BIGNUM(&key->x, buf2, y, z); } /* check for overflow */ if (*outlen < y) { #ifdef CLEAN_STACK zeromem(buf2, sizeof(buf2)); #endif return CRYPT_BUFFER_OVERFLOW; } /* store header */ packet_store_header(buf2, PACKET_SECT_DH, PACKET_SUB_KEY, y); /* output it */ *outlen = y; memcpy(out, buf2, y); /* clear mem */ zeromem(buf2, sizeof(buf2)); return CRYPT_OK; } int dh_import(const unsigned char *in, dh_key *key) { long x, y, s; int errno; _ARGCHK(in != NULL); _ARGCHK(key != NULL); /* check type byte */ if ((errno = packet_valid_header((unsigned char *)in, PACKET_SECT_DH, PACKET_SUB_KEY)) != CRYPT_OK) { return errno; } /* init */ if (mp_init_multi(&key->x, &key->y, NULL) != MP_OKAY) { return CRYPT_MEM; } y = PACKET_SIZE; key->type = in[y++]; s = (long)in[y++] * 8; for (x = 0; (s > sets[x].size) && (sets[x].size); x++); if (sets[x].size == 0) { errno = CRYPT_INVALID_KEYSIZE; goto error; } key->idx = x; /* type check both values */ if ((key->type != PK_PUBLIC) && (key->type != PK_PRIVATE)) { errno = CRYPT_PK_TYPE_MISMATCH; goto error; } /* is the key idx valid? */ if (!is_valid_idx(key->idx)) { errno = CRYPT_PK_TYPE_MISMATCH; goto error; } /* load public value g^x mod p*/ INPUT_BIGNUM(&key->y, in, x, y); if (key->type == PK_PRIVATE) { INPUT_BIGNUM(&key->x, in, x, y); } return CRYPT_OK; error: mp_clear_multi(&key->y, &key->x, NULL); return errno; } int dh_shared_secret(dh_key *private_key, dh_key *public_key, unsigned char *out, unsigned long *outlen) { mp_int tmp, p; unsigned long x; int res; _ARGCHK(private_key != NULL); _ARGCHK(public_key != NULL); _ARGCHK(out != NULL); _ARGCHK(outlen != NULL); /* types valid? */ if (private_key->type != PK_PRIVATE) { return CRYPT_PK_NOT_PRIVATE; } /* same idx? */ if (private_key->idx != public_key->idx) { return CRYPT_PK_TYPE_MISMATCH; } /* compute y^x mod p */ if (mp_init_multi(&tmp, &p, NULL) != MP_OKAY) { return CRYPT_MEM; } if (mp_read_radix(&p, sets[private_key->idx].prime, 10) != MP_OKAY) { goto error; } if (mp_exptmod(&public_key->y, &private_key->x, &p, &tmp) != MP_OKAY) { goto error; } /* enough space for output? */ x = mp_raw_size(&tmp); if (*outlen < x) { res = CRYPT_BUFFER_OVERFLOW; goto done; } mp_toraw(&tmp, out); *outlen = x; res = CRYPT_OK; goto done; error: res = CRYPT_MEM; done: mp_clear_multi(&p, &tmp, NULL); return res; } #include "dh_sys.c" #endif