Merge pull request #272 from libtom/update-demos-demo_dynamic.py
Update demos demo dynamic.py - everything is green
This commit is contained in:
commit
725532c6b6
@ -33,8 +33,31 @@
|
|||||||
mathlib. For example, public key crypto requires
|
mathlib. For example, public key crypto requires
|
||||||
a mathlib; hashing and symmetric encryption do not.
|
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
|
Larry Bugbee
|
||||||
March 2014 v1
|
March 2014 v1
|
||||||
@ -43,6 +66,7 @@
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
from ctypes import *
|
from ctypes import *
|
||||||
from ctypes.util import find_library
|
from ctypes.util import find_library
|
||||||
|
|
||||||
@ -55,21 +79,25 @@ SHOW_BUILD_OPTIONS_ALGS = True
|
|||||||
SHOW_SHA256_EXAMPLE = True
|
SHOW_SHA256_EXAMPLE = True
|
||||||
SHOW_CHACHA_EXAMPLE = True
|
SHOW_CHACHA_EXAMPLE = True
|
||||||
|
|
||||||
print
|
print(' ')
|
||||||
print(' demo_dynamic.py')
|
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
|
# load the .dylib
|
||||||
|
|
||||||
libname = 'tomcrypt'
|
libname = 'tomcrypt'
|
||||||
libpath = find_library(libname)
|
libpath = find_library(libname)
|
||||||
print
|
print(' ')
|
||||||
print(' path to library %s: %s' % (libname, libpath))
|
print(' path to library %s: %s' % (libname, libpath))
|
||||||
|
|
||||||
LTC = cdll.LoadLibrary(libpath)
|
LTC = cdll.LoadLibrary(libpath)
|
||||||
print(' loaded: %s' % LTC)
|
print(' loaded: %s' % LTC)
|
||||||
print
|
print(' ')
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
@ -78,79 +106,79 @@ print
|
|||||||
# and used as needed.
|
# and used as needed.
|
||||||
|
|
||||||
if SHOW_ALL_CONSTANTS:
|
if SHOW_ALL_CONSTANTS:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
print ' all supported constants and their values:'
|
print(' all supported constants and their values:')
|
||||||
|
|
||||||
# get size to allocate for constants output list
|
# get size to allocate for constants output list
|
||||||
str_len = c_int(0)
|
str_len = c_int(0)
|
||||||
ret = LTC.crypt_list_all_constants(None, byref(str_len))
|
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
|
# allocate that size and get (name, size) pairs, each pair
|
||||||
# separated by a newline char.
|
# separated by a newline char.
|
||||||
names_sizes = c_buffer(str_len.value)
|
names_sizes = c_buffer(str_len.value)
|
||||||
ret = LTC.crypt_list_all_constants(names_sizes, byref(str_len))
|
ret = LTC.crypt_list_all_constants(names_sizes, byref(str_len))
|
||||||
print names_sizes.value
|
print(names_sizes.value.decode("utf-8"))
|
||||||
print
|
print(' ')
|
||||||
|
|
||||||
|
|
||||||
if SHOW_ALL_SIZES:
|
if SHOW_ALL_SIZES:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
print ' all supported sizes:'
|
print(' all supported sizes:')
|
||||||
|
|
||||||
# get size to allocate for sizes output list
|
# get size to allocate for sizes output list
|
||||||
str_len = c_int(0)
|
str_len = c_int(0)
|
||||||
ret = LTC.crypt_list_all_sizes(None, byref(str_len))
|
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
|
# allocate that size and get (name, size) pairs, each pair
|
||||||
# separated by a newline char.
|
# separated by a newline char.
|
||||||
names_sizes = c_buffer(str_len.value)
|
names_sizes = c_buffer(str_len.value)
|
||||||
ret = LTC.crypt_list_all_sizes(names_sizes, byref(str_len))
|
ret = LTC.crypt_list_all_sizes(names_sizes, byref(str_len))
|
||||||
print names_sizes.value
|
print(names_sizes.value.decode("utf-8"))
|
||||||
print
|
print(' ')
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
# get individually named constants and sizes
|
# get individually named constants and sizes
|
||||||
|
|
||||||
if SHOW_SELECTED_CONSTANTS:
|
if SHOW_SELECTED_CONSTANTS:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
print '\n selected constants:'
|
print('\n selected constants:')
|
||||||
|
|
||||||
names = [
|
names = [
|
||||||
'ENDIAN_LITTLE',
|
b'ENDIAN_LITTLE',
|
||||||
'ENDIAN_64BITWORD',
|
b'ENDIAN_64BITWORD',
|
||||||
'PK_PUBLIC',
|
b'PK_PUBLIC',
|
||||||
'MAX_RSA_SIZE',
|
b'MAX_RSA_SIZE',
|
||||||
'CTR_COUNTER_BIG_ENDIAN',
|
b'CTR_COUNTER_BIG_ENDIAN',
|
||||||
]
|
]
|
||||||
for name in names:
|
for name in names:
|
||||||
const_value = c_int(0)
|
const_value = c_int(0)
|
||||||
rc = LTC.crypt_get_constant(name, byref(const_value))
|
rc = LTC.crypt_get_constant(name, byref(const_value))
|
||||||
value = const_value.value
|
value = const_value.value
|
||||||
print ' %-25s %d' % (name, value)
|
print(' %-25s %d' % (name.decode("utf-8"), value))
|
||||||
print
|
print(' ')
|
||||||
|
|
||||||
if SHOW_SELECTED_SIZES:
|
if SHOW_SELECTED_SIZES:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
print '\n selected sizes:'
|
print('\n selected sizes:')
|
||||||
|
|
||||||
names = [
|
names = [
|
||||||
'rijndael_key',
|
b'rijndael_key',
|
||||||
'rsa_key',
|
b'rsa_key',
|
||||||
'symmetric_CTR',
|
b'symmetric_CTR',
|
||||||
'twofish_key',
|
b'twofish_key',
|
||||||
'ecc_point',
|
b'ecc_point',
|
||||||
'gcm_state',
|
b'gcm_state',
|
||||||
'sha512_state',
|
b'sha512_state',
|
||||||
]
|
]
|
||||||
for name in names:
|
for name in names:
|
||||||
size_value = c_int(0)
|
size_value = c_int(0)
|
||||||
rc = LTC.crypt_get_size(name, byref(size_value))
|
rc = LTC.crypt_get_size(name, byref(size_value))
|
||||||
value = size_value.value
|
value = size_value.value
|
||||||
print ' %-25s %d' % (name, value)
|
print(' %-25s %d' % (name.decode("utf-8"), value))
|
||||||
print
|
print(' ')
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
@ -163,13 +191,14 @@ if SHOW_SELECTED_SIZES:
|
|||||||
# nm /usr/local/lib/libtomcrypt.dylib | grep " D "
|
# nm /usr/local/lib/libtomcrypt.dylib | grep " D "
|
||||||
|
|
||||||
def get_named_string(lib, name):
|
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:
|
if SHOW_BUILD_OPTIONS_ALGS:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
print 'This is a string compiled into LTC showing compile '
|
print('This is a string compiled into LTC showing compile')
|
||||||
print 'options and algorithms supported by this build \n'
|
print('options and algorithms supported by this build \n')
|
||||||
print get_named_string(LTC, 'crypt_build_settings')
|
# print(get_named_string(LTC, 'crypt_build_settings'))
|
||||||
|
inprint(get_named_string(LTC, 'crypt_build_settings'), 4)
|
||||||
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
#-------------------------------------------------------------------------------
|
||||||
@ -180,19 +209,7 @@ if SHOW_BUILD_OPTIONS_ALGS:
|
|||||||
# - - - - - - - - - - - - -
|
# - - - - - - - - - - - - -
|
||||||
# definitions
|
# definitions
|
||||||
|
|
||||||
def _get_size(name):
|
from binascii import hexlify, unhexlify
|
||||||
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
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
def _err2str(err):
|
def _err2str(err):
|
||||||
# define return type
|
# define return type
|
||||||
@ -201,11 +218,25 @@ def _err2str(err):
|
|||||||
# get and return err string
|
# get and return err string
|
||||||
return errstr(err)
|
return errstr(err)
|
||||||
|
|
||||||
CRYPT_OK = _get_constant('CRYPT_OK')
|
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):
|
class SHA256(object):
|
||||||
def __init__(self):
|
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))
|
LTC.sha256_init(byref(self.state))
|
||||||
def update(self, data):
|
def update(self, data):
|
||||||
LTC.sha256_process(byref(self.state), data, len(data))
|
LTC.sha256_process(byref(self.state), data, len(data))
|
||||||
@ -216,7 +247,7 @@ class SHA256(object):
|
|||||||
|
|
||||||
class ChaCha(object):
|
class ChaCha(object):
|
||||||
def __init__(self, key, rounds):
|
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)
|
self.counter = c_int(1)
|
||||||
err = LTC.chacha_setup(byref(self.state), key, len(key), rounds)
|
err = LTC.chacha_setup(byref(self.state), key, len(key), rounds)
|
||||||
if err != CRYPT_OK:
|
if err != CRYPT_OK:
|
||||||
@ -235,42 +266,39 @@ class ChaCha(object):
|
|||||||
# - - - - - - - - - - - - -
|
# - - - - - - - - - - - - -
|
||||||
# a SHA256 app fragment
|
# a SHA256 app fragment
|
||||||
|
|
||||||
# from wrapper import * # uncomment in real life
|
|
||||||
|
|
||||||
if SHOW_SHA256_EXAMPLE:
|
if SHOW_SHA256_EXAMPLE:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
data = 'hello world'
|
data = b'hello world' # we want bytes, not Unicode
|
||||||
|
|
||||||
sha256 = SHA256()
|
sha256 = SHA256()
|
||||||
sha256.update(data)
|
sha256.update(data)
|
||||||
md = sha256.digest()
|
md = sha256.digest()
|
||||||
|
|
||||||
template = '\n the SHA256 digest for "%s" is %s \n'
|
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
|
# a ChaCha app fragment
|
||||||
|
|
||||||
if SHOW_CHACHA_EXAMPLE:
|
if SHOW_CHACHA_EXAMPLE:
|
||||||
print '-'*60
|
print('-'*60)
|
||||||
key = 'hownowbrowncow\x00\x00' # exactly 16 or 32 bytes
|
key = b'hownowbrowncow\x00\x00' # exactly 16 or 32 bytes
|
||||||
rounds = 12 # common values: 8, 12, 20
|
rounds = 12 # common values: 8, 12, 20
|
||||||
iv = '123456789012' # exactly 12 bytes
|
iv = b'123456789012' # exactly 12 bytes
|
||||||
plain = 'Kilroy was here, there, and everywhere!'
|
plain = b'Kilroy was here, there, and everywhere!'
|
||||||
|
|
||||||
cha = ChaCha(key, rounds)
|
cha = ChaCha(key, rounds)
|
||||||
cha.set_iv32(iv)
|
cha.set_iv32(iv)
|
||||||
cipher = cha.crypt(plain)
|
cipher = cha.crypt(plain)
|
||||||
|
|
||||||
template = '\n ChaCha%d ciphertext for "%s" is "%s"'
|
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) # reset to decrypt
|
||||||
cha.set_iv32(iv)
|
|
||||||
decrypted = cha.crypt(cipher)
|
decrypted = cha.crypt(cipher)
|
||||||
|
|
||||||
template = ' ChaCha%d decoded text for "%s" is "%s" \n'
|
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,
|
# 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
|
# and that includes Python. For a tip on how to do that in Python, see
|
||||||
|
@ -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
|
|
||||||
|
|
||||||
#-------------------------------------------------------------------------------
|
|
||||||
#-------------------------------------------------------------------------------
|
|
||||||
#-------------------------------------------------------------------------------
|
|
Loading…
x
Reference in New Issue
Block a user