From 9f548c9928a96eaa353d95c98d8164254c04d5a1 Mon Sep 17 00:00:00 2001 From: Larry Bugbee Date: Wed, 9 Aug 2017 11:13:13 +0200 Subject: [PATCH] update demo_dynamic.py --- demos/demo_dynamic.py | 132 +++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 39 deletions(-) mode change 100755 => 100644 demos/demo_dynamic.py diff --git a/demos/demo_dynamic.py b/demos/demo_dynamic.py old mode 100755 new mode 100644 index 97e4855..ffb3017 --- a/demos/demo_dynamic.py +++ b/demos/demo_dynamic.py @@ -1,7 +1,7 @@ """ - demo_dynamic.py v1 + demo_dynamic.py v2 This program demonstrates Python's use of the dynamic language support additions to LTC, namely access to LTC @@ -19,26 +19,21 @@ load multiple .dylibs, but it does not support this level of tight coupling between otherwise 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" make - - 2- link LTC and LTM into a single .dylib: - ar2dylib_with tomcrypt tommath - where ar2dylib_with is a shell script that combines - the LTC .a with the LTM .dylib + My .dylib was created on OSX/macOS with the following: + sudo make -j5 -f makefile.shared \ + CFLAGS="-DUSE_TFM -DTFM_DESC -I/usr/local/include" \ + EXTRALIBS=/usr/local/lib/libtfm.a install 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 - do not. + you are going to use LTC functions that need a + mathlib. For example, public key crypto requires + a mathlib; hashing and symmetric encryption do not. This code was written for Python 2.7. Larry Bugbee - March 2014 + March 2014 v1 + August 2017 v2 """ @@ -46,15 +41,23 @@ from ctypes import * from ctypes.util import find_library +# switches to enable/disable selected output +SHOW_ALL_CONSTANTS = True +SHOW_ALL_SIZES = True +SHOW_SELECTED_CONSTANTS = True +SHOW_SELECTED_SIZES = True +SHOW_BUILD_OPTIONS_ALGS = True +SHOW_SHA256_EXAMPLE = True +SHOW_CHACHA_EXAMPLE = True + +print +print(' demo_dynamic.py') #--------------------------------------------------------------- # load the .dylib libname = 'tomcrypt' libpath = find_library(libname) - -print -print(' demo_dynamic.py') print print(' path to library %s: %s' % (libname, libpath)) @@ -69,7 +72,8 @@ print # supported sizes. One alternative: these lists may be parsed # and used as needed. -if 1: +if SHOW_ALL_CONSTANTS: + print '-'*60 print ' all supported constants and their values:' # get size to allocate for constants output list @@ -85,7 +89,8 @@ if 1: print -if 1: +if SHOW_ALL_SIZES: + print '-'*60 print ' all supported sizes:' # get size to allocate for sizes output list @@ -105,7 +110,8 @@ if 1: # get individually named constants and sizes # print selected constants -if 1: +if SHOW_SELECTED_CONSTANTS: + print '-'*60 print '\n selected constants:' names = [ @@ -122,7 +128,8 @@ if 1: print ' %-25s %d' % (name, value) # print selected sizes -if 1: +if SHOW_SELECTED_SIZES: + print '-'*60 print '\n selected sizes:' names = [ @@ -143,14 +150,18 @@ if 1: #--------------------------------------------------------------- #--------------------------------------------------------------- -# ctypes getting a list of this build's supported algorithms -# and compiler switches +# LibTomCrypt exposes one interesting string that can be accessed +# via Python's ctypes module, "crypt_build_settings", which +# provides a list of this build's compiler switches and supported +# algorithms. If someday LTC exposes other interesting strings, +# they can be found with: +# nm /usr/local/lib/libtomcrypt.dylib | grep " D " def get_named_string(lib, name): return c_char_p.in_dll(lib, name).value -if 0: - print '\n%s' % ('-'*60) +if SHOW_BUILD_OPTIONS_ALGS: + print '-'*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') @@ -160,23 +171,31 @@ if 0: #--------------------------------------------------------------- #--------------------------------------------------------------- -# here is an example of how a wrapper can make Python access -# more Pythonic +# here is an example of how Python code can be written to access +# LTC's implementation of SHA256 and ChaCha, # - - - - - - - - - - - - - -# a wrapper fragment... +# definitions def _get_size(name): size = c_int(0) rc = LTC.crypt_get_size(name, byref(size)) + if rc != 0: + raise Exception('LTC.crypt_get_size(%s) rc = %d' % (name, rc)) return size.value -sha256_state_struct_size = _get_size('sha256_state') -sha512_state_struct_size = _get_size('sha512_state') +def _get_constant(name): + constant = c_int(0) + rc = LTC.crypt_get_constant(name, byref(constant)) + if rc != 0: + raise Exception('LTC.crypt_get_constant(%s) rc = %d' % (name, rc)) + return constant.value + +CRYPT_OK = _get_constant('CRYPT_OK') class SHA256(object): def __init__(self): - self.state = c_buffer(sha256_state_struct_size) + self.state = c_buffer(_get_size('sha256_state')) LTC.sha256_init(byref(self.state)) def update(self, data): LTC.sha256_process(byref(self.state), data, len(data)) @@ -185,19 +204,54 @@ class SHA256(object): LTC.sha256_done(byref(self.state), byref(md)) return md.raw +class ChaCha(object): + def __init__(self, key, rounds): + self.state = c_buffer(_get_size('chacha_state')) + self.counter = c_int(1) + err = LTC.chacha_setup(byref(self.state), key, len(key), rounds) + def set_iv32(self, iv): + err = LTC.chacha_ivctr32(byref(self.state), iv, len(iv), byref(self.counter)) + if err != CRYPT_OK: + raise Exception('LTC.chacha_ivctr32() err = %d' % err) + def crypt(self, datain): + dataout = c_buffer(len(datain)) + err = LTC.chacha_crypt(byref(self.state), datain, len(datain), byref(dataout)) + if err != CRYPT_OK: + raise Exception('LTC.chacha_crypt() err = %d' % err) + return dataout.raw + # - - - - - - - - - - - - - -# an app fragment... +# a SHA256 app fragment... # from wrapper import * # uncomment in real life -data = 'hello world' +if SHOW_SHA256_EXAMPLE: + print '-'*60 + data = 'hello world' -sha256 = SHA256() -sha256.update(data) -md = sha256.digest() + 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')) + template = '\n the SHA256 digest for "%s" is %s \n' + print template % (data, md.encode('hex')) + +# - - - - - - - - - - - - - +# a ChaCha app fragment... + +if SHOW_CHACHA_EXAMPLE: + print '-'*60 + key = 'hownowbrowncow\x00\x00' # exactly 16 or 32 bytes + rounds = 12 # common values: 8, 12, 20 + iv = '123456789012' # exactly 12 bytes + plain = 'Kilroy was here, there, and everywhere!' + + cha = ChaCha(key, rounds) + cha.set_iv32(iv) + cipher = cha.crypt(plain) + + template = '\n ChaCha%d ciphertext for "%s" is "%s" \n' + print template % (rounds, plain, cipher.encode('hex'))