Skip to content

Instantly share code, notes, and snippets.

@mikecat
Created March 10, 2014 07:40
Show Gist options
  • Save mikecat/9460956 to your computer and use it in GitHub Desktop.
Save mikecat/9460956 to your computer and use it in GitHub Desktop.
GMPを使用してSSHのRSA鍵を作成するプログラム
/*
* このプログラムを使用するには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