2009/04/21

16進数 python

Python の OpenSSL のバインディング? っていうと
OpenSSLの本にも載っている M2Crypto
でもこれ SWIG を入れなきゃいけなかったりしてちょっとインストールが面倒
他にも SWIG 使ってる package 使いたいってんならいいんだけど、そうでもないし
SWIG 使ってる何か良いパッケージあるんでしょうか

で、簡単にインストールできるのが pyOpenSSL
これは easy_install でサクっと入ってくれたりするんだけど非力
何が例えば困ったかっていうと
  • X.509 の署名アルゴリズムが取れない
  • SSL で繋いだときのサーバが提示するサーバ証明書以外の証明書が取れない
  • 公開鍵のパラメータが取れない
とかまぁ、ニッチな要望なんですけど

で、patch でも書くかと思っていじっていたんですが
RSA っていうと大きな素数を使います、2 つ
しかも掛け算して 1024bit とか 2048bit でないと表現できないような数字を使うので
OpenSSL は BIGNUM とかって多倍長? って言うんでしょうか、型が用意されていて
その型で計算しています、桁溢れちゃうからね!!
で、pyOpenSSL はどうも BIGNUM をバインドしてくれていない、ひどい

ひどい! と思ったんですがそこで諦めてはいかんと思い
かといって BIGNUM を実装というのは踏み込んではいけない世界な気がして
OpenSSL: Documents, bn(3) を良く眺めてみると
char *BN_bn2hex(const BIGNUM *a);
とある、これは BIGNUM を char で 16 進表示してくれるようでした
string までもってったら Python の int にもできるだろうと思って検索
2-36進数の文字列をint型に変換する - スコトプリゴニエフスク通信にありました
>>> int("0101", 2)
5
>>> int("nishio", 36)
1422284208
おぉ〜

で、これを C で書かないといけないので include/python2.6/intobject.h をチェック
PyAPI_FUNC(PyObject *) PyInt_FromString(char*, char**, int);
名前からして何かこれっぽいけど、何だこの第二引数は、ということで更に "PyInt_FromString" で検索
7.2.1 (通常)整数型オブジェクト (plain integer object)
素晴しい、日本語だ
で、どうも NULL で良いらしいので NULL にしたら無事大きな数字が出てきました

NULL ってのはアドレス 0 を挿すポインタのことらしい
要するに 0?

結局どうなったかっていうと
static PyObject *
crypto_PKey_params(crypto_PKeyObj *self, PyObject *args)
{

PyObject *params;

if (!PyArg_ParseTuple(args, ":params"))
return NULL;

params = PyDict_New();

if (self->pkey->type == EVP_PKEY_RSA) {
if (self->pkey->pkey.rsa->n != NULL)
PyDict_SetItem(params, PyString_FromString("n"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->n), NULL, 16));
if (self->pkey->pkey.rsa->e != NULL)
PyDict_SetItem(params, PyString_FromString("e"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->e), NULL, 16));
if (self->pkey->pkey.rsa->d != 0)
PyDict_SetItem(params, PyString_FromString("d"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->d), NULL, 16));
if (self->pkey->pkey.rsa->p != NULL)
PyDict_SetItem(params, PyString_FromString("p"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->p), NULL, 16));
if (self->pkey->pkey.rsa->q != NULL)
PyDict_SetItem(params, PyString_FromString("q"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->q), NULL, 16));
if (self->pkey->pkey.rsa->dmp1 != NULL)
PyDict_SetItem(params, PyString_FromString("dmp1"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->dmp1), NULL, 16))
;
if (self->pkey->pkey.rsa->dmq1 != NULL)
PyDict_SetItem(params, PyString_FromString("dmq1"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->dmq1), NULL, 16))
;
if (self->pkey->pkey.rsa->iqmp != NULL)
PyDict_SetItem(params, PyString_FromString("iqmp"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.rsa->iqmp), NULL, 16))
;
} else if (self->pkey->type == EVP_PKEY_DSA) {
if (self->pkey->pkey.dsa->p != NULL)
PyDict_SetItem(params, PyString_FromString("p"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.dsa->p), NULL, 16));
if (self->pkey->pkey.dsa->q != NULL)
PyDict_SetItem(params, PyString_FromString("q"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.dsa->q), NULL, 16));
if (self->pkey->pkey.dsa->g != 0)
PyDict_SetItem(params, PyString_FromString("g"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.dsa->g), NULL, 16));
if (self->pkey->pkey.dsa->priv_key != NULL)
PyDict_SetItem(params, PyString_FromString("priv_key"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.dsa->priv_key), NU
LL, 16));
if (self->pkey->pkey.dsa->pub_key != NULL)
PyDict_SetItem(params, PyString_FromString("pub_key"), PyInt_FromString(BN_bn2hex(self->pkey->pkey.dsa->pub_key), NULL
, 16));
}

return params;
}
こんなんになっちゃったんだけど、何か格好悪くない?
誰かに直して欲しい、あと、unittest の書き方も教えて欲しい
つか先ず BIGNUM をバインドしてほしい

あ、ちなみに、Ruby の source を中々参考にしました。

0 件のコメント:

コメントを投稿