diff --git a/demos/demo_dynamic.py b/demos/demo_dynamic.py new file mode 100644 index 0000000..a22e240 --- /dev/null +++ b/demos/demo_dynamic.py @@ -0,0 +1,237 @@ + + +""" + demo_dynamic.py v1 + + This program demonstrates Python's use of the dynamic + language support additions to LTC, namely access to LTC + constants, struct and union sizes, and the binding of a + math package to LTC. Also provided are simple code + fragments to illustrate how one might write a Python + wrapper for LTC and how an app might call the wrapper. + This or a similar model should work for Ruby and other + dynamic languages. + + This instance uses Python's ctypes and requires a single + .dylib linking together LTC and one or more math libraries. + Building a single .dylib is needed because LTC wants a + fairly tight relationship between itself and the mathlib. + (ctypes can load multiple .dylibs, but it does not support + this level of coupling between those independent libraries.) + + My .dylib was created on OSX with the following steps: + + 1- compile LTC to a .a static lib: + CFLAGS="-DLTM_DESC -DUSE_LTM -DTFM_DESC -DUSE_TFM \ + -I/usr/local/include" make + + 2- link LTC, LTM and TFM into a single .dylib: + ar2dylib_with_and tomcrypt tommath tfm + where ar2dylib_with_and is a shell script that combines + the .a with .dylibs for LTM and TFM + + Reminder: you don't need to bind in a math library unless + you are going to use LTC functions that depend + on a mathlib. For example, public key crypto + needs a mathlib; hashing and symmetric encryption + does not. + + Larry Bugbee + March 2014 + +""" + + +from ctypes import * +from ctypes.util import find_library + + +#--------------------------------------------------------------- +# load the .dylib + +libname = 'tomcrypt' +libpath = find_library(libname) + +print +print(' demo_dynamic.py') +print +print(' path to library %s: %s' % (libname, libpath)) + +LTC = cdll.LoadLibrary(libpath) +print(' loaded: %s' % LTC) +print + + + +#--------------------------------------------------------------- +# get list of all supported constants followed by a list of all +# supported sizes. One alternative: these lists may be parsed +# and used as needed. + +if 1: + print ' all supported constants and their values:' + + # get size to allocate for constants output list + str_len = c_int(0) + ret = LTC.crypt_list_all_constants(None, byref(str_len)) + print ' need to allocate %d bytes \n' % str_len.value + + # allocate that size and get (name, size) pairs, each pair + # separated by a newline char. + names_sizes = c_buffer(str_len.value) + ret = LTC.crypt_list_all_constants(names_sizes, byref(str_len)) + print names_sizes.value + print + + +if 1: + print ' all supported sizes:' + + # get size to allocate for sizes output list + str_len = c_int(0) + ret = LTC.crypt_list_all_sizes(None, byref(str_len)) + print ' need to allocate %d bytes \n' % str_len.value + + # allocate that size and get (name, size) pairs, each pair + # separated by a newline char. + names_sizes = c_buffer(str_len.value) + ret = LTC.crypt_list_all_sizes(names_sizes, byref(str_len)) + print names_sizes.value + print + + +#--------------------------------------------------------------- +# get individually named constants and sizes + +# print selected constants +if 1: + print '\n selected constants:' + + names = [ + 'PK_PUBLIC', + 'MAX_RSA_SIZE', + 'CTR_COUNTER_BIG_ENDIAN', + ] + for name in names: + const_value = c_int(0) + rc = LTC.crypt_get_constant(name, byref(const_value)) + value = const_value.value + print ' %-25s %d' % (name, value) + +# print selected sizes +if 1: + print '\n selected sizes:' + + names = [ + 'rijndael_key_struct_size', + 'rsa_key_struct_size', + 'symmetric_CTR_struct_size', + 'twofish_key_struct_size', + 'ecc_point_struct_size', + 'gcm_state_struct_size', + 'sha512_state_struct_size', + ] + for name in names: + size_value = c_int(0) + rc = LTC.crypt_get_size(name, byref(size_value)) + value = size_value.value + print ' %-25s %d' % (name, value) + + +#--------------------------------------------------------------- +# init the selected math package, change to another mathlib, +# and change back to the first mathlib + +if 1: + print '\n init the selected math package, change, and change again' + + # show ltm_desc + ptr = c_int.in_dll(LTC, 'ltm_desc') + print ' ltm_desc: ', hex(ptr.value) + # show tfm_desc + ptr = c_int.in_dll(LTC, 'tfm_desc') + print ' tfm_desc: ', hex(ptr.value) + # let's see the initial value of ltc_mp + ptr = c_int.in_dll(LTC, 'ltc_mp') + print ' initial ptr:', hex(ptr.value) + + # init LTM and show ltc_mp + LTC.init_LTM() + ptr = c_int.in_dll(LTC, 'ltc_mp') + print ' ptr to LTM: ', hex(ptr.value) + + # init TFM and show ltc_mp + LTC.init_TFM() + ptr = c_int.in_dll(LTC, 'ltc_mp') + print ' ptr to TFM: ', hex(ptr.value) + + # now change back to LTM + LTC.init_LTM() + ptr = c_int.in_dll(LTC, 'ltc_mp') + print ' ptr to LTM: ', hex(ptr.value) + + + +#--------------------------------------------------------------- +#--------------------------------------------------------------- +# ctypes getting a list of this build's supported algorithms +# and compiler switches + +def get_named_string(lib, name): + return c_char_p.in_dll(lib, name).value + +if 0: + print '\n%s' % ('-'*60) + print 'This is a string compiled into LTC showing compile ' + print 'options and algorithms supported by this build \n' + print get_named_string(LTC, 'crypt_build_settings') + print + + + +#--------------------------------------------------------------- +#--------------------------------------------------------------- +# here is an example of how a wrapper can make Python access +# more Pythonic + +# - - - - - - - - - - - - - +# a wrapper fragment... + +def _get_size(name): + size = c_int(0) + rc = LTC.crypt_get_size(name, byref(size)) + return size.value + +sha256_state_struct_size = _get_size('sha256_state_struct_size') +sha512_state_struct_size = _get_size('sha512_state_struct_size') + +class SHA256(object): + def __init__(self): + self.state = c_buffer(sha256_state_struct_size) + LTC.sha256_init(byref(self.state)) + def update(self, data): + LTC.sha256_process(byref(self.state), data, len(data)) + def digest(self): + md = c_buffer(32) + LTC.sha256_done(byref(self.state), byref(md)) + return md.raw + +# - - - - - - - - - - - - - +# an app fragment... + +# from wrapper import * # uncomment in real life + +data = 'hello world' + +sha256 = SHA256() +sha256.update(data) +md = sha256.digest() + +template = '\n\n the SHA256 digest for "%s" is %s \n' +print template % (data, md.encode('hex')) + + + +#--------------------------------------------------------------- +#--------------------------------------------------------------- +#---------------------------------------------------------------