2008-10-27 11:16:54

Integer() is an int, but be aware that it's not

In Python's external ASN.1 toolkit features a special type, Integer(), which can be written to or fetched from an ASN.1 structure transparently. The resulting object, despite being an instance of pyasn1.Integer, behaves like any other integer: all operations can be applied as one would apply them to an integer.

All operations? Not quite! A single function parameter is holding out, strong as ever, against the integer compatibility. Life is not easy for the programmers attempting to make use of the resulting objects.

In fact it's quite funny: the problem is with the function pow. As the documentation says:

In [1]: pow.__doc__
Out[1]: 'pow(x, y[, z]) -> number\n\nWith two arguments, equivalent to x**y. With three arguments,\nequivalent to (x**y) % z, but may be more efficient (e.g. for longs).'

Since crypto wants speed, and ASN.1 is frequently used in crypto, we now try to combine pyasn1 and the amk crypto toolkit, since Python itself does not contain any crypto. We use the DSA sign function, which basically only calls pow() for us. This is where we get bitten. The reason is simple and astonishing:

In [2]: i = pyasn1.type.univ.Integer(23)
In [3]: pow(i, 23)
Out[3]: Integer('20880467999847912034355032910567')
In [4]: pow(23, i)
Out[4]: Integer('20880467999847912034355032910567')
In [5]: pow(23, 23, i)
TypeError Traceback (most recent call last)

/home/tonnerre/<ipython console> in <module>()

TypeError: unsupported operand type(s) for pow(): 'int', 'int', 'instance'

In [6]:

Astonishingly, the Integer instance is allowed as the first and second argument to pow(), but not as the third one. More astonishingly, all of them are supposed to be ints. Even more weirdly, if pow is called with 3 pyasn1 Integer()s, the error message is still the same: the first two Integer()s are said to be int, the last one remains an instance.

Posted by Tonnerre Lombard | Permanent link | File under: broken, programming