Преглед изворни кода

Merge pull request #272 from libtom/update-demos-demo_dynamic.py

Update demos demo dynamic.py - everything is green
Larry Bugbee пре 8 година
родитељ
комит
725532c6b6
2 измењених фајлова са 94 додато и 378 уклоњено
  1. 94 66
      demos/demo_dynamic.py
  2. 0 312
      demos/demo_dynamic.py3

+ 94 - 66
demos/demo_dynamic.py

@@ -1,7 +1,7 @@
 
 
 """
-    demo_dynamic.py                                     v2b
+    demo_dynamic.py                                    v2b
 
     This program demonstrates Python's use of the dynamic
     language support additions to LTC, namely access to LTC
@@ -33,8 +33,31 @@
               mathlib.  For example, public key crypto requires
               a mathlib; hashing and symmetric encryption do not.
 
-    This code was written for Python 2.7 with the ctypes standard
-    library.
+    ------
+
+    This code was originally written for Python 2.7 with the
+    ctypes standard library.  This version is modified to run
+    under both Python 2.7 and 3.6.
+
+    Arguably the biggest change for Python3 has to do with
+    strings.  Under Python2, native strings are ASCII bytes and
+    passing them to LTC is natural and requires no conversion.
+    Under Python3 all native strings are Unicode which requires
+    they be converted to bytes before use by LTC.
+
+    Note the following for Python3.
+        - ASCII keys, IVs and other string arguments must be
+          'bytes'.  Define them with a 'b' prefix or convert
+          via the 'bytes()' function.
+        - "strings" returned from LTC are bytes and conversion
+          to Unicode might be necessary for proper printing.
+          If so, use <string>.decode('utf-8').
+        - The Python2 'print' statement becomes a function in
+          Python3 which requires parenthesis, eg. 'print()'.
+
+    NB: Unicode is achieved under Python2 by either defining
+        a Unicode string with a 'u' prefix or passing ASCII
+        strings thru the 'unicode()' function.
 
     Larry Bugbee
     March 2014      v1
@@ -43,6 +66,7 @@
 """
 
 
+import sys
 from ctypes import *
 from ctypes.util import find_library
 
@@ -55,21 +79,25 @@ SHOW_BUILD_OPTIONS_ALGS = True
 SHOW_SHA256_EXAMPLE     = True
 SHOW_CHACHA_EXAMPLE     = True
 
-print
+print(' ')
 print('  demo_dynamic.py')
 
+def inprint(s, indent=0):
+    "prints strings indented, including multline strings"
+    for line in s.split('\n'):
+        print(' '*indent + line)
 
 #-------------------------------------------------------------------------------
 # load the .dylib
 
 libname = 'tomcrypt'
 libpath = find_library(libname)
-print
+print(' ')
 print('  path to library %s: %s' % (libname, libpath))
 
 LTC = cdll.LoadLibrary(libpath)
 print('  loaded: %s' % LTC)
-print
+print(' ')
 
 
 #-------------------------------------------------------------------------------
@@ -78,79 +106,79 @@ print
 # and used as needed.
 
 if SHOW_ALL_CONSTANTS:
