|
主要参考PKCS#1文档
利用了gmp和mhash库.
使用示例:
./rsa -k rsakey --pin password -f testin -o eout
./rsa -k rsakey --pin password -d -f eout -o dout
Key-Pair示例
- # rsakey file
- # every line should like below verbosly without #
- #p=1234345234521
- #p=0xabcd78681
- #p=071234
- # has these sections
- # p,q private prime
- # n modulus, n's length should be at least hash_len+4 bytes, the longer the better,
- # and more efficent for size.
- # the hash_len for sha1 is 20, and sha256 is 32. cur use sha1.
- # d decrypt priavte key
- # e encrypt public key
- # e=3213531385645551797655269345573485190241206387309544045384388753404578116867113921876014611339100923015091369066697829034443462519195336194839504846753773774626577528969985966217658232582247938901026223885442288817533990973400082467391172354029840157896081712524931431293739237905110365860173846145516826473720173566603102479940816595204190897685793188168701573643367447673000281308639244587618508591206234889570336933007277222902143744080839473018561732769400144090027728147701711440722839602873469978897861479886422925304985168762104108292149429656210650105528213534039327391044048786478565209414879849225257747337
- d=169258535211602407454289366564760320314234449009819175987247464020576502124431674676109820966938765248459868936451649729834408405473756699992778158122135155340959763340236569311539730618855953
- n=3356290175696944624889977359872915979764431525108550170386939121287775220471939091212620798724268489404968079532769980701058719660984642444522841248246878762394831180392646437417022723983414069327776338557319351828352982962288653043591388990548600488975194801824576739762555445519545665671552544553787647853875680072274077042431073586458592666493927202419993693748745226844065298333730440143538863306890276021012673272660746971921282501693884488811972505697716590409600692791313052443703252691607181569688328691460606100738042959614921557621790163293233102615102397781075505774943293514173712562558459824017024904519
复制代码
- /*
- /*
- * try to implments RSA and learn gmp
- *
- * gcc -lmhash -lgmp rsa.c -o rsa
- *
- */
- #include<stdio.h>
- #include<gmp.h>
- #include<mhash.h>
- #include<getopt.h>
- #include<assert.h>
- typedef struct
- {
- mpz_t n; // the RSA modulus, a positive integer
- mpz_t e; // the RSA public exponent, a positive integer
- mpz_t d; // the RSA private exponent, a positive integer
- int k; // the length in ocets of the modulus n.
- mpz_t p; // the first factor, a positive integer
- mpz_t q; // the second factor, a positive integer
- }rsa_key_t;
- typedef struct
- {
- int hLen;
- int limit;
- unsigned char *(*func)(unsigned char *t, int l);
- }hash_t;
- /*
- * formula
- * e*d \equiv 1 \mod \lambda(n) ==> e*d=1 mod (phi(n))
- * e*dP = 1 mod (p-1)
- * e*dQ = 1 mod (q-1)
- * q*qInv = 1 mod p
- */
- /*
- * I2OSP (x, xLen)
- *
- * input x nonegative integer to be converted.
- * xLen intended length of the resulting octet string.
- * output X corresponding octet string of length xLen.
- * Error: "integer too large"
- */
- // assume pool has least xLen's length!
- int i2osp(mpz_t x, unsigned char* pool, int xLen)
- {
- int s, bs;
- s=mpz_sizeinbase(x, 2);
- bs=((s+7)>>3);
- if(bs>xLen) return -2;
- memset(pool, 0, xLen-bs);
- mpz_export(pool+xLen-bs, NULL, 1, 1, 1, 0, x);
- return 1;
- }
- /*
- * OS2IP
- * Input: X octet string to be converted
- * Output: x corresponding nonnegative integer
- */
- int os2ip(mpz_t x, unsigned char *pool, int len)
- {
- mpz_import(x, len, 1, sizeof(pool[0]), 1, 0, pool);
- return 1;
- }
- inline int hrsapowm(mpz_t c, mpz_t n, mpz_t e, mpz_t m)
- {
- /* non check, just work for right case?
- if(mpz_cmp(n,m)<1 || mpz_sgn(m)==-1)
- {
- exit(17);
- return -1;
- }
- */
- mpz_powm(c, m, e, n);
- return 1;
- }
- /*
- * RSAEP ((n, e), m)
- * Input:
- * (n, e) RSA public key
- * m message representative, an integer between 0 and n 1
- * Output:
- * c ciphertext representative, an integer between 0 and n 1
- * Error: "message representative out of range"
- * Assumption: RSA public key (n, e) is valid
- */
- int rsaep(mpz_t x, rsa_key_t *K, mpz_t m)
- {
- return hrsapowm(x, K->n, K->e, m);
- }
- /*
- * RSADP (K, c)
- * Input:
- * K RSA private key, where K has one of the following forms:
- * a pair (n, d)
- * a quintuple (p, q, dP, dQ, qInv) and
- * a possibly empty sequence of triplets (ri, di, ti), i = 3, ..., u
- * c ciphertext representative, an integer between 0 and n 1
- * Output:
- * m message representative, an integer between 0 and n 1
- * Error: "ciphertext representative out of range"
- * Assumption: RSA private key K is valid
- */
- int rsadp(mpz_t m, rsa_key_t *K, mpz_t c)
- {
- return hrsapowm(m, K->n, K->d, c);
- }
- int rsasp1(mpz_t c, rsa_key_t *K, mpz_t m)
- {
- return rsadp(c, K, m);
- }
- int resvp1(mpz_t c, rsa_key_t *K, mpz_t m)
- {
- return rsaep(c, K, m);
- }
- void osxor(unsigned char*dst, int len,
- unsigned char*s1, unsigned char*s2)
- {
- int i;
- for(i=0;i<len;++i)
- {
- dst[i]=s1[i] ^ s2[i];
- }
- }
- // mask should be at least mask_len+hash_len-1 size;
- // tmpppool should be at least seed_len+4 size
- void mgf1(unsigned char *seed, int seedlen, hash_t *hash,
- unsigned char *mask, int masklen, unsigned char * tmppool)
- {
- int i;
- int c=(masklen+hash->hLen-1)/hash->hLen;
-
- memcpy(tmppool, seed, seedlen);
- unsigned char* Hash;
- for(i=0;i<c;++i)
- {
- tmppool[seedlen]=(i>>24);
- tmppool[seedlen+1]=(i>>16);
- tmppool[seedlen+2]=(i>>8);
- tmppool[seedlen+3]=i;
- Hash=hash->func(tmppool, seedlen+4);
- memcpy(mask+i*hash->hLen,Hash, hash->hLen);
- }
- }
- typedef struct {
- unsigned char *DB, *dbmask;
- unsigned char *tmppool;
- unsigned char *seed, *seedmask;
- unsigned char *EM;
- unsigned char *pin;
- mpz_t ic, im;
- }oaep_pool_t;
- void init_oaep_pool(oaep_pool_t *pool, rsa_key_t *K, hash_t *hash, char *pin)
- {
- pool->DB=(unsigned char*)malloc(K->k-hash->hLen-1);
- pool->dbmask=(unsigned char*)malloc(K->k-2);
- pool->seed=(unsigned char*)malloc(hash->hLen);
- pool->seedmask=(unsigned char*)malloc(hash->hLen+hash->hLen-1);
- pool->EM=(unsigned char*)malloc(K->k);
- pool->tmppool=hash->func((unsigned char*)pin, strlen(pin));
- pool->pin=(unsigned char*)malloc(hash->hLen);
- memcpy(pool->pin, pool->tmppool, hash->hLen);
- pool->tmppool=(unsigned char*)malloc(K->k+4);
- mpz_init2(pool->ic, K->k*8);
- mpz_init2(pool->im, K->k*8);
- }
- void deinit_oaep_pool(oaep_pool_t *pool)
- {
- mpz_clear(pool->ic);
- mpz_clear(pool->im);
- free(pool->DB);
- free(pool->dbmask);
- free(pool->seedmask);
- free(pool->seed);
- free(pool->tmppool);
- free(pool->EM);
- free(pool->pin);
- }
- unsigned char *rsaes_oaep_encrypt(rsa_key_t *K,
- unsigned char *M, int mLen,
- unsigned char *L, int lLen,
- hash_t *hash,
- oaep_pool_t *pool)
-
- {
- //len checking ...
- if(lLen>hash->limit
- || mLen> K->k-2*hash->hLen-2 )
- return NULL;
- // EME-OAEP encoding
- unsigned char * Hash;
- int i, lPs=K->k-mLen-2*hash->hLen-2;
- Hash=hash->func(L, lLen);
- // set DB
- int dbLen=K->k-hash->hLen-1;
- memcpy(pool->DB, Hash, hash->hLen);
- memset(pool->DB+hash->hLen, 0, lPs);
- pool->DB[lPs+hash->hLen]=1;
- memcpy(pool->DB+lPs+hash->hLen+1, M, mLen);
- for(i=0;i<hash->hLen;++i) pool->seed[i]=random();
- mgf1(pool->seed, hash->hLen, hash,
- pool->dbmask, dbLen, pool->tmppool);
- osxor(pool->DB, dbLen, pool->DB, pool->dbmask);
-
- mgf1(pool->DB, dbLen, hash,
- pool->seedmask, hash->hLen, pool->tmppool);
- osxor(pool->seed, hash->hLen, pool->seed, pool->seedmask);
- // added by pointer, not standard!!
- osxor(pool->seed, hash->hLen, pool->pin, pool->seed);
-
- pool->EM[0]=0;
- memcpy(pool->EM+1, pool->seed, hash->hLen);
- memcpy(pool->EM+hash->hLen+1, pool->DB, dbLen);
- os2ip(pool->im, pool->EM, K->k);
- rsaep(pool->ic, K, pool->im);
- i2osp(pool->ic, pool->EM, K->k);
- return pool->EM;
- }
- unsigned char * rsaes_oaep_decrypt(rsa_key_t *K,
- unsigned char *C, int k,
- unsigned char *L, int lLen,
- hash_t *hash,
- oaep_pool_t *pool)
- {
- if(lLen>hash->limit
- || k!= K->k
- || k< 2*hash->hLen+2)
- return NULL;
- int i;
- os2ip(pool->ic, C, K->k);
- if(rsadp(pool->im, K, pool->ic)<0)
- return NULL;
- i=i2osp(pool->im, pool->EM, K->k);
- if(i==-1 || pool->EM[0]!=0) {
- fprintf(stderr, "not like a encrypted block?\n");
- return NULL;
- }
-
- int dbLen=K->k-hash->hLen-1;
- mgf1(pool->EM+1+hash->hLen, dbLen, hash,
- pool->seedmask, hash->hLen, pool->tmppool);
- osxor(pool->seed, hash->hLen, pool->EM+1, pool->seedmask);
- // added by pointer, not standard!!
- osxor(pool->seed, hash->hLen, pool->seed, pool->pin);
- mgf1(pool->seed, hash->hLen, hash,
- pool->dbmask, dbLen, pool->tmppool);
- osxor(pool->DB, dbLen, pool->EM+1+hash->hLen, pool->dbmask);
- unsigned char *Hash=hash->func(L, lLen);
- if(memcmp(Hash, pool->DB, hash->hLen)!=0)
- {
- fprintf(stderr, "[decrypt][warning] check hash fail, maybe incorrect ...\n");
- }
- i=hash->hLen;
- while(i<K->k && pool->DB[i]==0) ++i;
- if(i==K->k || pool->DB[i]!= 1)
- {
- fprintf(stderr, "[decrypt] fail with K.k=%d i=%d %.2x!=01\n", K->k, i, pool->DB[i]);
- return NULL;
- }
- return pool->DB+i+1;
- }
-
- unsigned char *hash_sha1(unsigned char *t, int len)
- {
- static unsigned char hash[20];
- MHASH td=mhash_init(MHASH_SHA1);
- if(td == MHASH_FAILED) exit(13);
- mhash(td, t, len);
- mhash_deinit(td, hash);
- return hash;
- }
- void init_hash(hash_t *hash)
- {
- hash->hLen=20;
- hash->limit=INT_MAX;
- hash->func = hash_sha1;
- }
- int main(int argc, char *argv[])
- {
- char *usage="%s -k keyfile [-e] [-d] [--pin password] [-f inputfile] [-o outputfile]\n";
- int is_encrypt=1;
- int is_decrypt=0;
- unsigned char *label=(unsigned char*)"seceret";
- int lLen;
- char *infile=NULL;
- char *outfile=NULL;
- char *keyfile=NULL;
- char *pin=argv[0];
-
- FILE *ifp=NULL, *ofp=NULL, *kfp=NULL;
- rsa_key_t K;
- mpz_init(K.p);
- mpz_init(K.q);
- mpz_init(K.e);
- mpz_init(K.d);
- mpz_init(K.n);
- struct option lopt[]=
- {
- {"key-file", 1, 0, 'k'},
- {"encrypt", 0, 0, 'e'},
- {"decrypt", 0, 0, 'd'},
- {"input", 1, 0, 'f'},
- {"output", 1, 0, 'o'},
- {"label",1,0,'l'},
- {"help",0,0,'h'},
- {"pin",1,0,'p'},
- {"Kn",1, 0, 257},
- {"Ke",1, 0, 258},
- {"Kd",1, 0, 259},
- {"Kp",1, 0, 260},
- {"Kq",1, 0, 261},
- {0,0,0,0}
- };
- int c, opt_idx;
-
- while(1)
- {
- c=getopt_long(argc, argv, "k:f:o:l:p:edh", lopt, &opt_idx);
- if(c==-1) break;
- switch(c)
- {
- case 0:
- break;
- case 'f':
- infile=optarg;
- if(ifp!=NULL) fclose(ifp);
- ifp=fopen(infile, "rb");
- break;
- case 'o':
- outfile=optarg;
- if(ofp!=NULL) fclose(ofp);
- ofp=fopen(outfile, "wb");
- break;
- case 'k':
- keyfile=optarg;
- if(kfp!=NULL) fclose(kfp);
- kfp=fopen(keyfile, "r");
- break;
- case 'e':
- is_encrypt=1;
- is_decrypt=0;
- break;
- case 'd':
- is_decrypt=1;
- is_encrypt=0;
- break;
- case 'l':
- label=(unsigned char*)optarg;
- break;
- case 'p':
- pin=optarg;
- break;
- case 257://Kn
- mpz_set_str(K.n, optarg, 0);
- break;
- case 258://Ke
- mpz_set_str(K.e, optarg, 0);
- break;
- case 259://Kd
- mpz_set_str(K.d, optarg, 0);
- break;
- case 260://Kp
- mpz_set_str(K.p, optarg, 0);
- break;
- case 261://Kq
- mpz_set_str(K.q, optarg, 0);
- break;
- default:
- fprintf(stderr, usage, argv[0]);
- return 1;
- }
- }
- if(ifp==NULL) ifp=stdin;
- if(ofp==NULL) ofp=stdout;
- lLen=strlen((char*)label);
-
- unsigned char buf[1<<16], *p;
- while(kfp!=NULL && !feof(kfp))
- {
- fgets((char*)buf, 1<<16, kfp);
- switch(buf[0])
- {
- case ' ':
- case '\t':
- case 0:
- case '#':
- case '\r':
- case '\n':
- break;
- case 'p':
- if(buf[1]=='=' && mpz_sgn(K.p)==0 ) mpz_set_str(K.p,(char*)buf+2, 0);
- break;
- case 'q':
- if(buf[1]=='=' && mpz_sgn(K.q)==0 ) mpz_set_str(K.q,(char*)buf+2, 0);
- break;
- case 'd':
- if(buf[1]=='=' && mpz_sgn(K.d)==0 ) mpz_set_str(K.d,(char*)buf+2, 0);
- break;
- case 'e':
- if(buf[1]=='=' && mpz_sgn(K.e)==0 ) mpz_set_str(K.e,(char*)buf+2, 0);
- break;
- case 'n':
- if(buf[1]=='=' && mpz_sgn(K.n)==0 ) mpz_set_str(K.n,(char*)buf+2, 0);
- break;
- default:
- fprintf(stderr, "rsakey error: %s\n", buf);
- break;
- }
- }
- if(kfp!=NULL) fclose(kfp);
-
- if(mpz_sgn(K.n)!=1)
- {
- if(mpz_sgn(K.p)==1 && mpz_sgn(K.q)==1)
- {
- mpz_mul(K.n, K.p, K.q);
- }
- else
- {
- fprintf(stderr, "[K] modulus not set, and not p or q, ...\n");
- return 21;
- }
- }
- K.k=(mpz_sizeinbase(K.n, 2)+7)/8;
- hash_t hash;
- init_hash(&hash);
- oaep_pool_t pool;
- init_oaep_pool(&pool, &K, &hash, pin);
- int len, t;
- if(is_decrypt)
- {
- if(mpz_sgn(K.n)!=1 || mpz_sgn(K.d)!=1)
- {
- fprintf(stderr, "[main] no private set to decrypt ...\n");
- return 23;
- }
- while(!feof(ifp))
- {
- len=fread(buf, 1, K.k, ifp);
- if(len==K.k)
- {
- p=rsaes_oaep_decrypt(&K, buf, K.k, label, lLen, &hash, &pool);
- if(p==NULL) exit(1);
- t=K.k-hash.hLen-1-(p-pool.DB);
- fwrite(p, 1, t, ofp);
- }
- else
- {
- if(len>0)
- fprintf(stderr, "fread wrong, len=%d K.k=%d\n", len, K.k);
- break;
- }
- }
- }
- else
- {
- if(mpz_sgn(K.n)!=1 || mpz_sgn(K.e)!=1)
- {
- fprintf(stderr, "[main] no public set to encrypt ...\n");
- return 24;
- }
- int mLen=K.k-2*hash.hLen-2;
- while(!feof(ifp))
- {
- len=fread(buf, 1, mLen, ifp);
- if(len)
- {
- p=rsaes_oaep_encrypt(&K, buf, len, label, lLen, &hash, &pool);
- if(p==NULL) exit(1);
- fwrite(p, 1, K.k, ofp);
- }
- }
- }
- fclose(ifp);
- fclose(ofp);
- deinit_oaep_pool(&pool);
- return 0;
- }
复制代码 |
|