cryptlibConverter v.10 for cl3.2.2 snapshot September 13, 2005 Trevor Perrin =============================================================================== cryptlibConverter.py is a python script that parses cryptlib.h (from the cryptlib encryption library) and generates wrappers for cryptlib in java, python, and .NET: cryptlibConverter.py cryptlib.h [java|python|net] (make sure line-endings of cryptlib.h are appropriate for the system) In the bindings directory are pre-generated wrappers for the latest cryptlib 3.2.2. These can be copied directly into the ./bindings subdirectory of cryptlib. TestCryptlib.[java|py|cs] is a test program that demonstrates using cryptlib with these languages. Run it with no arguments for instructions. Everything in this package (cryptlibConverter.py, the code it generates, the test code) is in the public domain. See http://www.cs.auckland.ac.nz/~pgut001/cryptlib/ for cryptlib licensing details. Send questions, feedback, etc. to the address above. Java ----- The java version assumes the commands 'javac', 'jar', and 'javah' are on the path, and creates: ./cryptlib/crypt.java, .class ./cryptlib/CryptException.java, .class ./cryptlib/CRYPT_QUERY_INFO.java, .class ./cryptlib/CRYPT_OBJECT_INFO.java, .class ./cryptlib.jar (containing the above .class files) ./java_jni.c java_jni.c should be placed in the cryptlib bindings directory, then included in the cryptlib project, enabled with "#define USE_JAVA", and compiled into the shared library. This will require adding the JDK include directories to your compiler's settings (on Windows, this is \include, and \include\win32). You must use at least JDK 1.4. Once this is done, you can place cryptlib.jar on your classpath, the shared library on your path, and use System.loadLibrary() to load the shared library. Then you can start using cryptlib. crypt.java preserves much of the formatting from cryptlib.h, so it can serve as documentation of what functions are available, what their signatures are, etc.. All functions and constants are placed in the 'crypt' class, i.e.: crypt.SetAttribute(k, crypt.CTXINFO_KEYSIZE, 128); Instead of: cryptSetAttribute(k, CRYPT_CTXINFO_KEYSIZE, 128); A plethora of types are supported in place of pointers: - Java Strings can be used wherever the C interface requires an input char* or null-terminated void*. - Java byte arrays can be used wherever the C interface requires an input or output non-null-terminated void*. - As of JDK 1.4, there is an nio.ByteBuffer class which can be "direct", in which case they are arrays of bytes that are at a fixed memory location, so they can be passed to native code with zero copying. These can be passed to functions just like byte arrays, and will be more efficient. - Whenever passing a byte array or ByteBuffer as input, it can be followed by offset, length integers, or these can be omitted and will default to (0, length). Whenever passing a byte array or ByteBuffer for receiving output, it can be followed by an offset, which can be omitted and will default to 0. In C, cryptlib returns length values and handles through pass-by-address integers, and always has a status code as the return value. The java version instead throws CryptException for any status code besides CRYPT_OK, and migrates returned integer values to the return value. This means that function signatures are different than they are in C, so you may need to consult crypt.java to figure out what to pass to particular functions, and to understand error messages that refer to the position of a parameter. There is a special version of cryptGetAttributeString() which returns Strings, for convenience: String label = crypt.GetAttributeString(k, crypt.CTXINFO_LABEL); Python ------- Creates: ./python.c ./setup.py These should be placed in the cryptlib bindings directory. After building the cryptlib shared library, run "python setup.py install" to build and install the "cryptlib_py" extension module. Before running this on a UNIX platform, you may need to create a symbolic link from 'cl' to the actual cryptlib shared library, and specify additional libraries to link with in setup.py. You can now do "import cryptlib_py", or "from cryptlib_py import *", and then start using cryptlib. The python code accesses data through the "buffer" API. This API supports Python's strings and arrays, and also supports "Numeric" arrays which are a popular add-on. All these types are made availabe to the C code with zero copying. The python code does not have optional length and offset parameters, like the Java code. Python uses slicing syntax to select subsequences of a sequence, i.e. seq[startIndex:endIndex]. Slicing strings and arrays causes a copy, but "Numeric" arrays use view slicing, so they could be used for zero-copy operations on subsequences if you need that. Thus there's no need to provide explicit offset, length parameters. In C, cryptlib returns length values and handles through pass-by-address integers, and always has a status code as the return value. The python version instead throws CryptException for any status code besides CRYPT_OK, and migrates returned integer values to the return value. This means that function signatures are different than they are in C, so you may need to consult cryptlib_py.c and decode its call to 'PyArg_ParseTuples()' to figure out what to pass to particular functions, or to understand errror messages that refer to the position of a parameter. When returning handles, the python code returns objects of type 'CryptHandle', which inherits from integer, but adds overloads to support a "shortcut syntax" for getting/setting attributes with less typing: keyPair = cryptCreateContext(CRYPT_UNUSED, CRYPT_ALGO_RSA) # Verbose attribute syntax cryptSetAttributeString(keyPair, CRYPT_CTXINFO_LABEL, "blabla") # Shortcut attribute syntax keyPair.CTXINFO_KEYSIZE = 128 print keyPair.CTXINFO_NAME_ALGO .NET ----- Creates: ./cryptlib.cs This should be added to the .NET solution you'd like to use cryptlib from. Once this is done, you can place the shared library on your path, and start using cryptlib. crypt.cs preserves much of the formatting from cryptlib.h, so it can serve as documentation of what functions are available, what their signatures are, etc.. All functions and constants are placed in the 'crypt' class, i.e.: crypt.SetAttribute(k, crypt.CTXINFO_KEYSIZE, 128); Instead of: cryptSetAttribute(k, CRYPT_CTXINFO_KEYSIZE, 128); In place of pointers: - Strings can be used wherever the C interface requires an input char* or null- terminated void*. - byte arrays can be used wherever the C interface requires an input or output non-null-terminated void*. - Whenever passing a byte array as input, it can be followed by offset, length integers, or these can be omitted and will default to (0, length). Whenever passing a byte array for receiving output, it can be followed by an offset, which can be omitted and will default to 0. In C, cryptlib returns length values and handles through pass-by-address integers, and always has a status code as the return value. The .NET version instead throws CryptException for any status code besides CRYPT_OK, and migrates returned integer values to the return value. This means that function signatures are different than they are in C, so you may need to consult crypt.cs to figure out what to pass to particular functions, or to understand errror messages that refer to the position of a parameter. There is a special version of cryptGetAttributeString() which returns Strings, for convenience: String label = crypt.GetAttributeString(k, crypt.CTXINFO_LABEL); General Limitations -------------------- Ignores everything inside conditional directives (#if, #ifdef) in cryptlib.h, so if you want e.g. SHA2, you have to remove the conditionals manually. Can't handle cryptUIGenerateKey() or cryptUIDisplayCert(), since they're the only functions that take output char* and HWND parameters, and I haven't added support for these types. Doesn't support CRYPT_PKCSINFO_RSA or CRYPT_PKCINFO_DLP. CRYPT_QUERY_INFO and CRYPT_OBJECT_INFO are supported, see TestCryptlib for details. Python and Java don't have enumerated types. So all enums are just turned into integers (the .NET version does this as well, for consistency). The one exception to this is in Python, where handles are returned as instances of a type 'CryptHandle' which is defined within the module, and which is a child of integer. This class has overloads so that you can use a "shortcut" syntax to get/set the attributes of the cryptlib object. Python and Java don't have pass-by-reference primitive types. So in functions that accept such an integer, typically to return a length value or new object handle, it's migrated to the return value (the .NET version does this as well, for consistency). Instead of returning status values, these are converted to exceptions and thrown. Since it migrates any primitive pass-by-reference value it finds to the return value, it has trouble with cryptGetCertExtension(), which is the only function that takes two pass-by-reference ints. It resolves this by discarding the first such parameter (the criticalFlag in this case) when it finds two of them. The cryptlib error messages are returned directly, even though they sometimes refer to the position of C parameters, which might be different from the position of the Java, Python, or .NET parameters because of the above-mentioned migration of return values. So be wary of error messages that complain about the position of an argument. History -------- Version 10 - Fixed Java to work on Win CE (Unicode) Version 9 - Fixed C#/Java UTF-8 length problems updated to new directory structure updates tests for new attribute behavior Version 8 - In C# wrapper, ASCIIEncoding -> UTF8Encoding Version 7 - renamed cryptlibjni.c -> cryptlib_jni.c updated test scripts to account for the additional length parameter Version 6 - updated to deal with cryptlib.h's new C_STR type. Version 5 - added 'resolv' to python distutils on UNIX, fixed the test tls server script Version 4 - fixes memory bugs in .NET w/CRYPT_OBJECT_INFO, CRYPT_QUERY_INFO Version 3 - uses python distutils Acknowledgements ----------------- Jacques PHILIP found the memory bugs fixed in version 4 Alan Milligan helped with the python distutils Peter Gutmann wrote cryptlib