207 lines
5.8 KiB
Python
207 lines
5.8 KiB
Python
|
|
||
|
|
||
|
"""
|
||
|
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 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 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
|
||
|
|
||
|
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.
|
||
|
|
||
|
This code was written for Python 2.7.
|
||
|
|
||
|
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 = [
|
||
|
'ENDIAN_LITTLE',
|
||
|
'ENDIAN_64BITWORD',
|
||
|
'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',
|
||
|
'rsa_key',
|
||
|
'symmetric_CTR',
|
||
|
'twofish_key',
|
||
|
'ecc_point',
|
||
|
'gcm_state',
|
||
|
'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)
|
||
|
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
#---------------------------------------------------------------
|
||
|
# 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')
|
||
|
sha512_state_struct_size = _get_size('sha512_state')
|
||
|
|
||
|
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'))
|
||
|
|
||
|
|
||
|
|
||
|
#---------------------------------------------------------------
|
||
|
#---------------------------------------------------------------
|
||
|
#---------------------------------------------------------------
|