123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- """
- 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'))
- #---------------------------------------------------------------
- #---------------------------------------------------------------
- #---------------------------------------------------------------
|