2010年4月21日水曜日

PythonでPHPのopenssl_verify()相当の処理

PythonでPHPのopenssl_verify()の処理を実現しようとしたが、RHEL5に入っているM2Cryptoのバグにヒットした。

https://bugzilla.osafoundation.org/show_bug.cgi?id=7973

EVP.verify_final()に署名の情報を渡せないので、署名の検証が行えないというバグ。
最新版のM2Cryptoなら直っている。 2行ぐらい直すだけだけど。

openssl_verify()はこんな感じの実装になった。

def openssl_verify(data, sig, pubkeyfile):
rsa = M2Crypto.RSA.load_pub_key(pubkeyfile)
pubkey = M2Crypto.EVP.PKey()
pubkey.assign_rsa(rsa)
pubkey.reset_context()
pubkey.verify_init()
pubkey.verify_update(data)
return pubkey.verify_final(sig)



2010年4月9日金曜日

PythonでPHPのopenssl_seal()相当の処理を実現

PHPには、openssl_seal()が用意されていて、複数の受信者に対して、受信者ごとの公開鍵で暗号化したデーターを、一度に暗号化するインターフェースが用意されている。

これと同じことを、Pythonでやろうとすると、インターフェースが用意されていないので、M2Cryptoを利用してやる必要があるが、その方法がやっと分かった。

まず、opensslコマンドでテスト用に、公開鍵と秘密鍵を作成しておく。

$ openssl genrsa -out privatekey.pem
$ openssl rsa -pubout -in privatekey.pem -out publickey.pem


次にPythonの暗号化用のスクリプトで、データーを暗号化し、暗号化したデーターと、エンベロープキーをゲットする。

#!/usr/bin/python

import M2Crypto
import M2Crypto.Rand
import M2Crypto.RSA
import base64

PUBKEY = "publickey.pem"
message = "Hello World!"

pubkey = M2Crypto.RSA.load_pub_key(PUBKEY)
randdata = M2Crypto.Rand.rand_bytes(16)
msg = pubkey.public_encrypt(randdata,M2Crypto.RSA.pkcs1_padding)
print "== envelope key (Base64 encoded) =="
print base64.b64encode(msg)

cipher='rc4'
iv = ""
enc = M2Crypto.EVP.Cipher(cipher, randdata, iv, M2Crypto.encrypt)
data = enc.update(message)
data += enc.final()

print "== encrypted data (Base64 encoded) =="
print base64.b64encode(data)


これを実行すると、次のような結果が得られる。

== envelope key (Base64 encoded) ==
NIBGzm6ijGFjtruyVO4QDBGiWNu1bgJvJPlkY5kmCNLKEuabiBytsjRfOKZb7w4jsSnCrUREeCPHwa7SLMVceNQf6iWyE22RS6tAMVvzFBrKjXwNCZ+pU4v4pCQPTI+vZg7B/QcajR832hmBcG0NF8LRl1+9rSSvNpPMwJNTwos=
== encrypted data (Base64 encoded) ==
on5LIKdw1UxqfcYY


これらのデーターが復号化できることを、PHPのスクリプトでopenssl_open()を使って確認してみる。

$privatekey = file_get_contents("privatekey.pem");
$message= "";
$encrypted = "on5LIKdw1UxqfcYY";

$ekey = "NIBGzm6ijGFjtruyVO4QDBGiWNu1bgJvJPlkY5kmCNLKEuabiBytsjRfOKZb7w4jsSnCrUREeCPHwa7SLMVceNQf6iWyE22RS6tAMVvzFBrKjXwNCZ+pU4v4pCQPTI+vZg7B/QcajR832hmBcG0NF8LRl1+9rSSvNpPMwJNTwos=";

if (!openssl_open(base64_decode($encrypted), $message, base64_decode($ekey), $privatekey)){
echo "Failed decrypt\n";
die;
}
echo $message."\n";
?>


このPHPスクリプトを実行して、"Hello World!"が表示されれば、正しく復号化できたということ。


2010年4月6日火曜日

Python から Cを利用

PythonからCのライブラリを利用するときに、Pythonのリストオブジェクトをどのように利用するか調べてみた。

リストオブジェクトに入っている文字列を表示し、リストオブジェクト内のオブジェクト数を返却するCプログラムを、test2モジュールとして作成してみた。

#include <Python.h>

static PyObject *
test2_listnum(PyObject *self, PyObject *args)
{
PyObject *list;
PyObject *item;
char *itemstr;
int num;
int i;
if (!PyArg_ParseTuple(args, "O", &list)){
return NULL;
}
num = PyList_Size(list);

for (i=0;iitem = PyList_GetItem(list, i);
itemstr = PyString_AsString(item);
printf("%s\n", itemstr);
}

return Py_BuildValue("i", num);
}


これをビルドするためのMakefile。

CC = gcc

.c.o:
$(CC) -fPIC -I"/usr/include/python2.4" -c $<

all: test2

clean:
rm -r *.o; rm -r *.so

test2: test2.o
$(CC) $(OPT) -Wl,-soname,$@.so -shared -o $@.so $^


そして、テスト用のPythonプログラム。

#!/usr/bin/python

import test2

a = []
a.append("test1")
a.append("test2")
num = test2.listnum(a)
print num



2010年4月1日木曜日

Perl CPAN::Siteの仕様変更

ネットワークアプライアンスのInfobloxで提供されるPerl APIを利用するために、マニュアルに従って、Perl CPAN::Siteの最新版(1.05)をインストールした。

ドキュメントに従って、
# perl -MCPAN::Site -e shell
を実行すると、何も起きずにすぐ終了してしまう。
straceをかけてみたが、エラーらしきエラーもなし。

いろいろ調べていくうちに、CPAN::Siteのドキュメントに、1.01から仕様が大幅に変更されたとか書いてある。
もしやと思って、ちょっと古い CPAN::Site 0.26に入れ替えてみたら、ドキュメント通りに動作するようになった。
ありがちな罠だけど、これは一般人には解決できない気がしたので、メモを残しておく。