#9 closed enhancement (fixed)

link against existing (system) libcrypto++.so

Reported by: warner Owned by:
Priority: major Milestone:
Version: Keywords:
Cc: tahoe-dev@…, ruben@…, ruben, fernando.ribeiro@…, doko@…, micah@… Launchpad Bug:

Description

The pycryptopp build process should make it possible to link against an
existing libcrypto++.so instead of always compiling its own. Reasons to do
this:

  • faster: Crypto++ takes about 15 minutes to compile on our edgy buildslave, and this happens on every Tahoe build
  • smaller memory footprint: if all the various python-to-C glue libraries (rsa.so, aes.so, etc) use their own copy of libcrypto++.so, an application that uses them will wind up with multiple copies in RAM.
  • take advantage of newer versions: the system version may be more recent or faster than the one shipped with any given release of pycryptopp

Reasons to not do this:

  • vulnerable to bugs in the system version: the system version of Crypto++ might have bugs that were fixed in the version shipped with pycryptopp
  • static linking: if pycryptopp were to link statically against the pieces of Crypto++ that it needs, the resulting pycryptopp.egg might be transportable to a different machine. Note that currently it does *not* appear to do this: using 'ldd' on pycryptopp's rsa.so shows dynamic links to libcrypto++.so .

Attachments (2)

pycryptopp-system.patch (6.1 KB) - added by ruben at 2008-09-22T20:58:53Z.
aes-exception.diff (2.0 KB) - added by warner at 2009-02-09T21:20:46Z.
stop using symbol comparison in AES.init exception catching

Download all attachments as: .zip

Change History (17)

Changed at 2008-09-22T20:58:53Z by ruben

comment:1 Changed at 2008-09-22T20:59:17Z by ruben

  • Version 0.5.1 deleted

I'm working on packinging pycryptopp for Fedora, so it happens that I have to link against the system library libcryptopp.

I have attached a simple patch which does this, however I'm bumping into a problem while running the testsuite:

test_init_type_check (pycryptopp.test.test_aes.AES128) ...
terminate called after throwing an instance of 'CryptoPP::InvalidKeyLength?'

what(): AES/CTR: 1 is not a valid key length

Not sure what's going on, any help is appreciated.

comment:2 Changed at 2008-10-20T20:13:23Z by zooko

I committed a patch -- [576] -- which adds an option --disable-embedded-cryptopp, which forces setup.py to use the system Crypto++ instead of the bundled source code of Crypto++.

Using it, I get the same kind of problem that you got, e.g.:

test_init_type_check (pycryptopp.test.test_aes.AES128) ... terminate called after throwing an instance of 'CryptoPP::InvalidKeyLength'
  what():  AES/CTR: 1 is not a valid key length
Aborted

and

test_hexdigest (pycryptopp.test.test_sha256.SHA256) ... terminate called after throwing an instance of 'CryptoPP::NameValuePairs::ValueTypeMismatch'
  what():  NameValuePairs: type mismatch for 'Separator', stored 'N8CryptoPP23ConstByteArrayParameterE', trying to retrieve 'N8CryptoPP23ConstByteArrayParameterE'
Aborted

I know what causes this, but not exactly how to fix it. I'll post more in a message to tahoe-dev.

Changed at 2009-02-09T21:20:46Z by warner

stop using symbol comparison in AES.init exception catching

comment:4 Changed at 2009-02-09T21:23:21Z by warner

I've attached a patch (aes-exception.diff) to stop using symbol comparison in the AES constructor's exception-handling code, along with an update to the test code. The new code catches all exceptions (not just CryptoPP::InvalidKeyLength) and turns them into an AES.Error python exception, with a stringified copy of the c++ exception. Works For Me.

An improvement might be to have the code examine the c++ exception to decide (with string comparison, rather than symbol comparison) whether we've got an InvalidKeyLength or something else, and then customize the python-side error message accordingly. I don't know enough c++ to do this easily.

comment:5 Changed at 2009-02-09T22:31:20Z by zooko

Thank you for the patch!

If possible, I would prefer to use the structured C++ type information instead of regex matching in strings to detect the kind of an exception. This might be more important for the ecdsa key exceptions than for AES key exceptions. (All possible AES keys are valid as long as they are the right number of bytes in length, but ECDSA keys have mathematical structure.)