-    print '-'*60
-    print '  all supported constants and their values:'
+    print('-'*60)
+    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 to build list \n' % str_len.value
+    print('    need to allocate %d bytes to build list \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
+    print(names_sizes.value.decode("utf-8"))
+    print(' ')
 
 
 if SHOW_ALL_SIZES:
-    print '-'*60
-    print '  all supported sizes:'
+    print('-'*60)
+    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 to build list \n' % str_len.value
+    print('    need to allocate %d bytes to build list \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
+    print(names_sizes.value.decode("utf-8"))
+    print(' ')
 
 
 #-------------------------------------------------------------------------------
 # get individually named constants and sizes
 
 if SHOW_SELECTED_CONSTANTS:
-    print '-'*60
-    print '\n  selected constants:'
+    print('-'*60)
+    print('\n  selected constants:')
 
     names = [
-        'ENDIAN_LITTLE',
-        'ENDIAN_64BITWORD',
-        'PK_PUBLIC',
-        'MAX_RSA_SIZE',
-        'CTR_COUNTER_BIG_ENDIAN',
+        b'ENDIAN_LITTLE',
+        b'ENDIAN_64BITWORD',
+        b'PK_PUBLIC',
+        b'MAX_RSA_SIZE',
+        b'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
+        print('    %-25s  %d' % (name.decode("utf-8"), value))
+    print(' ')
 
 if SHOW_SELECTED_SIZES:
-    print '-'*60
-    print '\n  selected sizes:'
+    print('-'*60)
+    print('\n  selected sizes:')
 
     names = [
-        'rijndael_key',
-        'rsa_key',
-        'symmetric_CTR',
-        'twofish_key',
-        'ecc_point',
-        'gcm_state',
-        'sha512_state',
+        b'rijndael_key',
+        b'rsa_key',
+        b'symmetric_CTR',
+        b'twofish_key',
+        b'ecc_point',
+        b'gcm_state',
+        b'sha512_state',
     ]
     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)
-    print
+        print('    %-25s  %d' % (name.decode("utf-8"), value))
+    print(' ')
 
 
 #-------------------------------------------------------------------------------
@@ -163,13 +191,14 @@ if SHOW_SELECTED_SIZES:
 #   nm /usr/local/lib/libtomcrypt.dylib | grep " D "
 
 def get_named_string(lib, name):
-    return c_char_p.in_dll(lib, name).value
+    return c_char_p.in_dll(lib, name).value.decode("utf-8")
 
 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')
+    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'))
+    inprint(get_named_string(LTC, 'crypt_build_settings'), 4)
 
 
 #-------------------------------------------------------------------------------
@@ -180,32 +209,34 @@ if SHOW_BUILD_OPTIONS_ALGS:
 # - - - - - - - - - - - - -
 # definitions
 
+from binascii import hexlify, unhexlify
+
+def _err2str(err):
+    # define return type
+    errstr = LTC.error_to_string
+    errstr.restype = c_char_p
+    # get and return err string
+    return errstr(err)
+
 def _get_size(name):
     size = c_int(0)
-    rc = LTC.crypt_get_size(name, byref(size))
+    rc = LTC.crypt_get_size(bytes(name), byref(size))
     if rc != 0:
         raise Exception('LTC.crypt_get_size(%s) rc = %d' % (name, rc))
     return size.value
 
 def _get_constant(name):
     constant = c_int(0)
-    rc = LTC.crypt_get_constant(name, byref(constant))
+    rc = LTC.crypt_get_constant(bytes(name), byref(constant))
     if rc != 0:
         raise Exception('LTC.crypt_get_constant(%s) rc = %d' % (name, rc))
     return constant.value
 
-def _err2str(err):
-    # define return type
-    errstr = LTC.error_to_string
-    errstr.restype = c_char_p
-    # get and return err string
-    return errstr(err)
-
-CRYPT_OK = _get_constant('CRYPT_OK')
+CRYPT_OK = _get_constant(b'CRYPT_OK')
 
 class SHA256(object):
     def __init__(self):
-        self.state = c_buffer(_get_size('sha256_state'))
+        self.state = c_buffer(_get_size(b'sha256_state'))
         LTC.sha256_init(byref(self.state))
     def update(self, data):
         LTC.sha256_process(byref(self.state), data, len(data))
@@ -216,7 +247,7 @@ class SHA256(object):
 
 class ChaCha(object):
     def __init__(self, key, rounds):
-        self.state   = c_buffer(_get_size('chacha_state'))
+        self.state   = c_buffer(_get_size(b'chacha_state'))
         self.counter = c_int(1)
         err = LTC.chacha_setup(byref(self.state), key, len(key), rounds)
         if err != CRYPT_OK:
@@ -235,42 +266,39 @@ class ChaCha(object):
 # - - - - - - - - - - - - -
 # a SHA256 app fragment
 
-# from wrapper import *         # uncomment in real life
-
 if SHOW_SHA256_EXAMPLE:
-    print '-'*60
-    data = 'hello world'
+    print('-'*60)
+    data = b'hello world'               # we want bytes, not Unicode
 
     sha256 = SHA256()
     sha256.update(data)
     md = sha256.digest()
 
     template = '\n  the SHA256 digest for "%s" is %s \n'
-    print template % (data, md.encode('hex'))
+    print(template % (data, hexlify(md)))
 
 # - - - - - - - - - - - - -
 # a ChaCha app fragment
 
 if SHOW_CHACHA_EXAMPLE:
-    print '-'*60
-    key     = 'hownowbrowncow\x00\x00'  # exactly 16 or 32 bytes
+    print('-'*60)
+    key     = b'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!'
+    iv      = b'123456789012'           # exactly 12 bytes
+    plain   = b'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"'
-    print template % (rounds, plain, cipher.encode('hex'))
+    print(template % (rounds, plain, hexlify(cipher)))
 
-    # reset to decrypt
-    cha.set_iv32(iv)
+    cha.set_iv32(iv)                    # reset to decrypt
     decrypted = cha.crypt(cipher)
 
     template = '  ChaCha%d decoded text for "%s" is "%s" \n'
-    print template % (rounds, plain, decrypted)
+    print(template % (rounds, plain, decrypted.decode("utf-8")))
 
 # Footnote: Keys should be erased fm memory as soon as possible after use,
 # and that includes Python.  For a tip on how to do that in Python, see

+ 0 - 312
demos/demo_dynamic.py3

@@ -1,312 +0,0 @@
-
-
-"""
-    demo_dynamic.py3                                    v2b
-
-    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 a math library.  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 tight coupling between otherwise independent libraries.)
-
-    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
-
-    For python 2.7.12 on Ubuntu Xenial the following worked for
-    me (without MPI support):
-        sudo make -f makefile.shared install PREFIX="/usr"
-
-    Reminder: you don't need to bind in a math library unless
-              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 originally written for Python 2.7 with the
-    ctypes standard library.  This version was modified so that
-    it would run under both Python 2.7 and 3.6.  You might want
-    to run a diff on the .py and .py3 files to see the differences
-    between the two languages.    
-    
-    Arguably the biggest change for Python3 has to do with
-    strings.  Under Python2, native strings are ASCII bytes and
-    passing them to LTC is natural and requires no conversion.
-    Under Python3 all native strings are Unicode which requires 
-    they be converted to bytes before use by LTC.
-
-    Note the following for Python3.
-        - ASCII keys, IVs and other string arguments must be
-          'bytes'.  Define them with a 'b' prefix or convert
-          via the 'bytes()' function.
-        - "strings" returned from LTC are bytes and conversion
-          to Unicode might be necessary for proper printing.
-          If so, use <string>.decode('utf-8').
-        - The Python2 'print' statement becomes a function in
-          Python3 which requires parenthesis, eg. 'print()'.
-        
-    NB: Unicode is achieved under Python2 by either defining
-        a Unicode string with a 'u' prefix or passing ASCII
-        strings thru the 'unicode()' function.
-    
-
-    Larry Bugbee
-    March 2014      v1
-    August 2017     v2b
-
-"""
-
-
-import sys
-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')
-
-def inprint(s, indent=0):
-    "prints strings indented, including multline strings"
-    for line in s.split('\n'):
-        print(' '*indent + line)
-
-#-------------------------------------------------------------------------------
-# load the .dylib
-
-libname = 'tomcrypt'
-libpath = find_library(libname)
-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 SHOW_ALL_CONSTANTS:
-    print('-'*60)
-    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 to build list \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.decode("utf-8"))
-    print(' ')
-
-
-if SHOW_ALL_SIZES:
-    print('-'*60)
-    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 to build list \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.decode("utf-8"))
-    print(' ')
-
-
-#-------------------------------------------------------------------------------
-# get individually named constants and sizes
-
-if SHOW_SELECTED_CONSTANTS:
-    print('-'*60)
-    print('\n  selected constants:')
-
-    names = [
-        b'ENDIAN_LITTLE',
-        b'ENDIAN_64BITWORD',
-        b'PK_PUBLIC',
-        b'MAX_RSA_SIZE',
-        b'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.decode("utf-8"), value))
-    print(' ')
-
-if SHOW_SELECTED_SIZES:
-    print('-'*60)
-    print('\n  selected sizes:')
-
-    names = [
-        b'rijndael_key',
-        b'rsa_key',
-        b'symmetric_CTR',
-        b'twofish_key',
-        b'ecc_point',
-        b'gcm_state',
-        b'sha512_state',
-    ]
-    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.decode("utf-8"), value))
-    print(' ')
-
-
-#-------------------------------------------------------------------------------
-#-------------------------------------------------------------------------------
-# 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.decode("utf-8")
-
-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'))
-    inprint(get_named_string(LTC, 'crypt_build_settings'), 4)
-
-
-#-------------------------------------------------------------------------------
-#-------------------------------------------------------------------------------
-# here is an example of how Python code can be written to access
-# LTC's implementation of SHA256 and ChaCha,
-
-# - - - - - - - - - - - - -
-# definitions
-
-from binascii import hexlify, unhexlify
-
-def _err2str(err):
-    # define return type
-    errstr = LTC.error_to_string
-    errstr.restype = c_char_p
-    # get and return err string
-    return errstr(err)
-
-def _get_size(name):
-    size = c_int(0)
-    rc = LTC.crypt_get_size(bytes(name), byref(size))
-    if rc != 0:
-        raise Exception('LTC.crypt_get_size(%s) rc = %d' % (name, rc))
-    return size.value
-
-def _get_constant(name):
-    constant = c_int(0)
-    rc = LTC.crypt_get_constant(bytes(name), byref(constant))
-    if rc != 0:
-        raise Exception('LTC.crypt_get_constant(%s) rc = %d' % (name, rc))
-    return constant.value
-
-CRYPT_OK = _get_constant(b'CRYPT_OK')
-
-class SHA256(object):
-    def __init__(self):
-        self.state = c_buffer(_get_size(b'sha256_state'))
-        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
-
-class ChaCha(object):
-    def __init__(self, key, rounds):
-        self.state   = c_buffer(_get_size(b'chacha_state'))
-        self.counter = c_int(1)
-        err = LTC.chacha_setup(byref(self.state), key, len(key), rounds)
-        if err != CRYPT_OK:
-            raise Exception('LTC.chacha_setup(), err = %d, "%s"' % (err, _err2str(err)))
-    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, "%s"' % (err, _err2str(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, "%s"' % (err, _err2str(err)))
-        return dataout.raw
-
-# - - - - - - - - - - - - -
-# a SHA256 app fragment
-
-if SHOW_SHA256_EXAMPLE:
-    print('-'*60)
-    data = b'hello world'               # we want bytes, not Unicode
-
-    sha256 = SHA256()
-    sha256.update(data)
-    md = sha256.digest()
-
-    template = '\n  the SHA256 digest for "%s" is %s \n'
-    print(template % (data, hexlify(md)))
-
-# - - - - - - - - - - - - -
-# a ChaCha app fragment
-
-if SHOW_CHACHA_EXAMPLE:
-    print('-'*60)
-    key     = b'hownowbrowncow\x00\x00' # exactly 16 or 32 bytes
-    rounds  = 12                        # common values: 8, 12, 20
-    iv      = b'123456789012'           # exactly 12 bytes
-    plain   = b'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"'
-    print(template % (rounds, plain, hexlify(cipher)))
-
-    cha.set_iv32(iv)                    # reset to decrypt
-    decrypted = cha.crypt(cipher)
-
-    template = '  ChaCha%d decoded text for "%s" is "%s" \n'
-    print(template % (rounds, plain, decrypted.decode("utf-8")))
-
-# Footnote: Keys should be erased fm memory as soon as possible after use,
-# and that includes Python.  For a tip on how to do that in Python, see
-# http://buggywhip.blogspot.com/2010/12/erase-keys-and-credit-card-numbers-in.html
-
-#-------------------------------------------------------------------------------
-#-------------------------------------------------------------------------------
-#-------------------------------------------------------------------------------