import sys import os import stat import re #Helper Functions #========================================================================== def parseEnumContents(enumContents, nameSpace, debugString): enumPattern = re.compile(r"(CRYPT_[\w_]*)\s*(=.*?)?(\Z|,|(?=/))", re.DOTALL) # %1 [= %2][,] commentPattern = re.compile(r"\s*/\*(.*)\*/") # /* %1 */ counter = 0 #Keep track of the implicit enum value enumTuples = [] #Build a list of (key, val, comment) tuples, one for each enum value #Find the next "enum value" enumMatch = enumPattern.search(enumContents) while enumMatch: #Extract the key and RHS value rawKey, rawVal = enumMatch.groups()[:-1] key = rawKey.rstrip() if not key.startswith("CRYPT_"): raise "enum'd value doesn't start with CRYPT_ "+key key = key.replace("CRYPT_", "") #Evaluate the RHS (if it exists) to get the value if rawVal: rhs = rawVal[1:].strip().replace("CRYPT_", "") val = eval(rhs, nameSpace) #Otherwise the value is the implicit counter else: val = counter #Extract the comment commentMatch = commentPattern.match(enumContents, enumMatch.end()) if commentMatch: rawComment = commentMatch.group(1) comment = rawComment.strip() else: comment = "" #Collect all the parsed values into a tuple enumTuple = (key, str(val), comment) #if comment: # print debugString+ ":" + " Parsed Element %s = %s /* %s */" % enumTuple #else: # print debugString+ ":" + " Parsed Element %s = %s" % enumTuple[:-1] #raw_input() nameSpace[key] = val #Add new enum value into namespace counter = val + 1 #Increment implicit enum value #Accumulate the parsed (key, val, comment) tuples enumTuples.append(enumTuple) #Get next enum value enumMatch = enumPattern.search(enumContents, enumMatch.end()) return enumTuples #Parses a string of function parameters into a list of ParamStruct class ParamStruct: def __init__(self): self.type = "" self.isPtr = 0 self.isOut = 0 self.category = "" self.name = "" self.rawIndex = 0 # The index of this param in the initial, raw cryptlib header def __str__(self): return str( (self.type, self.isPtr, self.category, self.name, self.rawIndex) ) def parseFunctionParams(functionParams): paramStructs = [] functionParams = functionParams.replace("\n", "") #Make one big line functionParamsList = [e.strip() for e in functionParams.split(",")] #Break into a list of params index = 0 for e in functionParamsList: pieces = e.split(" ") #Separate each param into component pieces, ie ["C_IN", "CRYPT_ALGO_TYPE", "cryptAlgo"] p = ParamStruct() if len(pieces)==1 and pieces[0]=="void": continue elif len(pieces)==3: if pieces[0] == "C_OUT": p.isOut = 1 if pieces[0] == "C_OUT_OPT": p.isOut = 1 if pieces[1] == "C_STR": p.type = "char" p.name = pieces[2] p.isPtr = 1 else: p.type = pieces[1] p.name = pieces[2] p.isPtr = 0 elif len(pieces)==4: #Ie ["C_OUT", "CRYPT_CONTEXT", "C_PTR", "cryptContext"] if pieces[0] == "C_OUT": p.isOut = 1 if pieces[0] == "C_OUT_OPT": p.isOut = 1 p.type = pieces[1] if pieces[2] == "C_PTR": p.isPtr = 1 else: raise "Expecting C_PTR in parseFunctionParams" p.name = pieces[3] else: raise "parsing error in parseFunctionParams" if p.type in enumTypes: p.category = "enumType" elif p.type in intTypes: p.category = "intType" elif p.type in structTypes: p.category = "structType" elif p.type in rawTypes: p.category = "rawType" else: raise "unknown type error is parseFunctionParams" p.rawIndex = index index += 1 paramStructs.append(p) #for p in paramStructs: # print p.__dict__ #raw_input() return paramStructs #Takes a string containing a JNI function parameters prototype list, and a list of ParamStructs #And injects names into the string and returns it def expandFunctionPrototype(functionPrototype, newParamStructs): functionPrototype = functionPrototype.replace("\n", "") #Make one big line paramPrototypesList = [e.strip() for e in functionPrototype.split(",")] #Break into a list of params paramNamesList = ["env", "cryptClass"] + [e.name for e in newParamStructs] newFunctionParams = "" for (p1, p2) in zip(paramPrototypesList, paramNamesList): newFunctionParams += p1 + " " + p2 + ", " newFunctionParams = newFunctionParams[:-2] return newFunctionParams #Main #========================================================================= #Execution starts here... #========================================================================= if len(sys.argv) != 4: print "cryptlibConverter.py " sys.exit() inFile = sys.argv[1] outDir = sys.argv[2] language = sys.argv[3] if not os.path.exists(outDir): print "Making output directory..." os.mkdir(outDir) if not language in ("java", "python", "net"): print "only java, python, and net are supported!" sys.exit() if language == "java": #ENUM IDIOM #typedefEnumTemplate = "public static class %(typedefName)s\n{public int getValue(){return m_value;}private %(typedefName)s(int value){m_value = value;}int m_value;}" #typedefEnumElementTemplate = "public static final %(typedefName)s %(name)-NPADs = new %(typedefName)s(%(value)-VPADs);" #ENUMs as ints typedefEnumTemplate = "// %(typedefName)s" typedefEnumElementTemplate = "public static final int %(name)-NPADs = %(value)-VPADs;" typedefEnumElementTemplateComment = typedefEnumElementTemplate + " // %(comment)s" simpleEnumElementTemplate = "public static final int %(name)-NPADs = %(value)-VPADs;" simpleEnumElementTemplateComment = simpleEnumElementTemplate + " // %(comment)s" defineNPad = "40" defineVPad = "4" defineTemplate = simpleEnumElementTemplate defineTemplateComment = simpleEnumElementTemplateComment exceptionPrefix = """ package cryptlib; public class CryptException extends Exception { private int m_status; private String m_message; public CryptException(int status) { m_status = status; String prefix = Integer.toString(status) + ": "; """ exceptionPostfix = """\ m_message = prefix + "Unknown Exception ?!?!"; } public int getStatus() { return m_status; } public String getMessage() { return m_message; } };""" exceptionTemplate = """\ if (m_status == crypt.%(name)s) { m_message = prefix + "%(comment)s"; return; } """ cryptQueryInfoString = """ package cryptlib; public class CRYPT_QUERY_INFO { public String algoName; public int blockSize; public int minKeySize; public int keySize; public int maxKeySize; public CRYPT_QUERY_INFO(String newAlgoName, int newBlockSize, int newMinKeySize, int newKeySize, int newMaxKeySize) { algoName = newAlgoName; blockSize = newBlockSize; minKeySize = newMinKeySize; keySize = newKeySize; maxKeySize = newMaxKeySize; } };""" cryptObjectInfoString = """ package cryptlib; public class CRYPT_OBJECT_INFO { public int objectType; public int cryptAlgo; public int cryptMode; public int hashAlgo; public byte[] salt; public CRYPT_OBJECT_INFO(int newObjectType, int newCryptAlgo, int newCryptMode, int newHashAlgo, byte[] newSalt) { objectType = newObjectType; cryptAlgo = newCryptAlgo; cryptMode = newCryptMode; hashAlgo = newHashAlgo; salt = newSalt; } };""" addFunctionWrappers = 1 wholeFunctionDeclaration = None functionDeclaration = "public static native " returnIntDeclaration = "int " returnVoidDeclaration = "void " paramsPrefix = "(" paramsPostfix = ") throws CryptException;" paramWhiteSpace = "\t\t\t\t\t\t" paramVoidPtrTemplate = "java.nio.ByteBuffer %(name)s,\n" addFunctionAlternate = 1 paramVoidPtrAlternate = ("java.nio.ByteBuffer", "byte[]") paramCharPtrTemplate = "String %(name)s,\n" paramIntTemplate = "int %(name)s,\n" paramIntTypeTemplate = "int %(name)s, // %(type)s\n" #wrapperLengthTemplate = "%s.capacity(), " #wrapperStringLengthTemplate = "%s.length(), " wrapperLengthTemplate = "%(1)s == null ? 0 : %(1)s.capacity(), " wrapperStringLengthTemplate = "%(1)s == null ? 0 : %(1)s.getBytes().length, " wrapperStringReplace = ("java.nio.ByteBuffer", "String") wrapperStringTemplate = '%(1)s == null ? null : %(1)s.getBytes()' #ENUM IDIOM #paramEnumTypeTemplate = "%(type)s %(name)s,\n" #ENUMs as ints paramEnumTypeTemplate = "int %(name)s, // %(type)s\n" commentPrefix = "//" classPrefix = "package cryptlib;\n\nimport java.nio.*;\n\npublic class crypt\n{\n" classPostfix = "\n};" sFuncs = None sInts = None elif language == "python": typedefEnumTemplate = "" #typedefEnumElementTemplate = "%(name)-NPADs = %(value)-VPADs" typedefEnumElementTemplate = """\ v = Py_BuildValue("i", CRYPT_%(name)s); PyDict_SetItemString(moduleDict, "CRYPT_%(name)s", v); Py_DECREF(v);""" typedefEnumElementTemplateComment = typedefEnumElementTemplate + " /* %(comment)s */" simpleEnumElementTemplate = typedefEnumElementTemplate simpleEnumElementTemplateComment = typedefEnumElementTemplateComment defineNPad = "40" defineVPad = "4" defineTemplate = typedefEnumElementTemplate defineTemplateComment = typedefEnumElementTemplateComment exceptionPrefix = "" exceptionPostfix = "" exceptionTemplate = """\ else if (status == CRYPT_%(name)s) o = Py_BuildValue("(is)", CRYPT_%(name)s, "%(comment)s"); """ addFunctionWrappers = 0 wholeFunctionDeclaration = """\ static PyObject* python_crypt%s(PyObject* self, PyObject* args) { } """ moduleFunctionEntry = "\t{ \"crypt%s\", python_crypt%s, METH_VARARGS }, " pyBeforeExceptions = r""" #include #include "../cryptlib.h" static PyObject* cryptHandleClass; static PyObject* cryptQueryInfoClass; static PyObject* cryptObjectInfoClass; static PyObject *CryptException; static int getPointerWrite(PyObject* objPtr, unsigned char** bytesPtrPtr, int* lengthPtr) { if (objPtr == Py_None) { *bytesPtrPtr = NULL; *lengthPtr = 0; return 1; } Py_ssize_t size = 0; /*See if it's an array object*/ if (PyObject_AsWriteBuffer(objPtr, (void **)bytesPtrPtr, &size) == -1) return 0; *lengthPtr = size; return 1; } static int getPointerRead(PyObject* objPtr, unsigned char** bytesPtrPtr, int* lengthPtr) { if (objPtr == Py_None) { *bytesPtrPtr = NULL; *lengthPtr = 0; return 1; } Py_ssize_t size = 0; /*See if it's an array object*/ if (PyObject_AsWriteBuffer(objPtr, (void **)bytesPtrPtr, &size) == -1) { PyErr_Clear(); /*See if it's a string object*/ /*This returns the length excluding the NULL if it's a string, which is what we want*/ if (PyObject_AsCharBuffer(objPtr, (const char **)bytesPtrPtr, &size) == -1) return 0; } *lengthPtr = size; return 1; } static int getPointerReadNoLength(PyObject* objPtr, unsigned char** bytesPtrPtr) { int length; return getPointerRead(objPtr, bytesPtrPtr, &length); } static int getPointerWriteCheckIndices(PyObject* objPtr, unsigned char** bytesPtrPtr, int* lengthPtr) { int checkLength = *lengthPtr; if (getPointerWrite(objPtr, bytesPtrPtr, lengthPtr) == 0) return 0; //If sequence is non-NULL and too short... if (*bytesPtrPtr && (*lengthPtr < checkLength)) { PyErr_SetString(PyExc_IndexError, "A sequence passed to cryptlib was too small"); return 0; } return 1; } static int getPointerReadString(PyObject* objPtr, char** charPtrPtr) { Py_ssize_t length = 0; char* newPtr = NULL; if (objPtr == Py_None) { *charPtrPtr = NULL; return 1; } /*See if it's a string or a buffer object*/ if (PyObject_AsCharBuffer(objPtr, charPtrPtr, &length) == -1) { /*See if it's an array*/ PyErr_Clear(); if (PyObject_AsWriteBuffer(objPtr, charPtrPtr, &length) == -1) return 0; } /*This code isn't necessary for a string, but it is for arrays and buffers, so we do it always anyway, since the PyObject_AsCharBuffer apparently doesn't guarantee us null-terminated data, and this way releasePointerString() doesn't have to differentiate */ newPtr = malloc(length+1); if (newPtr == NULL) { PyErr_NoMemory(); return 0; } memcpy(newPtr, *charPtrPtr, length); newPtr[length] = 0; *charPtrPtr = newPtr; return 1; } static void releasePointer(PyObject* objPtr, unsigned char* bytesPtr) { } static void releasePointerString(PyObject* objPtr, char* charPtr) { free(charPtr); } static PyObject* processStatus(int status) { PyObject* o = NULL; /* If an error has already occurred, ignore the status and just fall through */ if (PyErr_Occurred()) return(NULL); if (status >= CRYPT_OK) return(Py_BuildValue("")); """ pyBeforeFuncs = """\ PyErr_SetObject(CryptException, o); Py_DECREF(o); return(NULL); } static int processStatusBool(int status) { PyObject* o = processStatus(status); if (o == NULL) return(0); else { Py_DECREF(o); return(1); } } static PyObject* processStatusReturnInt(int status, int returnValue) { PyObject* o = processStatus(status); if (o == NULL) return(0); else { Py_DECREF(o); o = Py_BuildValue("i", returnValue); return(o); } } static PyObject* processStatusReturnCryptHandle(int status, int returnValue) { PyObject* o2; PyObject* o = processStatus(status); if (o == NULL) return(0); else { Py_DECREF(o); o2 = Py_BuildValue("(i)", returnValue); o = PyObject_CallObject(cryptHandleClass, o2); Py_DECREF(o2); return(o); } } static PyObject* processStatusReturnCryptQueryInfo(int status, CRYPT_QUERY_INFO returnValue) { PyObject* o2; PyObject* o = processStatus(status); if (o == NULL) return(0); else { Py_DECREF(o); o2 = Py_BuildValue("(siiii)", returnValue.algoName, returnValue.blockSize, returnValue.minKeySize, returnValue.keySize, returnValue.maxKeySize); o = PyObject_CallObject(cryptQueryInfoClass, o2); Py_DECREF(o2); return(o); } } static PyObject* processStatusReturnCryptObjectInfo(int status, CRYPT_OBJECT_INFO returnValue) { PyObject* o2; PyObject* o = processStatus(status); if (o == NULL) return(0); else { Py_DECREF(o); o2 = Py_BuildValue("(iiiis#)", returnValue.objectType, returnValue.cryptAlgo, returnValue.cryptMode, returnValue.hashAlgo, returnValue.salt, returnValue.saltSize); o = PyObject_CallObject(cryptObjectInfoClass, o2); Py_DECREF(o2); return(o); } } """ pyBeforeModuleFunctions = """ static PyMethodDef module_functions[] = { """ pyBeforeInts = r""" {0, 0} }; #if PY_MAJOR_VERSION >= 3 static struct PyModuleDef moduledef = { PyModuleDef_HEAD_INIT, "cryptlib_py", NULL, -1, module_functions, NULL, NULL, NULL, NULL }; #endif PyMODINIT_FUNC #if PY_MAJOR_VERSION >= 3 PyInit_cryptlib_py(void) #else initcryptlib_py(void) #endif { PyObject* module; #if PY_MAJOR_VERSION >= 3 module = PyModule_Create(&moduledef); if (module == NULL){ return NULL; } #else module = Py_InitModule("cryptlib_py", module_functions); #endif PyObject* moduleDict; PyObject* v = NULL; PyObject *globalsDict; moduleDict = PyModule_GetDict(module); CryptException = PyErr_NewException("cryptlib_py.CryptException", NULL, NULL); PyDict_SetItemString(moduleDict, "CryptException", CryptException); globalsDict = PyEval_GetGlobals(); PyRun_String( "from array import *\n\ import types\n\ class CryptHandle:\n\ def __init__(self, value):\n\ self.__dict__['value'] = value\n\ def __int__(self):\n\ return self.value\n\ def __str__(self):\n\ return str(self.value)\n\ def __repr__(self):\n\ return str(self.value)\n\ def __getattr__(self, name):\n\ name = name.upper()\n\ if not name.startswith('CRYPT_'):\n\ name = 'CRYPT_' + name\n\ nameVal = globals()[name]\n\ try:\n\ return cryptGetAttribute(self, nameVal)\n\ except CryptException:\n\ length = cryptGetAttributeString(self, nameVal, None)\n\ buf = array('c', '0' * length)\n\ length = cryptGetAttributeString(self, nameVal, buf)\n\ return ''.join(buf[:length])\n\ def __setattr__(self, name, value):\n\ name = name.upper()\n\ if not name.startswith('CRYPT_'):\n\ name = 'CRYPT_' + name\n\ nameVal = globals()[name]\n\ if isinstance(value, types.IntType) or isinstance(value, CryptHandle):\n\ cryptSetAttribute(self, nameVal, value)\n\ else:\n\ cryptSetAttributeString(self, nameVal, value)\n", Py_file_input, globalsDict, moduleDict); PyRun_String( "class CRYPT_QUERY_INFO:\n\ def __init__(self, algoName, blockSize, minKeySize, keySize, maxKeySize):\n\ self.algoName = algoName\n\ self.blockSize = blockSize\n\ self.minKeySize = minKeySize\n\ self.keySize = keySize\n\ self.maxKeySize = maxKeySize\n", Py_file_input, globalsDict, moduleDict); PyRun_String( "class CRYPT_OBJECT_INFO:\n\ def __init__(self, objectType, cryptAlgo, cryptMode, hashAlgo, salt):\n\ self.objectType = objectType\n\ self.cryptAlgo = cryptAlgo\n\ self.cryptMode = cryptMode\n\ self.hashAlgo = hashAlgo\n\ self.salt = salt\n", Py_file_input, globalsDict, moduleDict); cryptHandleClass = PyMapping_GetItemString(moduleDict, "CryptHandle"); cryptQueryInfoClass = PyMapping_GetItemString(moduleDict, "CRYPT_QUERY_INFO"); cryptObjectInfoClass = PyMapping_GetItemString(moduleDict, "CRYPT_OBJECT_INFO"); Py_DECREF(globalsDict); """ pyAfterInts = """ #if PY_MAJOR_VERSION >= 3 return module; #endif }""" paramCharPtrTemplate = "%(name)s, # string\n" paramIntTemplate = "%(name)s, # integer\n" paramIntTypeTemplate = "%(name)s, # %(type)s\n" paramEnumTypeTemplate = "%(name)s, # %(type)s\n" commentPrefix = "# " #pad to 2-characters for formatting consistency classPrefix = "class crypt:\n" classPostfix= "" outFile = os.path.join(outDir, "cryptlib.py") sFuncs = "\n" sInts = "\n" sModFuncs = "" setupPy = r"""#!/usr/bin/env python from distutils.core import setup, Extension import sys if sys.platform == "win32": ext = Extension("cryptlib_py", sources=["python.c"], library_dirs=['../binaries'], libraries=['cl32']) else: ext = Extension("cryptlib_py", sources=["python.c"], library_dirs=['..'], libraries=['cl']) setup(name="cryptlib_py", ext_modules=[ext]) """ elif language == "net": typedefEnumTemplate = "// %(typedefName)s" typedefEnumElementTemplate = "public const int %(name)-NPADs = %(value)-VPADs;" typedefEnumElementTemplateComment = typedefEnumElementTemplate + " // %(comment)s" simpleEnumElementTemplate = "public const int %(name)-NPADs = %(value)-VPADs;" simpleEnumElementTemplateComment = simpleEnumElementTemplate + " // %(comment)s" defineNPad = "40" defineVPad = "4" defineTemplate = simpleEnumElementTemplate defineTemplateComment = simpleEnumElementTemplateComment exceptionPrefix = """ [StructLayout(LayoutKind.Sequential, Pack=0, CharSet=CharSet.Ansi)] public class CRYPT_QUERY_INFO { [MarshalAs(UnmanagedType.ByValTStr, SizeConst=64)]public String algoName; public int blockSize; public int minKeySize; public int keySize; public int maxKeySize; public CRYPT_QUERY_INFO(){} public CRYPT_QUERY_INFO(String newAlgoName, int newBlockSize, int newMinKeySize, int newKeySize, int newMaxKeySize) { algoName = newAlgoName; blockSize = newBlockSize; minKeySize = newMinKeySize; keySize = newKeySize; maxKeySize = newMaxKeySize; } } [StructLayout(LayoutKind.Sequential, Pack=0, CharSet=CharSet.Ansi)] public class CRYPT_OBJECT_INFO { public int objectType; public int cryptAlgo; public int cryptMode; public int hashAlgo; [MarshalAs(UnmanagedType.ByValArray, SizeConst=32)]public byte[] salt; public int saltSize; public CRYPT_OBJECT_INFO() { salt = new byte[64]; saltSize = 64; } public CRYPT_OBJECT_INFO(int newObjectType, int newCryptAlgo, int newCryptMode, int newHashAlgo, byte[] newSalt) { objectType = newObjectType; cryptAlgo = newCryptAlgo; cryptMode = newCryptMode; hashAlgo = newHashAlgo; } } public class CryptException : ApplicationException { public int Status { get { return (int)Data["Status"]; } } public int ExtraInfo { get { return (int)Data["ExtraInfo"]; } } public CryptException(int status) : base(convertMessage(status)) { Data.Add("Status", status); } public CryptException(int status, int extra) : base(convertMessage(status)) { Data.Add("Status", status); Data.Add("ExtraInfo", extra); } private static string convertMessage(int status) { String prefix = Convert.ToString(status) + ": "; switch (status) { """ exceptionPostfix = """\ default: return prefix + "Unknown Exception ?!?!"; } } }""" exceptionTemplate = """\ case crypt.%(name)s: return prefix + "%(comment)s"; """ addFunctionWrappers = 1 wholeFunctionDeclaration = None functionDeclaration = "public static " returnIntDeclaration = "int " returnVoidDeclaration = "void " paramsPrefix = "(" paramsPostfix = ");" paramWhiteSpace = "\t\t\t\t\t\t" paramVoidPtrTemplate = "byte[] %(name)s,\n" addFunctionAlternate = 0 paramCharPtrTemplate = "String %(name)s,\n" paramIntTemplate = "int %(name)s,\n" paramIntTypeTemplate = "int %(name)s, // %(type)s\n" wrapperLengthTemplate = "%(1)s == null ? 0 : %(1)s.Length, " wrapperStringLengthTemplate = "%(1)s == null ? 0 : new UTF8Encoding().GetByteCount(%(1)s), " wrapperStringReplace = ("byte[]", "String") wrapperStringTemplate = "%(1)s == null ? null : new UTF8Encoding().GetBytes(%(1)s)" #ENUM IDIOM #paramEnumTypeTemplate = "%(type)s %(name)s,\n" #ENUMs as ints paramEnumTypeTemplate = "int %(name)s, // %(type)s\n" commentPrefix = "//" classPrefix = """using System; using System.Runtime.InteropServices; using System.Text; namespace cryptlib { public class crypt { """ classPostfix = """ /* Helper Functions */ private static void processStatus(int status) { if (status < crypt.OK) throw new CryptException(status); } private static void processStatus(int status, int extraInfo) { if (status < crypt.OK) throw new CryptException(status, extraInfo); } private static void checkIndices(byte[] array, int sequenceOffset, int sequenceLength) { if (array == null) { if (sequenceOffset == 0) return; else throw new IndexOutOfRangeException(); } int arrayLength = array.Length; if (sequenceOffset < 0 || sequenceOffset >= arrayLength || sequenceOffset + sequenceLength > arrayLength) throw new IndexOutOfRangeException(); } private static void getPointer(byte[] buffer, int bufferOffset, ref GCHandle bufferHandle, ref IntPtr bufferPtr) { if (buffer == null) return; bufferHandle = GCHandle.Alloc(buffer, GCHandleType.Pinned); bufferPtr = Marshal.UnsafeAddrOfPinnedArrayElement(buffer, bufferOffset); } private static void releasePointer(GCHandle bufferHandle) { if (bufferHandle.IsAllocated) bufferHandle.Free(); } } """ sFuncs = None sInts = None s = open(inFile).read() inFileTabSize = 4 #Global variables #These accumulate information about the types in the input file #---------------------------------------------------------------- nameSpace = {} #Accumulate enum'd values here and use them to eval() the RHS of new ones enumTypes = [] #Accumulate typedef'd enum types here intTypes = [] #Accumulate typedef'd int types here structTypes = []#Accumulate typedef'd struct types here rawTypes = ["char", "int", "void"] functionNames = [] #Accumulate function names here rawParamStructsDict = {} #Accumulate function name -> list of ParamStructs (of original c code) newParamStructsDict = {} #Accumulate function name -> list of ParamStructs (of new java/python code) newReturnStructsDict = {} #Accumulate function name -> ParamStruct of return parameter (of new java/python code) newDiscardedStructsDict = {} #Accumulate function name -> ParamStruct of discarded parameter lengthIndicesDict = {} #Accumulate function name -> indices in newParamStructs of lengths (used for python) offsetIndicesDict= {} #Accumulate function name -> indices in newParamStructs of offsets (used for python) errors = {} #Dictionary mapping return values to exception objects print "Parsing input file and generating %s files..." % language #Removing enclosing include guard #--------------------------------- s = re.search(r"#ifndef _CRYPTLIB_DEFINED\n(.*)\n#endif", s, re.DOTALL).group(1) #Ignore anything before "#define C_INOUT..." #-------------------------------------------- s = s[re.search(r"#define C_INOUT.*?\n", s, re.DOTALL).end() : ] #Remove all conditionals #------------------------ while 1: endifMatch = re.search(r"#endif.*?\n", s, re.DOTALL) if endifMatch == None: break ifdefIndex = s.rfind("#if", 0, endifMatch.start()) s = s[ : ifdefIndex] + s[endifMatch.end() : ] s = re.sub(r'\n\s*/\*.*\*/\s*\n', lambda match: '' if match.group(0).find('CRYPT_') >= 0 else match.group(0), s) #Delete lines used for extended function and function-parameter checking #like C_CHECK_RETVAL C_NONNULL_ARG( ( 3 ) ) \ #-------------------------------------------- functionParamterPattern = re.compile(r"((C_CHECK_RETVAL|C_NONNULL_ARG\s*\(\s*\([ \t0-9,]+\s*\)\s*\))\s+(\\\n)?)", re.DOTALL) while 1: deleteExtended = functionParamterPattern.search(s) if deleteExtended == None: break s = s[ : deleteExtended.start(1) ] + s[ deleteExtended.end(1) : ] #Replace typedef enums #---------------------- typedefEnumPattern = re.compile(r"typedef[ \t]+enum[ \t]+{([^}]*)}\s*(\w*);", re.DOTALL) # typedef enum { %1 } %2; #Find the next typedef enum typedefEnumMatch = typedefEnumPattern.search(s) while typedefEnumMatch: #Extract its contents and type name enumContents, typedefName = typedefEnumMatch.groups() enumTypes.append(typedefName) #Parse its contents enumTuples = parseEnumContents(enumContents, nameSpace, "typedef") #Determine the length to pad names to namePad = str( max( [len(e[0]) for e in enumTuples] ) ) valuePad = str( max( [len(e[1]) for e in enumTuples] ) ) #Construct its output equivalent from language-specific string templates newTypedefEnum = typedefEnumTemplate % vars() for enumTuple in enumTuples: name, value, comment = enumTuple if not comment: paddedTemplate = typedefEnumElementTemplate.replace("NPAD", namePad).replace("VPAD", valuePad) newEnum = paddedTemplate % vars() else: paddedTemplate = typedefEnumElementTemplateComment.replace("NPAD", namePad).replace("VPAD", valuePad) newEnum = paddedTemplate % vars() if newTypedefEnum: newTypedefEnum += "\n" #Don't always add this or we'll get extraneous newlines in python newTypedefEnum += newEnum #print "Output Equivalent of Typedef Enum====\n", newTypedefEnum #raw_input() if sInts: sInts += newTypedefEnum + "\n" #Substitute the output equivalent for the input s = s[ : typedefEnumMatch.start()] + newTypedefEnum + s[typedefEnumMatch.end() : ] #Get next typedef typedefEnumMatch = typedefEnumPattern.search(s, typedefEnumMatch.start() + len(newTypedefEnum)) #print "ENUMTYPES:\n",enumTypes #Replace simple enums #--------------------- #This works on the theory that we've already replaced all typedef enums with #something that doesn't use the word "enum", so any remaining occurrences of #enum will belong to simple enums. simpleEnumPattern = re.compile(r"enum[ \t]+{([^}]*)};", re.DOTALL) # enum { %1 }; #Find the next simple enum simpleEnumMatch = simpleEnumPattern.search(s) while simpleEnumMatch: #Extract its contents enumContents = simpleEnumMatch.group(1) #Parse its contents enumTuples = parseEnumContents(enumContents, nameSpace, "simple") #Determine the length to pad names to namePad = str( max( [len(e[0]) for e in enumTuples] ) ) valuePad = str( max( [len(e[1]) for e in enumTuples] ) ) #Construct its output equivalent from language-specific string templates newSimpleEnum = "" for enumTuple in enumTuples: name, value, comment = enumTuple if not comment: paddedTemplate = simpleEnumElementTemplate.replace("NPAD", namePad).replace("VPAD", valuePad) newEnum = paddedTemplate % vars() else: paddedTemplate = simpleEnumElementTemplateComment.replace("NPAD", namePad).replace("VPAD", valuePad) newEnum = paddedTemplate % vars() if newSimpleEnum: newSimpleEnum += "\n" #Don't always add this or we'll get extraneous newlines in python newSimpleEnum += newEnum #print "Output Equivalent of Simple Enum====\n", newSimpleEnum #raw_input() if sInts: sInts += newSimpleEnum + "\n" #Substitute the output equivalent for the input s = s[ : simpleEnumMatch.start()] + newSimpleEnum + s[simpleEnumMatch.end() : ] #Get next typedef simpleEnumMatch = simpleEnumPattern.search(s, simpleEnumMatch.start() + len(newSimpleEnum)) #Replace #define'd constants #---------------------------- definePattern = re.compile(r"#define[ \t]+(\w+)[ \t]+([-\w]+)[ \t]*(/\*.*\*/*)?") # #define %1 %2 [/*%3*/] exceptionString = exceptionPrefix #Find the next #define defineMatch = definePattern.search(s) while defineMatch: #Parse its contents name, value, comment = defineMatch.groups() if not name.startswith("CRYPT_"): raise "name doesn't start with CRYPT_"+name name = name.replace("CRYPT_", "") #Construct its output equivalent from language-specific string templates if not comment: paddedTemplate = defineTemplate.replace("NPAD", defineNPad).replace("VPAD", defineVPad) newDefine = paddedTemplate % vars() else: comment = comment[2:-2].strip() paddedTemplate = defineTemplateComment.replace("NPAD", defineNPad).replace("VPAD", defineVPad) newDefine = paddedTemplate % vars() #print "define: " + newDefine #raw_input() if sInts: sInts += newDefine + "\n" #Substitute the output equivalent for the input s = s[ : defineMatch.start()] + newDefine + s[defineMatch.end() : ] #Append to exception string if error if name.startswith("ERROR_") or name.startswith("ENVELOPE_RESOURCE"): exceptionString += exceptionTemplate % vars() #Get next #define defineMatch = definePattern.search(s, defineMatch.start() + len(newDefine)) exceptionString += exceptionPostfix #Replace #define'd constants with parenthesis #-------------------------------------------- definePattern = re.compile(r"#define[ \t]+(\w+)[ \t]+\([ \t]*([-0-9]+)[ \)]*\)[ \t]*(/\*.*\*/*)?") # #define %1 ( %2 ) [/*%3*/] exceptionString = exceptionPrefix #Find the next #define defineMatch = definePattern.search(s) while defineMatch: #Parse its contents name, value, comment = defineMatch.groups() if not name.startswith("CRYPT_"): raise "name doesn't start with CRYPT_"+name name = name.replace("CRYPT_", "") #Construct its output equivalent from language-specific string templates if not comment: paddedTemplate = defineTemplate.replace("NPAD", defineNPad).replace("VPAD", defineVPad) newDefine = paddedTemplate % vars() else: comment = comment[2:-2].strip() paddedTemplate = defineTemplateComment.replace("NPAD", defineNPad).replace("VPAD", defineVPad) newDefine = paddedTemplate % vars() #print "define: " + newDefine #raw_input() if sInts: sInts += newDefine + "\n" #Substitute the output equivalent for the input s = s[ : defineMatch.start()] + newDefine + s[defineMatch.end() : ] #Append to exception string if error if name.startswith("ERROR_") or name.startswith("ENVELOPE_RESOURCE"): exceptionString += exceptionTemplate % vars() #Get next #define defineMatch = definePattern.search(s, defineMatch.start() + len(newDefine)) exceptionString += exceptionPostfix #Comment out #define'd macros #----------------------------- definePattern = re.compile(r"#define[ \t]+[^(]+\([^\)]*\)([^\n]*\\\n)*[^\n]*") defineMatch = definePattern.search(s) while defineMatch: #print "defined macros:", defineMatch.group() #raw_input() define = defineMatch.group() newDefine = commentPrefix + "CRYPTLIBCONVERTER - NOT SUPPORTED:\n" + define newDefine = newDefine.replace("\n", "\n"+commentPrefix) s = s[ : defineMatch.start()] + newDefine + s[defineMatch.end() : ] defineMatch = definePattern.search(s, defineMatch.start() + len(newDefine)) #Comment out typedef integer types #---------------------------------- typedefIntPattern = re.compile(r"typedef[ \t]+int[ \t]+([^ \t]*)[ \t]*;[ \t]*\n") typedefIntMatch = typedefIntPattern.search(s) while typedefIntMatch: typedefInt = typedefIntMatch.group() typedefIntName = typedefIntMatch.group(1) intTypes.append(typedefIntName) #print "typedef int:", typedefInt #raw_input() newTypedefInt = commentPrefix + "CRYPTLIBCONVERTER - NOT NEEDED: " + typedefInt s = s[ : typedefIntMatch.start()] + newTypedefInt + s[typedefIntMatch.end() : ] typedefIntMatch = typedefIntPattern.search(s, typedefIntMatch.start() + len(newTypedefInt)) #print "INTTYPES:\n",intTypes #Comment out typedef structs #---------------------------- typedefStructPattern = re.compile(r"typedef[ \t]+struct[ \t]\{[^}]*}[ \t]*([^;]+);") typedefStructMatch = typedefStructPattern.search(s) while typedefStructMatch: typedefStruct = typedefStructMatch.group() typedefStructName = typedefStructMatch.group(1) structTypes.append(typedefStructName) #print "typedef struct:", typedefStructName #raw_input() newTypedefStruct = commentPrefix + "CRYPTLIBCONVERTER - NOT SUPPORTED:\n" + typedefStruct newTypedefStruct = newTypedefStruct.replace("\n", "\n"+commentPrefix) s = s[ : typedefStructMatch.start()] + newTypedefStruct + s[typedefStructMatch.end() : ] typedefStructMatch = typedefStructPattern.search(s, typedefStructMatch.start() + len(newTypedefStruct)) #print "STRUCTTYPES:\n",structTypes #raw_input() #Translate functions #-------------------- functionPattern = re.compile(r"C_RET[ \t]+([^ \t]+)[ \t]*\(([^\)]*)\);", re.DOTALL) functionMatch = functionPattern.search(s) while functionMatch: function = functionMatch.group() functionName, functionParams = functionMatch.groups() if not functionName.startswith("crypt"): raise "name doesn't start with crypt"+functionName functionName = functionName[len("crypt") : ] functionNames.append(functionName) #print "function:", functionName, functionParams #raw_input() #Parse its parameters paramStructs = parseFunctionParams(functionParams) #Add raw list of ParamStructs to dictionary #This will be used later, when generating the .c glue code rawParamStructsDict[functionName] = paramStructs # Since java and python don't have pass-by-reference, what we do is migrate the # output int parameter in certain functions into the return value. If the function # creates or returns values such as integers or a (void*, int*) pair, we record # the indexes of the parameters to migrate. We do this in functions like: # cryptCreate*() # return handle of new object # cryptGetAttribute() # return integer value of attribute # cryptGetAttributeString() # convert (void*, int*) to python string or java byte array # cryptExportKey() # convert (void*, int*) " # cryptCreateSignature() # convert (void*, int*) # cryptKeysetOpen() # return handle # cryptGetPublicKey() # return handle # cryptGetPrivateKey() # return handle # cryptGetCertExtension() # convert (void*, int) but DISCARD criticalFlag (the int* before)! # cryptImportCert() # return handle # cryptExportCert() # convert (void*, int) # cryptCAGetItem() # return handle # cryptCACertManagement() # return handle # cryptPushData() # return integer (# of bytes copied) # cryptPopData() # convert (void*, int*) even though they're not adjacent discardIntIndex = -1 returnIntIndex = -1 returnVoidPtrIndex = -1 discardInLengthIndex1 = -1 # To discard input lengths, since python don't need these discardInLengthIndex2 = -1 #Scan through looking for a void pointer preceded by "keyIDtype" #Convert it into a char* index = 1 for p in paramStructs[1:]: p2 = paramStructs[index-1] if p.isPtr and p.type=="void" and p2.type=="CRYPT_KEYID_TYPE": p.type = "char" index += 1 #Scan through looking for output int pointers (or structs)?! #If there's two, we will migrate the second occurrence to the return value #and discard the first so as to handle cryptGetCertExtension() index = 0 for p in paramStructs: if p.isOut and p.isPtr and (p.category=="intType" or p.type=="int" or p.category=="structType"): if returnIntIndex != -1: if discardIntIndex != -1: raise "Found two returned ints to discard?!" discardIntIndex = returnIntIndex returnIntIndex = index index += 1 #Record the migrated return value's ParamStruct if returnIntIndex != -1: newReturnStructsDict[functionName] = paramStructs[returnIntIndex] #Return the discarded value's ParamStruct if discardIntIndex != -1: newDiscardedStructsDict[functionName] = paramStructs[discardIntIndex] #Copy the parsed parameters and remove those we're going to migrate or discard newParamStructs = [paramStructs[count] for count in range(len(paramStructs)) if count not in (discardIntIndex, returnIntIndex)] #Indices of input offsets and lengths offsetIndices = [] lengthIndices = [] #Scan through looking for void pointer, add an int offset index = 0 while 1: if index >= len(newParamStructs): break p = newParamStructs[index] if p.isPtr and p.type=="void": newp = ParamStruct() newp.type = "int" newp.isPtr = 0 newp.isOut = 0 newp.category = "rawType" newp.name = p.name+"Offset" newParamStructs = newParamStructs[:index+1] + [newp] + newParamStructs[index+1:] offsetIndices.append(index+1) if not p.isOut and len(newParamStructs)> index+2 and newParamStructs[index+2].type == "int": lengthIndices.append(index+2) index += 1 #Add processed list of ParamStructs to dictionary #This will be used later, when generating the .c glue code newParamStructsDict[functionName] = newParamStructs lengthIndicesDict[functionName] = lengthIndices offsetIndicesDict[functionName] = offsetIndices #Used for Python if wholeFunctionDeclaration: newFunction = wholeFunctionDeclaration % functionName if sFuncs: sFuncs += newFunction + "\n" else: assert(0) sModFuncs += (moduleFunctionEntry % (functionName, functionName)) + "\n" else: #Java #Construct new function declaration from language-specific templates newFunction = functionDeclaration if returnIntIndex != -1: if newReturnStructsDict.get(functionName).category == "structType": newFunction += newReturnStructsDict.get(functionName).type + " " else: newFunction += returnIntDeclaration else: newFunction += returnVoidDeclaration newFunction += functionName + paramsPrefix if len(newParamStructs): newFunction += "\n" + paramWhiteSpace if offsetIndices or lengthIndices: newFunctionWrapper = newFunction newFunctionWrapperArgs = "" else: newFunctionWrapper = None #At this point I'm just getting lazy. Basically, we automatically generate #String wrappers for function that take void* input parameters. Encrypt and #Decrypt take void* in/out parameters. We should be smart enough to detect #these and not generate wrappers for them, but instead, since we don't otherwise #differentiate between C_IN and C_INOUT, we just hardcodedly exclude these #from having String wrappers if offsetIndices and lengthIndices and functionName not in ("Encrypt", "Decrypt"): newFunctionStringWrapper = newFunction newFunctionStringWrapperArgs = "" else: newFunctionStringWrapper = None newFunctionStringWrapperArgs = "" index = 0 for p in newParamStructs: if p.category == "rawType" and p.type == "void" and p.isPtr: template = paramVoidPtrTemplate previousBufferName = p.name elif p.category == "rawType" and p.type == "char" and p.isPtr: template = paramCharPtrTemplate elif p.category == "rawType" and p.type == "int" and not p.isPtr: template = paramIntTemplate elif p.category == "intType" and not p.isPtr: template = paramIntTypeTemplate elif p.category == "enumType" and not p.isPtr: template = paramEnumTypeTemplate #elif p.category == "structType" else: raise "Unrecognized parameter type! " + str(p) #Strip out commas from the last param template, kind of a hack.. if index == len(newParamStructs)-1: template = template[:].replace(",", "") #Update the main function with this new param newFunction += template % vars(p) newFunction += paramWhiteSpace #Update the wrapper function with this new param #If this is not a special param... if addFunctionWrappers and newFunctionWrapper and \ index not in offsetIndices and index not in lengthIndices: #Determine if this is the last param in the wrapper function anyMoreParams = [e for e in range(index+1, len(newParamStructs)) if e not in offsetIndices and e not in lengthIndices] #Update the wrapper function's param list if not anyMoreParams: template = template[:].replace(",", "") newFunctionWrapper += template % vars(p) newFunctionWrapper += paramWhiteSpace #Update the wrapper function's args that it uses to call the main function newFunctionWrapperArgs += p.name newFunctionWrapperArgs += ", " #Do the same things for the string wrapper if newFunctionStringWrapper: newFunctionStringWrapper += template % vars(p) newFunctionStringWrapper += paramWhiteSpace if p.type=="void" and p.isPtr and not p.isOut: newFunctionStringWrapperArgs += wrapperStringTemplate % {"1":p.name}; else: newFunctionStringWrapperArgs += p.name newFunctionStringWrapperArgs += ", " else: #If this is a special param (an offset or length)... if index in offsetIndices: newFunctionWrapperArgs += "0, " newFunctionStringWrapperArgs += "0, " elif index in lengthIndices: newFunctionWrapperArgs += wrapperLengthTemplate % {"1":previousBufferName} newFunctionStringWrapperArgs += wrapperStringLengthTemplate % {"1":previousBufferName} index += 1 #Add final postfix of ); to the main and wrapper param lists newFunction += paramsPostfix if newFunctionWrapper: newFunctionWrapper += paramsPostfix if newFunctionStringWrapper: newFunctionStringWrapper += paramsPostfix #If this function takes a void* parameter, and we want to convert this #into two different versions, duplicate and modify the version here if addFunctionAlternate: if newFunction.find(paramVoidPtrAlternate[0]) != -1: newFunction += "\n" + newFunction.replace(*paramVoidPtrAlternate) #If we've prepared a wrapper function to eliminate need for offset[, length]: if addFunctionWrappers and newFunctionWrapper: newFunctionWrapper = newFunctionWrapper.replace("native ", "") newFunctionWrapper = newFunctionWrapper[:-1] + " { return %s(%s); }" % (functionName, newFunctionWrapperArgs[:-2]) if returnIntIndex == -1: newFunctionWrapper = newFunctionWrapper.replace("return ", "") #Duplicate and modify the wrapper function if addFunctionAlternate: newFunctionWrapper2 = newFunctionWrapper.replace(*paramVoidPtrAlternate) newFunctionWrapper2 = newFunctionWrapper2.replace("capacity()", "length") newFunctionWrapper += "\n" + newFunctionWrapper2 newFunction += "\n" + newFunctionWrapper if addFunctionWrappers and newFunctionStringWrapper: newFunctionStringWrapper = newFunctionStringWrapper.replace("native ", "") newFunctionStringWrapper = newFunctionStringWrapper[:-1] + " { return %s(%s); }" % (functionName, newFunctionStringWrapperArgs[:-2]) newFunctionStringWrapper = newFunctionStringWrapper.replace(*wrapperStringReplace) if returnIntIndex == -1: newFunctionStringWrapper = newFunctionStringWrapper.replace("return ", "") newFunction += "\n" + newFunctionStringWrapper #Add a special-case string accessor for GetAttributeString() to Java and .NET if functionName == "GetAttributeString" and language == "java": newFunction += """ public static String GetAttributeString( int cryptHandle, // CRYPT_HANDLE int attributeType // CRYPT_ATTRIBUTE_TYPE ) throws CryptException { int length = GetAttributeString(cryptHandle, attributeType, (byte[])null); byte[] bytes = new byte[length]; length = GetAttributeString(cryptHandle, attributeType, bytes); return new String(bytes, 0, length); } """ elif functionName == "GetAttributeString" and language == "net": newFunction += """ public static String GetAttributeString( int cryptHandle, // CRYPT_HANDLE int attributeType // CRYPT_ATTRIBUTE_TYPE ) { int length = GetAttributeString(cryptHandle, attributeType, null); byte[] bytes = new byte[length]; length = GetAttributeString(cryptHandle, attributeType, bytes); return new UTF8Encoding().GetString(bytes, 0, length); } """ #Add special-case functions for cryptAddRandom(), since it allows NULL as a #first parameter, and a pollType constant in place of the length elif functionName == "AddRandom": if language == "java": newFunction += """ public static native void AddRandom( int pollType ) throws CryptException; """ elif language == "net": newFunction += """ public static void AddRandom( int pollType ); """ # Add an extra linebreak between functions # This isn't in cryptlib.h, but it makes the converted files more readable if s[functionMatch.end()+1] != "\n": newFunction += "\n" s = s[ : functionMatch.start()] + newFunction + s[functionMatch.end() : ] functionMatch = functionPattern.search(s, functionMatch.start() + len(newFunction)) #Translate comments #------------------- if language != "java" and language != "net": while 1: match = re.search(r"/\*(.*?)\*/", s, re.DOTALL) if match == None: break #print match.group() #raw_input() commentStrings = (commentPrefix + match.group(1) + " ").split("\n") newComment = commentStrings[0] for commentString in commentStrings[1:]: if commentString.startswith("\t"): newComment += "\n" + commentPrefix + (" " * (inFileTabSize-2)) + commentString[1:] elif commentString.startswith(" "): newComment += "\n" + commentPrefix + commentString[1:] else: newComment += "\n" + commentPrefix + commentString #print "building up:\n", newComment #raw_input() idx = commentString.find("\n") s = s[ : match.start()] + newComment + s[match.end() : ] #Indent each line by one tab #--------------------------- s = s.replace("\n", "\n\t") #Write out file(s) #Then generate the .h/.c files necessary for language integration #At this point it's easier to just hardcode constants and have #separate python and java codepaths #--------------- if language=="java": #Add enclosing class syntax #--------------------------- s = classPrefix + s + classPostfix os.chdir(outDir) if not os.path.exists("cryptlib"): os.mkdir("./cryptlib") os.chdir("./cryptlib") print "Writing java files..." f = open("crypt.java", "w") f.write(s) f.close() f = open("CryptException.java", "w") f.write(exceptionString) f.close() f = open("CRYPT_QUERY_INFO.java", "w") f.write(cryptQueryInfoString) f.close() f = open("CRYPT_OBJECT_INFO.java", "w") f.write(cryptObjectInfoString) f.close() print "Compiling java files..." print os.popen4("javac -classpath .. crypt.java")[1].read() #Compile java file print os.popen4("javac -classpath .. CryptException.java")[1].read() #Compile java file print os.popen4("javac -classpath .. CRYPT_QUERY_INFO.java")[1].read() #Compile java file print os.popen4("javac -classpath .. CRYPT_OBJECT_INFO.java")[1].read() #Compile java file os.chdir("..") print "Generating jar file..." print os.popen4("jar cf cryptlib.jar cryptlib/crypt.class cryptlib/CryptException.class cryptlib/CRYPT_QUERY_INFO.class cryptlib/CRYPT_OBJECT_INFO.class cryptlib")[1].read() print "Generating JNI header file..." print os.popen4("javah -classpath . -o cryptlib_jni.h -jni cryptlib.crypt")[1].read() #Generate C header s = open("cryptlib_jni.h").read() os.remove("cryptlib_jni.h") print "Generating JNI source file..." #Now we take cryptlib_jni.h and derive the .c file from it #Strip off headers and footers #startIndex = s.find("/*\n * Class") #endIndex = s.find("#ifdef", startIndex) #s = s[startIndex : endIndex] startIndex = s.find("#undef") endIndex = s.find("/*\n * Class", startIndex) sold = s s = s[startIndex : endIndex] startIndex = endIndex endIndex = sold.find("#ifdef", startIndex) s2 = sold[startIndex : endIndex] #Add includes and helper functions #Note that we assume "cryptlib.h" is one directory behind us s = r""" #include "../crypt.h" #ifdef USE_JAVA #include #include //printf #include //malloc, free %s /* Helper Functions */ int processStatus(JNIEnv *env, jint status) { jclass exClass; jmethodID exConstructor; jthrowable obj; if (status >= cryptlib_crypt_OK) return 1; exClass = (*env)->FindClass(env, "cryptlib/CryptException"); if (exClass == 0) { printf("java_jni.c:processStatus - no class?!\n"); return 0; } exConstructor = (*env)->GetMethodID(env, exClass, "", "(I)V"); if (exConstructor == 0) { printf("java_jni.c:processStatus - no constructor?!\n"); return 0; } obj = (*env)->NewObject(env, exClass, exConstructor, status); if (obj == 0) { printf("java_jni.c:processStatus - no object?!\n"); return 0; } if ((*env)->Throw(env, obj) < 0) { printf("java_jni.c:processStatus - failed to throw?!\n"); return 0; } return 0; } jobject processStatusReturnCryptQueryInfo(JNIEnv *env, int status, CRYPT_QUERY_INFO returnValue) { jclass exClass; jmethodID exConstructor; jstring algoName; jobject obj; if (status < cryptlib_crypt_OK) return NULL; exClass = (*env)->FindClass(env, "cryptlib/CRYPT_QUERY_INFO"); if (exClass == 0) { printf("java_jni.c:processStatusReturnCryptQueryInfo - no class?!\n"); return NULL; } exConstructor = (*env)->GetMethodID(env, exClass, "", "(Ljava/lang/String;IIII)V"); if (exConstructor == 0) { printf("java_jni.c:processStatusReturnCryptQueryInfo - no constructor?!\n"); return NULL; } algoName = (*env)->NewStringUTF(env, returnValue.algoName); obj = (*env)->NewObject(env, exClass, exConstructor, algoName, returnValue.blockSize, returnValue.minKeySize, returnValue.keySize, returnValue.maxKeySize); if (obj == 0) { printf("java_jni.c:processStatusReturnCryptQueryInfo - no object?!\n"); return NULL; } return obj; } jobject processStatusReturnCryptObjectInfo(JNIEnv *env, int status, CRYPT_OBJECT_INFO returnValue) { jclass exClass; jmethodID exConstructor; jbyteArray salt; jobject obj; if (status < cryptlib_crypt_OK) return NULL; exClass = (*env)->FindClass(env, "cryptlib/CRYPT_OBJECT_INFO"); if (exClass == 0) { printf("java_jni.c:processStatusReturnCryptObjectInfo - no class?!\n"); return NULL; } exConstructor = (*env)->GetMethodID(env, exClass, "", "(IIII[B)V"); if (exConstructor == 0) { printf("java_jni.c:processStatusReturnCryptObjectInfo - no constructor?!\n"); return NULL; } salt = (*env)->NewByteArray(env, returnValue.saltSize); (*env)->SetByteArrayRegion(env, salt, 0, returnValue.saltSize, returnValue.salt); obj = (*env)->NewObject(env, exClass, exConstructor, returnValue.objectType, returnValue.cryptAlgo, returnValue.cryptMode, returnValue.hashAlgo, salt); if (obj == 0) { printf("java_jni.c:processStatusReturnCryptObjectInfo - no object?!\n"); return NULL; } return obj; } int checkIndicesArray(JNIEnv *env, jbyteArray array, int sequenceOffset, int sequenceLength) { jsize arrayLength; jclass exClass; if (array == NULL) { if (sequenceOffset == 0) return 1; else { exClass = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException"); if (exClass == 0) printf("java_jni.c:checkIndicesArray - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "") < 0) printf("java_jni.c:checkIndicesArray - failed to throw?!\n"); return 0; } } arrayLength = (*env)->GetArrayLength(env, array); if (sequenceOffset < 0 || sequenceOffset >= arrayLength || sequenceOffset + sequenceLength > arrayLength) { exClass = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException"); if (exClass == 0) printf("java_jni.c:checkIndicesArray - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "") < 0) printf("java_jni.c:checkIndicesArray - failed to throw?!\n"); return 0; } return 1; } int getPointerArray(JNIEnv* env, jbyteArray array, jbyte** bytesPtrPtr) { jboolean isCopy; if (array == NULL) { (*bytesPtrPtr) = NULL; return 1; } (*bytesPtrPtr) = (*env)->GetByteArrayElements(env, array, &isCopy); if (*bytesPtrPtr == NULL) { printf("java_jni.c:getPointer - failed to get elements of array?!\n"); return 0; } return 1; } void releasePointerArray(JNIEnv* env,jbyteArray array, jbyte* bytesPtr) { if (bytesPtr == NULL) return; (*env)->ReleaseByteArrayElements(env, array, bytesPtr, 0); } int checkIndicesNIO(JNIEnv *env, jobject byteBuffer, int sequenceOffset, int sequenceLength) { jlong byteBufferLength; jclass exClass; if (byteBuffer == NULL) { if (sequenceOffset == 0) return 1; else { exClass = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException"); if (exClass == 0) printf("java_jni.c:checkIndicesNIO - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "") < 0) printf("java_jni.c:checkIndicesNIO - failed to throw?!\n"); return 0; } } byteBufferLength = (*env)->GetDirectBufferCapacity(env, byteBuffer); if (byteBufferLength == -1) { exClass = (*env)->FindClass(env, "java/lang/UnsupportedOperationException"); if (exClass == 0) printf("java_jni.c:checkIndicesNIO - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "Either a non-direct ByteBuffer was passed or your JVM doesn't support JNI access to direct ByteBuffers") < 0) printf("java_jni.c:checkIndicesNIO - failed to throw?!\n"); return 0; } if (sequenceOffset < 0 || sequenceOffset >= byteBufferLength || sequenceOffset + sequenceLength > byteBufferLength) { exClass = (*env)->FindClass(env, "java/lang/ArrayIndexOutOfBoundsException"); if (exClass == 0) printf("java_jni.c:checkIndicesNIO - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "") < 0) printf("java_jni.c:checkIndicesNIO - failed to throw?!\n"); return 0; } return 1; } int getPointerNIO(JNIEnv* env, jobject byteBuffer, jbyte** bytesPtrPtr) { jclass exClass; if (byteBuffer == NULL) { (*bytesPtrPtr) = NULL; return 1; } (*bytesPtrPtr) = (*env)->GetDirectBufferAddress(env, byteBuffer); if (*bytesPtrPtr == NULL) { exClass = (*env)->FindClass(env, "java/lang/UnsupportedOperationException"); if (exClass == 0) printf("java_jni.c:getPointerNIO - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "Your JVM doesn't support JNI access to direct ByteBuffers") < 0) printf("java_jni.c:getPointerNIO - failed to throw?!\n"); return 0; } return 1; } void releasePointerNIO(JNIEnv* env,jbyteArray array, jbyte* bytesPtr) { } int getPointerString(JNIEnv* env, jstring str, jbyte** bytesPtrPtr) { jboolean isCopy; jsize strLength; const jbyte* rawBytesPtr; jclass exClass; #ifdef __WINCE__ int status; #endif // __WINCE__ if (str == NULL) { (*bytesPtrPtr) = NULL; return 1; } rawBytesPtr = (*env)->GetStringUTFChars(env, str, &isCopy); if (rawBytesPtr == NULL) { printf("java_jni.c:getPointerString - failed to get elements of String?!\n"); return 0; } strLength = (*env)->GetStringUTFLength(env, str); #ifdef __WINCE__ (*bytesPtrPtr) = (jbyte*)malloc(strLength*2+2); // this is unicode, therefore \0 is two bytes long #else (*bytesPtrPtr) = (jbyte*)malloc(strLength+1); #endif // __WINCE__ if (*bytesPtrPtr == NULL) { exClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError"); if (exClass == 0) printf("java_jni.c:getPointerString - no class?!\n"); else if ((*env)->ThrowNew(env, exClass, "") < 0) printf("java_jni.c:getPointerString - failed to throw?!\n"); (*env)->ReleaseStringUTFChars(env, str, rawBytesPtr); return 0; } #ifdef __WINCE__ status = asciiToUnicode (*bytesPtrPtr, strLength*2+2, rawBytesPtr, strLength+1); if (status == CRYPT_ERROR_BADDATA) { (*env)->ReleaseStringUTFChars(env, str, rawBytesPtr); return 0; } #else memcpy(*bytesPtrPtr, rawBytesPtr, strLength); (*bytesPtrPtr)[strLength] = 0; #endif // __WINCE__ (*env)->ReleaseStringUTFChars(env, str, rawBytesPtr); return 1; } void releasePointerString(JNIEnv* env, jstring str, jbyte* bytesPtr) { if (bytesPtr == NULL) return; free(bytesPtr); } %s #endif /* USE_JAVA */ """ % (s, s2) functionPattern = re.compile(r"JNIEXPORT ([^ \t]+) JNICALL Java_cryptlib_crypt_([^ \t\n]+)\n[ \t]*\(([^\)]*)\);") functionMatch = functionPattern.search(s) while functionMatch: #print functionMatch.groups() #Extract the returnType, name, and prototype for this function function = functionMatch.group() functionReturnType, functionName, functionPrototype = functionMatch.groups() #Handle special-case AddRandom(pollType) function if functionName == "AddRandom__I": p = ParamStruct() p.type = "int" p.isPtr = 0 p.isOut = 0 p.category = "intType" p.name = "NULL" p.rawIndex = 0 p2 = ParamStruct() p2.type = "int" p2.isPtr = 0 p2.isOut = 0 p2.category = "intType" p2.name = "pollType" p2.rawIndex = 1 rawParamStructs = [p,p2] newParamStructs = [p2,p2] voidTag = "Array" functionName = functionName.split("__")[0] returnName = None discardName = None else: #Strip JNI decoration off function name #But record which variety of tagged helper functions to use if functionName.find("__") != -1: if functionName.find("ByteBuffer") != -1: voidTag = "NIO" else: voidTag = "Array" functionName = functionName.split("__")[0] #Look up the parameters we've previously determined for this function rawParamStructs = rawParamStructsDict[functionName] newParamStructs = newParamStructsDict[functionName] if newReturnStructsDict.get(functionName): returnName = newReturnStructsDict.get(functionName).name returnType = newReturnStructsDict.get(functionName).type returnCategory = newReturnStructsDict.get(functionName).category else: returnName = None if newDiscardedStructsDict.get(functionName): discardName = newDiscardedStructsDict.get(functionName).name else: discardName = None #for p in newParamStructs: print " "+str(p) #Substitute parameter names into the function prototype newFunctionParams = expandFunctionPrototype(functionPrototype, newParamStructs) startIndex = functionMatch.start(3) - functionMatch.start() endIndex = functionMatch.end(3) - functionMatch.start() function = function[ : startIndex] + newFunctionParams + function[ endIndex : ] newFunctionBody = "\nint status = 0;\n" arguments = "" for p in rawParamStructs: if p.name == returnName or p.name == discardName: arguments += "&" if p.isPtr and p.type=="void": arguments += "%sPtr + %sOffset, " % (p.name, p.name) elif p.isPtr and p.type=="char": arguments += "%sPtr, " % p.name else: arguments += p.name + ", " arguments = arguments[:-2] if returnName: if returnCategory == "intType" or returnType=="int": newFunctionBody += "jint %s = 0;\n" % returnName else: newFunctionBody += returnType +" %s;\n" % returnName if discardName: newFunctionBody += "jint %s = 0;\n" % discardName #If we have arrays, add the code to handle them arrayNames = [p.name for p in newParamStructs if p.isPtr] charArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="char"] voidArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="void"] outVoidArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="void" and p.isOut] if arrayNames: #Declare C pointers to retrieve array contents for n in arrayNames: newFunctionBody += "jbyte* " + n + "Ptr = 0;\n" newFunctionBody += "\n" #Retrieve the contents for strings #We need to do this first cause in one case this char* is needed as an argument if charArrayNames: for n in charArrayNames: newFunctionBody += "if (!getPointerString(env, %(n)s, &%(n)sPtr))\n\tgoto finish;\n" % vars() newFunctionBody += "\n" #Query the length of output data #CryptPopData is the only exception that produces output data #but doesn't require this cause an explicit length is passed in if outVoidArrayNames and functionName.find("PopData") == -1: for n in outVoidArrayNames: argumentsWithNull = arguments.replace("%sPtr + %sOffset" % (n,n), "NULL") newFunctionBody += "if (!processStatus(env, crypt%s(%s)))\n\tgoto finish;\n" % (functionName, argumentsWithNull) newFunctionBody += "\n" elif functionName.find("PopData") != -1: newFunctionBody += "//CryptPopData is a special case that doesn't have the length querying call\n\n" if voidArrayNames: for n in voidArrayNames: index = [p.name for p in newParamStructs].index(n) if n in outVoidArrayNames: lengthName = returnName else: if len(newParamStructs)<=index+2 or newParamStructs[index+2].category != "rawType" or newParamStructs[index+2].type != "int": lengthName = "1" #CheckSignature and ImportKey don't have a length, so we can't do a good check! else: lengthName = newParamStructs[index+2].name newFunctionBody += "if (!checkIndices%(voidTag)s(env, %(n)s, %(n)sOffset, %(lengthName)s))\n\tgoto finish;\n" % vars() newFunctionBody += "\n" for n in voidArrayNames: newFunctionBody += "if (!getPointer%(voidTag)s(env, %(n)s, &%(n)sPtr))\n\tgoto finish;\n" % vars() if newFunctionBody[-2] != "\n": newFunctionBody += "\n" newFunctionBody += "status = crypt%s(%s);\n\n" % (functionName, arguments) if arrayNames: newFunctionBody += "finish:\n" if arrayNames: for n in voidArrayNames: newFunctionBody += "releasePointer%(voidTag)s(env, %(n)s, %(n)sPtr);\n" % vars() for n in charArrayNames: newFunctionBody += "releasePointerString(env, %(n)s, %(n)sPtr);\n" % vars() #newFunctionBody += "processStatus(env, status);\n" #if returnName: # newFunctionBody += "return(%s);\n" % returnName if returnName: if returnCategory == "intType" or returnType == "int": newFunctionBody += "processStatus(env, status);\n" newFunctionBody += "return(%s);\n" % returnName elif returnType == "CRYPT_QUERY_INFO": newFunctionBody += "return(processStatusReturnCryptQueryInfo(env, status, %s));\n" % returnName elif returnType == "CRYPT_OBJECT_INFO": newFunctionBody += "return(processStatusReturnCryptObjectInfo(env, status, %s));\n" % returnName else: newFunctionBody += "processStatus(env, status);\n" newFunctionBody = newFunctionBody[:-1] #Strip off last \n newFunctionBody = newFunctionBody.replace("\n", "\n\t"); newFunction = function[:-1]+"\n{" + newFunctionBody + "\n}" #Substitute the output equivalent for the input s = s[ : functionMatch.start()] + newFunction + s[functionMatch.end() : ] #Get next function functionMatch = functionPattern.search(s, functionMatch.start() + len(newFunction)) f = open("java_jni.c", "w") f.write(s) f.close() elif language == "python": os.chdir(outDir) #print sInts #raw_input() #print sFuncs #raw_input() moduleFunctions = "" s = pyBeforeExceptions + exceptionString + pyBeforeFuncs + sFuncs + \ pyBeforeModuleFunctions + moduleFunctions + sModFuncs + \ pyBeforeInts + sInts + \ pyAfterInts #print s #raw_input() functionPattern = re.compile(r"static PyObject\* python_crypt([^\(]+)[^{]+{([^}]*)}", re.DOTALL) functionMatch = functionPattern.search(s) while functionMatch: #print functionMatch.group() #print functionMatch.groups() #raw_input() #Most of the code in this loop is copied-then-modified from the java code above, ugly.. voidTag = "" #Extract the function name and body functionName, functionBody = functionMatch.groups() #Look up the parameters we've previously determined for this function rawParamStructs = rawParamStructsDict[functionName] newParamStructs = newParamStructsDict[functionName] lengthIndices = lengthIndicesDict[functionName] offsetIndices = offsetIndicesDict[functionName] #print functionName, lengthIndices, offsetIndices #raw_input() if newReturnStructsDict.get(functionName): returnName = newReturnStructsDict.get(functionName).name returnType = newReturnStructsDict.get(functionName).type returnCategory = newReturnStructsDict.get(functionName).category else: returnName = None if newDiscardedStructsDict.get(functionName): discardName = newDiscardedStructsDict.get(functionName).name else: discardName = None newFunctionBody = "\nint status = 0;\n" #Arguments to pass to the C cryptlib function arguments = "" for p in rawParamStructs: if p.name == returnName or p.name == discardName: arguments += "&" if p.isPtr and p.type=="void": arguments += "%sPtr, " % (p.name) elif p.isPtr and p.type=="char": arguments += "%sPtr, " % p.name else: arguments += p.name + ", " arguments = arguments[:-2] if returnName: if returnCategory == "intType" or returnType=="int": newFunctionBody += "int %s = 0;\n" % returnName else: newFunctionBody += returnType +" %s;\n" % returnName if discardName: newFunctionBody += "int %s = 0;\n" % discardName #Declare variables to parse args tuple into index = 0 for p in newParamStructs: if index not in offsetIndices: #Python doesn't use the offsets if p.isPtr: newFunctionBody += "PyObject* %s = NULL;\n" % p.name else: newFunctionBody += "int %s = 0;\n" % p.name index += 1 #If we have arrays, add the code to handle them arrayNames = [p.name for p in newParamStructs if p.isPtr] charArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="char"] voidArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="void"] outVoidArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="void" and p.isOut] if arrayNames: #Declare C pointers to retrieve array contents for n in arrayNames: newFunctionBody += "unsigned char* " + n + "Ptr = 0;\n" newFunctionBody += "\n" #Retrieve the contents for strings #We need to do this first cause in one case this char* is needed as an argument #Parse the input arguments from the python user #Arguments to parse from the python args tuple if newParamStructs: parseFormatString = "" parseArgsList = [] index = 0 for p in newParamStructs: if index not in lengthIndices and index not in offsetIndices: if p.isPtr and p.type=="char": parseFormatString += "O" parseArgsList.append("&" + p.name) elif p.isPtr and p.type=="void": parseFormatString += "O" parseArgsList.append("&" + p.name) else: parseFormatString += "i" parseArgsList.append("&" + p.name) index += 1 if newFunctionBody[-2] != "\n": newFunctionBody += "\n" if functionName == "AddRandom": newFunctionBody += """\ //Special case to handle SLOWPOLL / FASTPOLL values if (PyArg_ParseTuple(args, "i", &randomDataLength)) return processStatus(cryptAddRandom(NULL, randomDataLength));\n\n""" newFunctionBody += """\ if (!PyArg_ParseTuple(args, "%s", %s)) return(NULL);\n\n""" % (parseFormatString, ", ".join(parseArgsList)) #for p in newParamStructs: # print p.name, if arrayNames: if charArrayNames: for n in charArrayNames: newFunctionBody += "if (!getPointerReadString(%(n)s, &%(n)sPtr))\n\tgoto finish;\n" % vars() newFunctionBody += "\n" #Query the length of output data #CryptPopData is the only exception that produces output data #but doesn't require this cause an explicit length is passed in if outVoidArrayNames and functionName.find("PopData") == -1: for n in outVoidArrayNames: argumentsWithNull = arguments.replace("%sPtr" % (n), "NULL") newFunctionBody += "if (!processStatusBool(crypt%s(%s)))\n\tgoto finish;\n" % (functionName, argumentsWithNull) newFunctionBody += "\n" elif functionName.find("PopData") != -1: newFunctionBody += "//CryptPopData is a special case that doesn't have the length querying call\n\n" #Go through and get the pointers for translated void* if voidArrayNames: for n in voidArrayNames: index = [p.name for p in newParamStructs].index(n) #Determine the name of its length parameter if n in outVoidArrayNames: lengthName = returnName else: if len(newParamStructs)<=index+2 or newParamStructs[index+2].category != "rawType" or newParamStructs[index+2].type != "int": lengthName = "1" #QueryObject, CheckSignature and ImportKey don't have a length, so we can't do a good check! else: lengthName = newParamStructs[index+2].name if n in outVoidArrayNames and functionName.find("PopData") == -1: newFunctionBody += "if (!getPointerWriteCheckIndices%(voidTag)s(%(n)s, &%(n)sPtr, &%(lengthName)s))\n\tgoto finish;\n" % vars() else: if lengthName == "1": #Handle the #CheckSignature/ImportKey case newFunctionBody += "if (!getPointerReadNoLength%(voidTag)s(%(n)s, &%(n)sPtr))\n\tgoto finish;\n" % vars() else: #If the pointer is C_IN and not C_INOUT #(we check against Encrypt/Decrypt directory for this latter check) #We only need it for reading, not writing if n not in outVoidArrayNames and functionName not in ("Encrypt", "Decrypt"): newFunctionBody += "if (!getPointerRead(%(n)s, &%(n)sPtr, &%(lengthName)s))\n\tgoto finish;\n" % vars() else: newFunctionBody += "if (!getPointerWrite(%(n)s, &%(n)sPtr, &%(lengthName)s))\n\tgoto finish;\n" % vars() if newFunctionBody[-2] != "\n": newFunctionBody += "\n" newFunctionBody += "status = crypt%s(%s);\n\n" % (functionName, arguments) if arrayNames: newFunctionBody += "finish:\n" if arrayNames: for n in voidArrayNames: newFunctionBody += "releasePointer(%(n)s, %(n)sPtr);\n" % vars() for n in charArrayNames: newFunctionBody += "releasePointerString(%(n)s, %(n)sPtr);\n" % vars() if returnName: if returnCategory == "intType": newFunctionBody += "return(processStatusReturnCryptHandle(status, %s));" % returnName elif returnType == "CRYPT_QUERY_INFO": newFunctionBody += "return(processStatusReturnCryptQueryInfo(status, %s));" % returnName elif returnType == "CRYPT_OBJECT_INFO": newFunctionBody += "return(processStatusReturnCryptObjectInfo(status, %s));" % returnName elif returnType == "int": newFunctionBody += "return(processStatusReturnInt(status, %s));" % returnName else: newFunctionBody += "return(processStatus(status));" newFunctionBody = newFunctionBody.replace("\n", "\n\t") #Substitute the output equivalent for the input s = s[ : functionMatch.start(2)] + newFunctionBody + "\n" + s[functionMatch.end(2) : ] #Get next function functionMatch = functionPattern.search(s, functionMatch.start() + len(newFunction)) f = open("python.c", "w") f.write(s) f.close() f = open("setup.py", "w") f.write(setupPy) f.close() elif language == "net": flagForAddRandomHack = 0 #functionPattern = re.compile(r"public static ([^ \t]+) ([^ \t\n]+)\([ \t\n]*\(([^\)]*)\) throws CryptException;") functionPattern = re.compile(r"public static ([^ \t]+) ([^ \t\n]+)\([ \t\n]*([^\)]*)\);") functionMatch = functionPattern.search(s) while functionMatch: #print functionMatch.groups() #Extract the returnType, name, and prototype for this function function = functionMatch.group() functionReturnType, functionName, functionPrototype = functionMatch.groups() #Handle special-case AddRandom(pollType) function if functionName == "AddRandom": flagForAddRandomHack += 1 if flagForAddRandomHack == 2: p = ParamStruct() p.type = "int" p.isPtr = 0 p.isOut = 0 p.category = "intType" p.name = "IntPtr.Zero" p.rawIndex = 0 p2 = ParamStruct() p2.type = "int" p2.isPtr = 0 p2.isOut = 0 p2.category = "intType" p2.name = "pollType" p2.rawIndex = 1 rawParamStructs = [p,p2] newParamStructs = [p2,p2] voidTag = "Array" functionName = functionName.split("__")[0] returnName = None discardName = None flagForAddRandomHack = None else: #Look up the parameters we've previously determined for this function rawParamStructs = rawParamStructsDict[functionName] newParamStructs = newParamStructsDict[functionName] if newReturnStructsDict.get(functionName): returnName = newReturnStructsDict.get(functionName).name returnType = newReturnStructsDict.get(functionName).type returnCategory = newReturnStructsDict.get(functionName).category else: returnName = None if newDiscardedStructsDict.get(functionName): discardName = newDiscardedStructsDict.get(functionName).name else: discardName = None #for p in newParamStructs: print " "+str(p) #Substitute parameter names into the function prototype newFunctionParams = functionPrototype #expandFunctionPrototype(functionPrototype, newParamStructs) startIndex = functionMatch.start(3) - functionMatch.start() endIndex = functionMatch.end(3) - functionMatch.start() function = function[ : startIndex] + newFunctionParams + function[ endIndex : ] newFunctionBody = "\n" arguments = "" for p in rawParamStructs: if p.name == returnName or p.name == discardName: arguments += "%sPtr, " % p.name elif p.isPtr and p.type=="void": arguments += "%sPtr, " % p.name elif p.isPtr and p.type=="char": arguments += "%sPtr, " % p.name else: arguments += p.name + ", " arguments = arguments[:-2] if returnName: if returnCategory == "structType": newFunctionBody += "IntPtr %sPtr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(%s)));\n" % (returnName, returnType) newFunctionBody += "%s %s = new %s();\n" % (returnType, returnName, returnType) else: newFunctionBody += "IntPtr %sPtr = Marshal.AllocHGlobal(4);\n" % returnName if discardName: newFunctionBody += "IntPtr %sPtr = Marshal.AllocHGlobal(4);\n" % discardName #If we have arrays, add the code to handle them arrayNames = [p.name for p in newParamStructs if p.isPtr] charArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="char"] voidArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="void"] outVoidArrayNames = [p.name for p in newParamStructs if p.isPtr and p.type=="void" and p.isOut] if arrayNames: #Declare C pointers to retrieve array contents for n in arrayNames: #newFunctionBody += "jbyte* " + n + "Ptr = 0;\n" newFunctionBody += "GCHandle %sHandle = new GCHandle();\nIntPtr %sPtr = IntPtr.Zero;\n" % (n,n) if n in charArrayNames: newFunctionBody += "byte[] %sArray = new UTF8Encoding().GetBytes(%s);\n" % (n,n) newFunctionBody += "try\n{\n" #Retrieve the contents for strings #We need to do this first cause in one case this char* is needed as an argument if charArrayNames: for n in charArrayNames: newFunctionBody += "getPointer(%(n)sArray, 0, ref %(n)sHandle, ref %(n)sPtr);\n" % vars() #Query the length of output data #CryptPopData is the only exception that produces output data #but doesn't require this cause an explicit length is passed in if outVoidArrayNames and functionName.find("PopData") == -1: for n in outVoidArrayNames: argumentsWithNull = arguments.replace("%sPtr + %sOffset" % (n,n), "NULL") newFunctionBody += "processStatus(wrapped_%s(%s));\n" % (functionName, argumentsWithNull) newFunctionBody += "int %s = Marshal.ReadInt32(%sPtr);\n" % (returnName, returnName) elif functionName.find("PopData") != -1 or functionName.find("PushData") != -1: newFunctionBody += "int %s = 0;\n" % returnName newFunctionBody += "int status;\n" if voidArrayNames: for n in voidArrayNames: index = [p.name for p in newParamStructs].index(n) if n in outVoidArrayNames: lengthName = returnName else: if len(newParamStructs)<=index+2 or newParamStructs[index+2].category != "rawType" or newParamStructs[index+2].type != "int": lengthName = "1" #CheckSignature and ImportKey don't have a length, so we can't do a good check! else: lengthName = newParamStructs[index+2].name newFunctionBody += "checkIndices(%(n)s, %(n)sOffset, %(lengthName)s);\n" % vars() for n in voidArrayNames: newFunctionBody += "getPointer(%(n)s, %(n)sOffset, ref %(n)sHandle, ref %(n)sPtr);\n" % vars() elif returnName: newFunctionBody += "try\n{\n" if functionName.find("PopData") == -1 and functionName.find("PushData") == -1: newFunctionBody += "processStatus(wrapped_%s(%s));\n" % (functionName, arguments) else: newFunctionBody += "status = wrapped_%s(%s);\n" % (functionName, arguments) newFunctionBody += "%s = Marshal.ReadInt32(%sPtr);\n" % (returnName, returnName) newFunctionBody += "processStatus(status, %s);\n" %returnName #if newFunctionBody[-2] != "\n": # newFunctionBody += "\n" if returnName: if returnCategory == "structType": newFunctionBody += "Marshal.PtrToStructure(%sPtr, %s);\n" % (returnName, returnName) newFunctionBody += "return %s;\n" % returnName else: if functionName.find("PopData") == -1 and functionName.find("PushData") == -1: newFunctionBody += "return Marshal.ReadInt32(%sPtr);\n" % returnName else: newFunctionBody += "return %s;\n" %returnName if arrayNames or returnName: newFunctionBody += "}\nfinally\n{\n" if returnName: newFunctionBody += "Marshal.FreeHGlobal(%sPtr);\n" % returnName if arrayNames: for n in voidArrayNames: newFunctionBody += "releasePointer(%(n)sHandle);\n" % vars() for n in charArrayNames: newFunctionBody += "releasePointer(%(n)sHandle);\n" % vars() newFunctionBody += "}\n" #Add tabs to lines inside brackets: lines = newFunctionBody.split("\n") brackets = 0 for count in range(len(lines)): line = lines[count] if line.startswith("}"): brackets -= 1 lines[count] = ("\t" * brackets) + line if line.startswith("{"): brackets += 1 newFunctionBody = "\n".join(lines) newFunctionBody = newFunctionBody[:-1] #Strip off last \n newFunctionBody = newFunctionBody.replace("\n", "\n\t"); newFunction = function[:-1]+"\n{" + newFunctionBody + "\n}" newFunction = newFunction.replace("\n", "\n\t"); #Substitute the output equivalent for the input s = s[ : functionMatch.start()] + newFunction + s[functionMatch.end() : ] #Get next function functionMatch = functionPattern.search(s, functionMatch.start() + len(newFunction)) #Add enclosing class syntax #--------------------------- s = classPrefix + s for functionName in functionNames: rawParamStructs = rawParamStructsDict[functionName] parameters = "" for p in rawParamStructs: if p.isPtr: parameters += "IntPtr %s, " % p.name else: parameters += "int %s, " % p.name parameters = parameters[:-2] s += '\t[DllImport("cl32.dll", EntryPoint="crypt%s")]\n\tprivate static extern int wrapped_%s(%s);\n\n' % (functionName, functionName, parameters) functionNames = [] #Accumulate function names here #rawParamStructsDict = {} #Accumulate function name -> list of ParamStructs (of original c code) #newParamStructsDict = {} #Accumulate function name -> list of ParamStructs (of new java/python code) s += classPostfix + exceptionString + "\n\n}" os.chdir(outDir) print "Writing .NET file..." f = open("cryptlib.cs", "w") f.write(s) f.close()