tomcrypt/demos/demo_dynamic.py

207 lines
5.9 KiB
Python
Raw Normal View History

2014-03-07 00:25:31 -05:00
"""
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
2014-03-08 15:16:58 -05:00
.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.)
2014-03-07 00:25:31 -05:00
My .dylib was created on OSX with the following steps:
1- compile LTC to a .a static lib:
2014-03-08 15:16:58 -05:00
CFLAGS="-DLTM_DESC -DUSE_LTM" make
2014-03-07 00:25:31 -05:00
2014-03-08 15:16:58 -05:00
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
2014-03-07 00:25:31 -05:00
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
2014-03-08 15:16:58 -05:00
do not.
This code was written for Python 2.7.
2014-03-07 00:25:31 -05:00
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',
2014-03-07 00:25:31 -05:00
'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',
2014-03-07 00:25:31 -05:00
]
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')
2014-03-07 00:25:31 -05:00
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'))
#---------------------------------------------------------------
#---------------------------------------------------------------
#---------------------------------------------------------------