How to make cryptlib_py work on 64-bit platforms

Cryptlib is a totally fascinating cross-platform crypto library with Python bindings. Unfortunately, the current version (3.3.3) is unusable on 64-bit platforms. The good news though it is easily fixable. Let's look what's going on there:

$ python
Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> from cryptlib_py import *
>>> cryptInit()
>>> sess = cryptCreateSession(CRYPT_UNUSED, CRYPT_SESSION_SSH)
>>> sess.CRYPT_SESSINFO_SERVER_NAME = "myserver.com"
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 32, in __setattr__
cryptlib_py.CryptException: (-2, 'Bad argument, parameter 2')
>>>

No good. The problem is the way PyObject_AsWriteBuffer (and PyObject_AsCharBuffer) is called. The last parameter is declared as a pointer to Py_ssize_t type, which can be either 32 or 64 bit depending on the platform. Here is the actual declaration in the abstract.h file:

PyAPI_FUNC(int) PyObject_AsWriteBuffer(PyObject *obj,
                      void **buffer,
                      Py_ssize_t *buffer_len);

Now, here is how this function is used in cryptlib_py (python.c, line 21):

if (PyObject_AsWriteBuffer(objPtr, bytesPtrPtr, lengthPtr) == -1)

Where lengthPtr is declared as "int* lengthPtr". See the problem? This is what happens: the function expects a pointer to a 8-byte blob but instead it is provided with a pointer to a 4-byte int. Being unaware of that, the function smashes the variable next to the one pointed by lengthPtr. The solution is to patch cryptlibConverter.py, the script generating bindings/python.c. Although this problem is very likely to be fixed in the next cryptlib release, here is what you do if you can't wait:

mkdir cryptlib; cd cryptlib
curl -O ftp://ftp.franken.de/pub/crypt/cryptlib/cl333.zip
unzip cl333.zip
curl -O http://mikeivanov.com/pc/cryptlibConverter.py.patch
patch -p0 < cryptlibConverter.py.patch
python tools/cryptlibConverter.py cryptlib.h bindings python
make
cd bindings
python setup.py build
sudo python setup.py install

Fixed! The patched version is working just fine:

$ python
Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> 
>>> from cryptlib_py import *
>>> cryptInit()
>>> sess = cryptCreateSession(CRYPT_UNUSED, CRYPT_SESSION_SSH)
>>> sess.CRYPT_SESSINFO_SERVER_NAME = "myserver.com"
>>> sess.CRYPT_SESSINFO_USERNAME = "mike"
>>> sess.CRYPT_SESSINFO_PASSWORD = raw_input("pwd=")
pwd=mypassword
>>> sess.CRYPT_SESSINFO_ACTIVE = 1
>>> data = array('c', '\0' * 1024)
>>> recv = cryptPopData(sess, data, 1024)
>>> print data.tostring()[:recv]
Linux myserver.com 2.6 XXXXXXXXX x86_64 GNU/Linux
Ubuntu 10.04 LTS
.......
>>> cryptPushData(sess, "uptime\n")
7
>>> cryptFlushData(sess)
>>> recv = cryptPopData(sess, data, 1024)
>>> print data.tostring()[:recv]
uptime
 18:17:15 up 6 days,  1:54, 13 users,  load average: 0.30, 0.27, 0.26
mike@myserver:~$ 
>>>