と言っても独自に実装したわけではなく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 件のコメント:
コメントを投稿