|
@@ -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'))
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+#---------------------------------------------------------------
|
|
|
|
+#---------------------------------------------------------------
|
|
|
|
+#---------------------------------------------------------------
|