488 lines
15 KiB
C
488 lines
15 KiB
C
#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
|
|
|