11
22
33"""
4- demo_dynamic.py v2b
4+ demo_dynamic.py v2b
55
66 This program demonstrates Python's use of the dynamic
77 language support additions to LTC, namely access to LTC
3333 mathlib. For example, public key crypto requires
3434 a mathlib; hashing and symmetric encryption do not.
3535
36- This code was written for Python 2.7 with the ctypes standard
37- library.
36+ ------
37+
38+ This code was originally written for Python 2.7 with the
39+ ctypes standard library. This version is modified to run
40+ under both Python 2.7 and 3.6.
41+
42+ Arguably the biggest change for Python3 has to do with
43+ strings. Under Python2, native strings are ASCII bytes and
44+ passing them to LTC is natural and requires no conversion.
45+ Under Python3 all native strings are Unicode which requires
46+ they be converted to bytes before use by LTC.
47+
48+ Note the following for Python3.
49+ - ASCII keys, IVs and other string arguments must be
50+ 'bytes'. Define them with a 'b' prefix or convert
51+ via the 'bytes()' function.
52+ - "strings" returned from LTC are bytes and conversion
53+ to Unicode might be necessary for proper printing.
54+ If so, use <string>.decode('utf-8').
55+ - The Python2 'print' statement becomes a function in
56+ Python3 which requires parenthesis, eg. 'print()'.
57+
58+ NB: Unicode is achieved under Python2 by either defining
59+ a Unicode string with a 'u' prefix or passing ASCII
60+ strings thru the 'unicode()' function.
3861
3962 Larry Bugbee
4063 March 2014 v1
4366"""
4467
4568
69+ import sys
4670from ctypes import *
4771from ctypes .util import find_library
4872
5579SHOW_SHA256_EXAMPLE = True
5680SHOW_CHACHA_EXAMPLE = True
5781
58- print
82+ print ( ' ' )
5983print (' demo_dynamic.py' )
6084
85+ def inprint (s , indent = 0 ):
86+ "prints strings indented, including multline strings"
87+ for line in s .split ('\n ' ):
88+ print (' ' * indent + line )
6189
6290#-------------------------------------------------------------------------------
6391# load the .dylib
6492
6593libname = 'tomcrypt'
6694libpath = find_library (libname )
67- print
95+ print ( ' ' )
6896print (' path to library %s: %s' % (libname , libpath ))
6997
7098LTC = cdll .LoadLibrary (libpath )
7199print (' loaded: %s' % LTC )
72- print
100+ print ( ' ' )
73101
74102
75103#-------------------------------------------------------------------------------
78106# and used as needed.
79107
80108if SHOW_ALL_CONSTANTS :
81- print '-' * 60
82- print ' all supported constants and their values:'
109+ print ( '-' * 60 )
110+ print ( ' all supported constants and their values:' )
83111
84112 # get size to allocate for constants output list
85113 str_len = c_int (0 )
86114 ret = LTC .crypt_list_all_constants (None , byref (str_len ))
87- print ' need to allocate %d bytes to build list \n ' % str_len .value
115+ print ( ' need to allocate %d bytes to build list \n ' % str_len .value )
88116
89117 # allocate that size and get (name, size) pairs, each pair
90118 # separated by a newline char.
91119 names_sizes = c_buffer (str_len .value )
92120 ret = LTC .crypt_list_all_constants (names_sizes , byref (str_len ))
93- print names_sizes .value
94- print
121+ print ( names_sizes .value . decode ( "utf-8" ))
122+ print ( ' ' )
95123
96124
97125if SHOW_ALL_SIZES :
98- print '-' * 60
99- print ' all supported sizes:'
126+ print ( '-' * 60 )
127+ print ( ' all supported sizes:' )
100128
101129 # get size to allocate for sizes output list
102130 str_len = c_int (0 )
103131 ret = LTC .crypt_list_all_sizes (None , byref (str_len ))
104- print ' need to allocate %d bytes to build list \n ' % str_len .value
132+ print ( ' need to allocate %d bytes to build list \n ' % str_len .value )
105133
106134 # allocate that size and get (name, size) pairs, each pair
107135 # separated by a newline char.
108136 names_sizes = c_buffer (str_len .value )
109137 ret = LTC .crypt_list_all_sizes (names_sizes , byref (str_len ))
110- print names_sizes .value
111- print
138+ print ( names_sizes .value . decode ( "utf-8" ))
139+ print ( ' ' )
112140
113141
114142#-------------------------------------------------------------------------------
115143# get individually named constants and sizes
116144
117145if SHOW_SELECTED_CONSTANTS :
118- print '-' * 60
119- print '\n selected constants:'
146+ print ( '-' * 60 )
147+ print ( '\n selected constants:' )
120148
121149 names = [
122- 'ENDIAN_LITTLE' ,
123- 'ENDIAN_64BITWORD' ,
124- 'PK_PUBLIC' ,
125- 'MAX_RSA_SIZE' ,
126- 'CTR_COUNTER_BIG_ENDIAN' ,
150+ b 'ENDIAN_LITTLE' ,
151+ b 'ENDIAN_64BITWORD' ,
152+ b 'PK_PUBLIC' ,
153+ b 'MAX_RSA_SIZE' ,
154+ b 'CTR_COUNTER_BIG_ENDIAN' ,
127155 ]
128156 for name in names :
129157 const_value = c_int (0 )
130158 rc = LTC .crypt_get_constant (name , byref (const_value ))
131159 value = const_value .value
132- print ' %-25s %d' % (name , value )
133- print
160+ print ( ' %-25s %d' % (name . decode ( "utf-8" ) , value ) )
161+ print ( ' ' )
134162
135163if SHOW_SELECTED_SIZES :
136- print '-' * 60
137- print '\n selected sizes:'
164+ print ( '-' * 60 )
165+ print ( '\n selected sizes:' )
138166
139167 names = [
140- 'rijndael_key' ,
141- 'rsa_key' ,
142- 'symmetric_CTR' ,
143- 'twofish_key' ,
144- 'ecc_point' ,
145- 'gcm_state' ,
146- 'sha512_state' ,
168+ b 'rijndael_key' ,
169+ b 'rsa_key' ,
170+ b 'symmetric_CTR' ,
171+ b 'twofish_key' ,
172+ b 'ecc_point' ,
173+ b 'gcm_state' ,
174+ b 'sha512_state' ,
147175 ]
148176 for name in names :
149177 size_value = c_int (0 )
150178 rc = LTC .crypt_get_size (name , byref (size_value ))
151179 value = size_value .value
152- print ' %-25s %d' % (name , value )
153- print
180+ print ( ' %-25s %d' % (name . decode ( "utf-8" ) , value ) )
181+ print ( ' ' )
154182
155183
156184#-------------------------------------------------------------------------------
163191# nm /usr/local/lib/libtomcrypt.dylib | grep " D "
164192
165193def get_named_string (lib , name ):
166- return c_char_p .in_dll (lib , name ).value
194+ return c_char_p .in_dll (lib , name ).value . decode ( "utf-8" )
167195
168196if SHOW_BUILD_OPTIONS_ALGS :
169- print '-' * 60
170- print 'This is a string compiled into LTC showing compile '
171- print 'options and algorithms supported by this build \n '
172- print get_named_string (LTC , 'crypt_build_settings' )
197+ print ('-' * 60 )
198+ print ('This is a string compiled into LTC showing compile' )
199+ print ('options and algorithms supported by this build \n ' )
200+ # print(get_named_string(LTC, 'crypt_build_settings'))
201+ inprint (get_named_string (LTC , 'crypt_build_settings' ), 4 )
173202
174203
175204#-------------------------------------------------------------------------------
@@ -180,32 +209,34 @@ def get_named_string(lib, name):
180209# - - - - - - - - - - - - -
181210# definitions
182211
212+ from binascii import hexlify , unhexlify
213+
214+ def _err2str (err ):
215+ # define return type
216+ errstr = LTC .error_to_string
217+ errstr .restype = c_char_p
218+ # get and return err string
219+ return errstr (err )
220+
183221def _get_size (name ):
184222 size = c_int (0 )
185- rc = LTC .crypt_get_size (name , byref (size ))
223+ rc = LTC .crypt_get_size (bytes ( name ) , byref (size ))
186224 if rc != 0 :
187225 raise Exception ('LTC.crypt_get_size(%s) rc = %d' % (name , rc ))
188226 return size .value
189227
190228def _get_constant (name ):
191229 constant = c_int (0 )
192- rc = LTC .crypt_get_constant (name , byref (constant ))
230+ rc = LTC .crypt_get_constant (bytes ( name ) , byref (constant ))
193231 if rc != 0 :
194232 raise Exception ('LTC.crypt_get_constant(%s) rc = %d' % (name , rc ))
195233 return constant .value
196234
197- def _err2str (err ):
198- # define return type
199- errstr = LTC .error_to_string
200- errstr .restype = c_char_p
201- # get and return err string
202- return errstr (err )
203-
204- CRYPT_OK = _get_constant ('CRYPT_OK' )
235+ CRYPT_OK = _get_constant (b'CRYPT_OK' )
205236
206237class SHA256 (object ):
207238 def __init__ (self ):
208- self .state = c_buffer (_get_size ('sha256_state' ))
239+ self .state = c_buffer (_get_size (b 'sha256_state' ))
209240 LTC .sha256_init (byref (self .state ))
210241 def update (self , data ):
211242 LTC .sha256_process (byref (self .state ), data , len (data ))
@@ -216,7 +247,7 @@ def digest(self):
216247
217248class ChaCha (object ):
218249 def __init__ (self , key , rounds ):
219- self .state = c_buffer (_get_size ('chacha_state' ))
250+ self .state = c_buffer (_get_size (b 'chacha_state' ))
220251 self .counter = c_int (1 )
221252 err = LTC .chacha_setup (byref (self .state ), key , len (key ), rounds )
222253 if err != CRYPT_OK :
@@ -235,42 +266,39 @@ def crypt(self, datain):
235266# - - - - - - - - - - - - -
236267# a SHA256 app fragment
237268
238- # from wrapper import * # uncomment in real life
239-
240269if SHOW_SHA256_EXAMPLE :
241- print '-' * 60
242- data = 'hello world'
270+ print ( '-' * 60 )
271+ data = b 'hello world' # we want bytes, not Unicode
243272
244273 sha256 = SHA256 ()
245274 sha256 .update (data )
246275 md = sha256 .digest ()
247276
248277 template = '\n the SHA256 digest for "%s" is %s \n '
249- print template % (data , md . encode ( 'hex' ))
278+ print ( template % (data , hexlify ( md ) ))
250279
251280# - - - - - - - - - - - - -
252281# a ChaCha app fragment
253282
254283if SHOW_CHACHA_EXAMPLE :
255- print '-' * 60
256- key = 'hownowbrowncow\x00 \x00 ' # exactly 16 or 32 bytes
284+ print ( '-' * 60 )
285+ key = b 'hownowbrowncow\x00 \x00 ' # exactly 16 or 32 bytes
257286 rounds = 12 # common values: 8, 12, 20
258- iv = '123456789012' # exactly 12 bytes
259- plain = 'Kilroy was here, there, and everywhere!'
287+ iv = b '123456789012' # exactly 12 bytes
288+ plain = b 'Kilroy was here, there, and everywhere!'
260289
261290 cha = ChaCha (key , rounds )
262291 cha .set_iv32 (iv )
263292 cipher = cha .crypt (plain )
264293
265294 template = '\n ChaCha%d ciphertext for "%s" is "%s"'
266- print template % (rounds , plain , cipher . encode ( 'hex' ))
295+ print ( template % (rounds , plain , hexlify ( cipher ) ))
267296
268- # reset to decrypt
269- cha .set_iv32 (iv )
297+ cha .set_iv32 (iv ) # reset to decrypt
270298 decrypted = cha .crypt (cipher )
271299
272300 template = ' ChaCha%d decoded text for "%s" is "%s" \n '
273- print template % (rounds , plain , decrypted )
301+ print ( template % (rounds , plain , decrypted . decode ( "utf-8" )) )
274302
275303# Footnote: Keys should be erased fm memory as soon as possible after use,
276304# and that includes Python. For a tip on how to do that in Python, see
0 commit comments