と言っても独自に実装したわけではなくOpenSSLを利用しました。
RSAはすでに特許が切れているので自由に使えはしますが、
各実装には著作権等が絡んできますのでその辺はご注意を。
さて、Ubuntu 12.04であれば
# apt-get install libssl-devを実行した後に、
#include <stdio.h>
#include <openssl/rsa.h>
int main(void)
{
int i;
FILE *fp;
RSA *rsa;
SSL_library_init();
rsa = RSA_generate_key(1024,65537,NULL,NULL);
RSA_print_fp(stdout,rsa,0);
fp=fopen("public.pem","w");
PEM_write_RSAPublicKey(fp,rsa);
fclose(fp);
fp=fopen("private.pem","w");
PEM_write_RSAPrivateKey(fp,rsa,NULL,NULL,0,NULL,NULL);
fclose(fp);
RSA_free(rsa);
return EXIT_SUCCESS;
}
を中身とするファイル"gen.c"を作成して
$ gcc gen.c -lcrypto -lssl $ ./genとすれば、秘密鍵ファイル"private.pem"と公開鍵ファイル"public.pem"が生成されます。
生成される鍵データは毎回異なります。
なお、エラーハンドリングは一切してませんがご容赦を。
続いて
#include <stdio.h>
#include <openssl/rsa.h>
int main(void)
{
int i,j,size;
FILE *fp;
RSA *rsa=NULL;
unsigned char *rb=NULL,*wb=NULL;
SSL_library_init();
fp=fopen("private.pem","r");
PEM_read_RSAPrivateKey(fp,&rsa,NULL,NULL);
fclose(fp);
size=RSA_size(rsa);
rb=malloc(size);
wb=malloc(size);
size-=11;
while((i=fread(rb,1,size,stdin))>0){
j=RSA_private_encrypt(i,rb,wb,rsa,RSA_PKCS1_PADDING);
if(j<=0)
return EXIT_FAILURE;
fwrite(wb,1,j,stdout);
}
free(rb);
free(wb);
RSA_free(rsa);
return EXIT_SUCCESS;
}
を中身とするファイル"enc.c"を作成して
$ gcc enc.c -lcrypto -lssl $ ./enc < 1 > 2とするとファイル"1"を秘密鍵ファイル"private.pem"で暗号化したファイル"2"が得られます。
さらに
#include <stdio.h>
#include <openssl/rsa.h>
int main(void)
{
int i,j,size;
FILE *fp;
RSA *rsa=NULL;
unsigned char *rb=NULL,*wb=NULL;
SSL_library_init();
fp=fopen("public.pem","r");
PEM_read_RSAPublicKey(fp,&rsa,NULL,NULL);
fclose(fp);
size=RSA_size(rsa);
rb=malloc(size);
wb=malloc(size);
while((i=fread(rb,1,size,stdin))>0){
j=RSA_public_decrypt(i,rb,wb,rsa,RSA_PKCS1_PADDING);
if(j<=0)
return EXIT_FAILURE;
fwrite(wb,1,j,stdout);
}
free(rb);
free(wb);
RSA_free(rsa);
return EXIT_SUCCESS;
}
を中身とするファイル"dec.c"を作成して
$ gcc dec.c -lcrypto -lssl $ ./dec < 2 > 3とするとファイル"2"を公開鍵ファイル"public.pem"で暗号化したファイル"3"が得られ、
"1"と"3"の内容は同一となります。
もし公開鍵をCのソースファイルに埋め込みたいなら、
先の"dec.c"で鍵をファイルから読み込んだ後のrsa->n->dの指し示すメモリから256バイトを
読み取ってメモしておき、
fp=fopen("public.pem","r");
PEM_read_RSAPublicKey(fp,&rsa,NULL,NULL);
fclose(fp);
の代わりに
unsigned char pubkey[]={
<256バイトの鍵データ>
};
rsa = RSA_generate_key(1024,65537,NULL,NULL);
memcpy(rsa->n->d,pubkey,sizeof(pubkey));
を実行してやればうまくいくっぽいです。結構強引ですが動いています。ちなみにこれの代わりに
unsigned char pubkey[]={
<256バイトの鍵データ>,
<16バイトのダミーデータ(0x00)>
};
RSA rsa1;
BIGNUM e,n;
RSA_METHOD method;
unsigned long long ed=65537;
rsa = RSA_generate_key(1024,65537,NULL,NULL);
if(!rsa){
fprintf(stderr,"failed to generate\n");
return EXIT_FAILURE;
}
memset(&rsa1,0,sizeof(RSA));
memcpy(&method,rsa->meth,sizeof(RSA_METHOD));
rsa1.meth=&method;
RSA_free(rsa);
rsa=&rsa1;
memset(&e,0,sizeof(BIGNUM));
memset(&n,0,sizeof(BIGNUM));
rsa->references=1;
rsa->flags=6;
rsa->e=&e;
rsa->e->d=&ed;
rsa->e->top=1;
rsa->e->dmax=1;
rsa->e->flags=1;
rsa->n=&n;
rsa->n->d=pubkey;
rsa->n->top=16;
rsa->n->dmax=17;
rsa->n->flags=1;
でもいけました。ただし64ビット処理系です。なおRSA_generate_key()は処理関数へのポインタを得るためだけに実行しています。
実体はライブラリ上でstatic宣言されているので直接関数名を指定することができず、
このような形になっています。
また、試していませんが秘密鍵を埋め込みたい場合は、
rsaポインタのe,d,p,q,dmp1,dmq1,iqmpの各メンバ変数のdプロパティについて
同様に処理するといけるような気がします。
もしやるなら"bn.h"の"struct bignum_st"や"rsa.h"の"struct rsa_st"を見ながら
トライしてみてください。
0 件のコメント:
コメントを投稿