Here is a tutorial on using gcc export maps to control which symbols are exported from your library. The pycryptopp shared library ought not to be exporting symbols which are logical singletons and which are exported by libcryptopp.so:

http://accu.org/index.php/journals/1372

If we can't figure out how to do this the Right Way, then I will accept patches like yours which either determine an exceptions type by string inspection, or else which treat all exceptions as of one indistinguishable type, but I would prefer not to.

comment:6 Changed at 2009-02-09T23:53:05Z by warner

in looking at the sha256 hexdigest() code, I think it would be easiest to just remove that method, and require callers to hexlify it themselves. I looked at two approaches:

  1. modify pycryptopp's SHA256_hexdigest() to hexlify using python instead of crypto++: basically insert a call to "import binascii; return binascii.b2a_hex(digest)". However, doing both the import and the call-into-python from there was more than a 5 minute project.
  2. interpose a python module between sha256module.cpp and the outside world, with an eye towards wrapping the SHA256 object in one that has a hexdigest() method defined in python. That was more than a 5 minute project too, because I couldn't rename and change enough things to produce a working _sha256 .so instead of sha256.so (to make room for sha256.py).

So, just delete it. Callers can use binascii.b2a_hex(h.digest()) easily enough.

comment:7 Changed at 2009-02-10T00:18:24Z by zooko

  • Cc tahoe-dev@… added

Hm, on reflection, I'm not sure that pycryptopp currently does anything with an exception from Crypto++ except re-raise it as a Python exception.

I hate, in principle to limit pycryptopp and its users to a single undifferentiated exception of type "exception from underlying library", when that underlying library is actually providing a carefully typed and informative exception.

But, in practice, this might make no different to our current code. I'll keep this in mind when returning to pycryptopp hacking after the tahoe-1.3.0 release.

comment:8 Changed at 2009-02-10T00:19:36Z by zooko

I agree about .hexdigest() -- I wouldn't mind removing it. I'm hoping that before I get around to deleting it, someone will fix pycryptopp to export only the right symbols and then the current code including .hexdigest() will start to work even when linked against the system libcryptopp.so, though...

comment:9 Changed at 2009-02-10T16:57:58Z by zooko

It looks like there is a nice fix:

http://allmydata.org/pipermail/tahoe-dev/2009-February/001153.html

The next step is to configure some builders to test this issue, by installing a Crypto++ shared library on those builders and passing the --disable-embedded-cryptopp flag to setup.py build.

comment:10 Changed at 2009-03-02T23:24:26Z by warner

Ok, we've got a "gutsy-syslib" builder now testing --disable-embedded-cryptopp. I fixed one debian-specific issue. The builder is currently red.

comment:11 Changed at 2009-03-02T23:27:48Z by warner

To use that RTLD_GLOBAL fix, I suspect we'll need to create a python wrapper library: aes.py will do from _aes import * or something, and then _aesmodule.so will contain all the C++ glue. That will give us the opportunity to mess around with dlopen flags before and after the _aes import, without obligating all users of this library to be aware of the problem.

I tried briefly to rearrange aesmodule.cpp to make this work, but I failed. I've done this successfully a long time ago, but it was both C (instead of C++) and using distutils (instead of setuptools).

comment:12 Changed at 2009-05-22T17:03:03Z by zooko

I wrote to the cryptopp mailing list asking for help with this, saying that the RTLD_GLOBAL seems a bit fragile:

http://groups.google.com/group/cryptopp-users/browse_thread/thread/eb815f228db50380

comment:13 Changed at 2009-05-24T23:34:15Z by zooko

  • Cc ruben@… ruben fernando.ribeiro@… doko@… micah@… added

Wei Dai suggested that I ask around on other lists, and I re-discovered the existence of the Python cplusplus-sig list, and summarized the problems and the four known ways forward:

http://mail.python.org/pipermail/cplusplus-sig/2009-May/014531.html

If Debian and Fedora representatives could look at this and advise me how to proceed I would appreciate it. Adding Cc: a set of people who hack on Debian and/or Ubuntu and/or Fedora and who have previously offered to help.

comment:14 Changed at 2009-05-26T22:10:07Z by zooko

Possibly related: the mysterious failure of dynamic_cast<> to downcast a private key in ecdsamodule.cpp:

http://groups.google.com/group/cryptopp-users/browse_thread/thread/c6e8d97b25733ee2

Okay, probably not related, but still interesting...

Note: See TracTickets for help on using tickets.