Created
March 10, 2014 07:40
-
-
Save mikecat/9460956 to your computer and use it in GitHub Desktop.
GMPを使用してSSHのRSA鍵を作成するプログラム
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* このプログラムを使用するにはGNU MP https://gmplib.org/index.html が必要です。 | |
* コマンドライン | |
* generatersakey <使用する素数のビット数> <公開鍵のファイル名> <秘密鍵のファイル名> | |
*/ | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <time.h> | |
#include <gmp.h> | |
static const char base64chars[]= | |
"ABCDEFGHIJKLMNOPQRSTUVWXYZ" | |
"abcdefghijklmnopqrstuvwxyz" | |
"0123456789+/"; | |
typedef struct { | |
FILE* fp; | |
int bufferStatus; | |
int linePosition; | |
int lineBreak; | |
unsigned char buffer; | |
} base64encode_t; | |
void base64start(base64encode_t* b64,FILE* fp,int lineBreak) { | |
b64->fp=fp; | |
b64->bufferStatus=0; | |
b64->linePosition=0; | |
b64->lineBreak=lineBreak; | |
} | |
void base64putchar(base64encode_t* b64,int c) { | |
fputc(c,b64->fp); | |
b64->linePosition++; | |
if(b64->lineBreak>0 && b64->linePosition>=b64->lineBreak) { | |
b64->linePosition=0; | |
fputc('\n',b64->fp); | |
} | |
} | |
void base64write(base64encode_t* b64,const void* data,int size) { | |
int i; | |
const unsigned char* p=(const unsigned char*)data; | |
for(i=0;i<size;i++) { | |
unsigned char now=*(p++); | |
switch(b64->bufferStatus) { | |
case 0: | |
b64->buffer=now; | |
base64putchar(b64,base64chars[(now>>2)&0x3f]); | |
b64->bufferStatus=1; | |
break; | |
case 1: | |
base64putchar(b64,base64chars[((b64->buffer<<4)|(now>>4))&0x3f]); | |
b64->buffer=now; | |
b64->bufferStatus=2; | |
break; | |
case 2: | |
base64putchar(b64,base64chars[((b64->buffer<<2)|(now>>6))&0x3f]); | |
base64putchar(b64,base64chars[now&0x3f]); | |
b64->bufferStatus=0; | |
break; | |
} | |
} | |
} | |
void base64end(base64encode_t* b64) { | |
switch(b64->bufferStatus) { | |
/* case 0: do nothing */ | |
case 1: | |
base64putchar(b64,base64chars[(b64->buffer<<4)&0x3f]); | |
base64putchar(b64,'='); | |
fputc('=',b64->fp); | |
break; | |
case 2: | |
base64putchar(b64,base64chars[(b64->buffer<<2)&0x3f]); | |
fputc('=',b64->fp); | |
break; | |
} | |
b64->bufferStatus=0; | |
b64->linePosition=0; | |
} | |
void writeSizeDataToBase64(base64encode_t* b64,size_t size) { | |
unsigned char sizeBuffer[4]; | |
unsigned char count; | |
int i; | |
if(size<0x80) { | |
count=(unsigned char)size; | |
base64write(b64,(void*)&count,1); | |
} else { | |
for(count=0;size>0;size>>=8)sizeBuffer[count++]=size&0xff; | |
count|=0x80; | |
base64write(b64,(void*)&count,1); | |
for(i=(count&0x7f)-1;i>=0;i--)base64write(b64,(void*)&sizeBuffer[i],1); | |
} | |
} | |
void writeIntegerToBase64(base64encode_t* b64,const void* dat,size_t size,int mode) { | |
unsigned char sizeBuffer[4]; | |
size_t writeSize; | |
int i; | |
if(((const unsigned char*)dat)[0]&0x80) { | |
writeSize=size+1; | |
} else { | |
writeSize=size; | |
} | |
if(mode==0) { | |
for(i=0;i<4;i++)sizeBuffer[i]=(writeSize>>((3-i)*8))&0xff; | |
base64write(b64,(void*)sizeBuffer,4); | |
} else { | |
sizeBuffer[0]=0x02; | |
base64write(b64,(void*)sizeBuffer,1); | |
writeSizeDataToBase64(b64,writeSize); | |
} | |
if(((const unsigned char*)dat)[0]&0x80) { | |
sizeBuffer[0]=0; | |
base64write(b64,(void*)sizeBuffer,1); | |
} | |
base64write(b64,dat,size); | |
} | |
int calcuateSizeOfSizeData(size_t size) { | |
int ret; | |
if(size<0x80)return 1; | |
for(ret=1;size>0;size>>=8)ret++; | |
return ret; | |
} | |
int main(int argc,char* argv[]) { | |
static const char identifier[]="\x00\x00\x00\x07ssh-rsa"; | |
int bits=1024; | |
mpz_t n,e,d,p,q,x1,x2,x3,tmp; | |
gmp_randstate_t rs; | |
FILE* fp; | |
base64encode_t b64; | |
void* n_dat=NULL; | |
void* e_dat=NULL; | |
void* dats[6]={}; | |
size_t n_size,e_size,sizes[6]; | |
size_t dataSize; | |
int i; | |
/* パラメータチェック */ | |
if(argc!=4) { | |
fputs("Usage: generatersakey <bit num> <public key file> <private key file>\n",stderr); | |
return 1; | |
} | |
/* ビット数の入力 */ | |
if(sscanf(argv[1],"%d",&bits)!=1 || bits<4) { | |
fputs("Invalid bits!\n",stderr); | |
return 1; | |
} | |
/* 初期化 */ | |
mpz_inits(n,e,d,p,q,x1,x2,x3,tmp,NULL); | |
gmp_randinit_default(rs); | |
gmp_randseed_ui(rs,(unsigned int)time(NULL)); | |
/* ランダムな素数の生成 */ | |
do { | |
mpz_urandomb(p,rs,bits-1); | |
mpz_setbit(p,bits-1); | |
mpz_nextprime(p,p); | |
} while(mpz_tstbit(p,bits)); /* while p>=2^bits (overflow) */ | |
do { | |
mpz_urandomb(q,rs,bits-1); | |
mpz_setbit(q,bits-1); | |
mpz_nextprime(q,q); | |
} while(mpz_tstbit(q,bits) || mpz_cmp(p,q)==0); | |
/* パラメータの計算 */ | |
mpz_mul(n,p,q); | |
mpz_sub_ui(tmp,p,1); | |
mpz_sub_ui(x1,q,1); | |
mpz_mul(tmp,tmp,x1); | |
if(mpz_gcd_ui(NULL,tmp,65537)==1) { | |
mpz_set_ui(e,65537); | |
} else if(mpz_gcd_ui(NULL,tmp,17)==1) { | |
mpz_set_ui(e,17); | |
} else if(mpz_gcd_ui(NULL,tmp,35)==1) { | |
mpz_set_ui(e,35); | |
} else if(mpz_gcd_ui(NULL,tmp,3)==1) { | |
mpz_set_ui(e,3); | |
} else { | |
fputs("Bad luck! Key generation failed. Please try again.\n",stderr); | |
} | |
mpz_invert(d,e,tmp); | |
mpz_sub_ui(tmp,p,1); | |
mpz_mod(x1,d,tmp); | |
mpz_sub_ui(tmp,q,1); | |
mpz_mod(x2,d,tmp); | |
mpz_invert(x3,q,p); | |
/* 計算したパラメータの書き出し */ | |
n_dat=mpz_export(NULL,&n_size,1,1,1,0,n); | |
e_dat=mpz_export(NULL,&e_size,1,1,1,0,e); | |
dats[0]=mpz_export(NULL,&sizes[0],1,1,1,0,d); | |
dats[1]=mpz_export(NULL,&sizes[1],1,1,1,0,p); | |
dats[2]=mpz_export(NULL,&sizes[2],1,1,1,0,q); | |
dats[3]=mpz_export(NULL,&sizes[3],1,1,1,0,x1); | |
dats[4]=mpz_export(NULL,&sizes[4],1,1,1,0,x2); | |
dats[5]=mpz_export(NULL,&sizes[5],1,1,1,0,x3); | |
/* 公開鍵の書き出し */ | |
if((fp=fopen(argv[2],"wb"))!=NULL) { | |
fputs("ssh-rsa ",fp); | |
base64start(&b64,fp,0); | |
base64write(&b64,(void*)identifier,11); | |
writeIntegerToBase64(&b64,e_dat,e_size,0); | |
writeIntegerToBase64(&b64,n_dat,n_size,0); | |
base64end(&b64); | |
fputs(" key\n",fp); | |
fclose(fp); | |
} else { | |
fputs("Public key file open error!\n",stderr); | |
} | |
/* 秘密鍵の書き出し */ | |
if((fp=fopen(argv[3],"wb"))!=NULL) { | |
fputs("-----BEGIN RSA PRIVATE KEY-----\n",fp); | |
base64start(&b64,fp,64); | |
base64write(&b64,"\x30",1); | |
dataSize=3; | |
dataSize+=1+calcuateSizeOfSizeData(n_size)+n_size; | |
if(((unsigned char*)n)[0]&0x80)dataSize++; | |
dataSize+=1+calcuateSizeOfSizeData(e_size)+e_size; | |
if(((unsigned char*)e)[0]&0x80)dataSize++; | |
for(i=0;i<6;i++) { | |
dataSize+=1+calcuateSizeOfSizeData(sizes[i])+sizes[i]; | |
if(((unsigned char*)dats[i])[0]&0x80)dataSize++; | |
} | |
writeSizeDataToBase64(&b64,dataSize); | |
writeIntegerToBase64(&b64,(void*)"\x00",1,1); | |
writeIntegerToBase64(&b64,n_dat,n_size,1); | |
writeIntegerToBase64(&b64,e_dat,e_size,1); | |
for(i=0;i<6;i++)writeIntegerToBase64(&b64,dats[i],sizes[i],1); | |
base64end(&b64); | |
fputs("\n-----END RSA PRIVATE KEY-----\n",fp); | |
fclose(fp); | |
} else { | |
fputs("Private key file open error!\n",stderr); | |
} | |
/* 解放して終了 */ | |
free(n_dat); | |
free(e_dat); | |
for(i=0;i<6;i++)free(dats[i]); | |
gmp_randclear(rs); | |
mpz_clears(n,e,d,p,q,x1,x2,x3,tmp,NULL); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment