demo_dynamic.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. """
  2. demo_dynamic.py v1
  3. This program demonstrates Python's use of the dynamic
  4. language support additions to LTC, namely access to LTC
  5. constants, struct and union sizes, and the binding of a
  6. math package to LTC. Also provided are simple code
  7. fragments to illustrate how one might write a Python
  8. wrapper for LTC and how an app might call the wrapper.
  9. This or a similar model should work for Ruby and other
  10. dynamic languages.
  11. This instance uses Python's ctypes and requires a single
  12. .dylib linking together LTC and one or more math libraries.
  13. Building a single .dylib is needed because LTC wants a
  14. fairly tight relationship between itself and the mathlib.
  15. (ctypes can load multiple .dylibs, but it does not support
  16. this level of coupling between those independent libraries.)
  17. My .dylib was created on OSX with the following steps:
  18. 1- compile LTC to a .a static lib:
  19. CFLAGS="-DLTM_DESC -DUSE_LTM -DTFM_DESC -DUSE_TFM \
  20. -I/usr/local/include" make
  21. 2- link LTC, LTM and TFM into a single .dylib:
  22. ar2dylib_with_and tomcrypt tommath tfm
  23. where ar2dylib_with_and is a shell script that combines
  24. the .a with .dylibs for LTM and TFM
  25. Reminder: you don't need to bind in a math library unless
  26. you are going to use LTC functions that depend
  27. on a mathlib. For example, public key crypto
  28. needs a mathlib; hashing and symmetric encryption
  29. does not.
  30. Larry Bugbee
  31. March 2014
  32. """
  33. from ctypes import *
  34. from ctypes.util import find_library
  35. #---------------------------------------------------------------
  36. # load the .dylib
  37. libname = 'tomcrypt'
  38. libpath = find_library(libname)
  39. print
  40. print(' demo_dynamic.py')
  41. print
  42. print(' path to library %s: %s' % (libname, libpath))
  43. LTC = cdll.LoadLibrary(libpath)
  44. print(' loaded: %s' % LTC)
  45. print
  46. #---------------------------------------------------------------
  47. # get list of all supported constants followed by a list of all
  48. # supported sizes. One alternative: these lists may be parsed
  49. # and used as needed.
  50. if 1:
  51. print ' all supported constants and their values:'
  52. # get size to allocate for constants output list
  53. str_len = c_int(0)
  54. ret = LTC.crypt_list_all_constants(None, byref(str_len))
  55. print ' need to allocate %d bytes \n' % str_len.value
  56. # allocate that size and get (name, size) pairs, each pair
  57. # separated by a newline char.
  58. names_sizes = c_buffer(str_len.value)
  59. ret = LTC.crypt_list_all_constants(names_sizes, byref(str_len))
  60. print names_sizes.value
  61. print
  62. if 1:
  63. print ' all supported sizes:'
  64. # get size to allocate for sizes output list
  65. str_len = c_int(0)
  66. ret = LTC.crypt_list_all_sizes(None, byref(str_len))
  67. print ' need to allocate %d bytes \n' % str_len.value
  68. # allocate that size and get (name, size) pairs, each pair
  69. # separated by a newline char.
  70. names_sizes = c_buffer(str_len.value)
  71. ret = LTC.crypt_list_all_sizes(names_sizes, byref(str_len))
  72. print names_sizes.value
  73. print
  74. #---------------------------------------------------------------
  75. # get individually named constants and sizes
  76. # print selected constants
  77. if 1:
  78. print '\n selected constants:'
  79. names = [
  80. 'PK_PUBLIC',
  81. 'MAX_RSA_SIZE',
  82. 'CTR_COUNTER_BIG_ENDIAN',
  83. ]
  84. for name in names:
  85. const_value = c_int(0)
  86. rc = LTC.crypt_get_constant(name, byref(const_value))
  87. value = const_value.value
  88. print ' %-25s %d' % (name, value)
  89. # print selected sizes
  90. if 1:
  91. print '\n selected sizes:'
  92. names = [
  93. 'rijndael_key_struct_size',
  94. 'rsa_key_struct_size',
  95. 'symmetric_CTR_struct_size',
  96. 'twofish_key_struct_size',
  97. 'ecc_point_struct_size',
  98. 'gcm_state_struct_size',
  99. 'sha512_state_struct_size',
  100. ]
  101. for name in names:
  102. size_value = c_int(0)
  103. rc = LTC.crypt_get_size(name, byref(size_value))
  104. value = size_value.value
  105. print ' %-25s %d' % (name, value)
  106. #---------------------------------------------------------------
  107. # init the selected math package, change to another mathlib,
  108. # and change back to the first mathlib
  109. if 1:
  110. print '\n init the selected math package, change, and change again'
  111. # show ltm_desc
  112. ptr = c_int.in_dll(LTC, 'ltm_desc')
  113. print ' ltm_desc: ', hex(ptr.value)
  114. # show tfm_desc
  115. ptr = c_int.in_dll(LTC, 'tfm_desc')
  116. print ' tfm_desc: ', hex(ptr.value)
  117. # let's see the initial value of ltc_mp
  118. ptr = c_int.in_dll(LTC, 'ltc_mp')
  119. print ' initial ptr:', hex(ptr.value)
  120. # init LTM and show ltc_mp
  121. LTC.init_LTM()
  122. ptr = c_int.in_dll(LTC, 'ltc_mp')
  123. print ' ptr to LTM: ', hex(ptr.value)
  124. # init TFM and show ltc_mp
  125. LTC.init_TFM()
  126. ptr = c_int.in_dll(LTC, 'ltc_mp')
  127. print ' ptr to TFM: ', hex(ptr.value)
  128. # now change back to LTM
  129. LTC.init_LTM()
  130. ptr = c_int.in_dll(LTC, 'ltc_mp')
  131. print ' ptr to LTM: ', hex(ptr.value)
  132. #---------------------------------------------------------------
  133. #---------------------------------------------------------------
  134. # ctypes getting a list of this build's supported algorithms
  135. # and compiler switches
  136. def get_named_string(lib, name):
  137. return c_char_p.in_dll(lib, name).value
  138. if 0:
  139. print '\n%s' % ('-'*60)
  140. print 'This is a string compiled into LTC showing compile '
  141. print 'options and algorithms supported by this build \n'
  142. print get_named_string(LTC, 'crypt_build_settings')
  143. print
  144. #---------------------------------------------------------------
  145. #---------------------------------------------------------------
  146. # here is an example of how a wrapper can make Python access
  147. # more Pythonic
  148. # - - - - - - - - - - - - -
  149. # a wrapper fragment...
  150. def _get_size(name):
  151. size = c_int(0)
  152. rc = LTC.crypt_get_size(name, byref(size))
  153. return size.value
  154. sha256_state_struct_size = _get_size('sha256_state_struct_size')
  155. sha512_state_struct_size = _get_size('sha512_state_struct_size')
  156. class SHA256(object):
  157. def __init__(self):
  158. self.state = c_buffer(sha256_state_struct_size)
  159. LTC.sha256_init(byref(self.state))
  160. def update(self, data):
  161. LTC.sha256_process(byref(self.state), data, len(data))
  162. def digest(self):
  163. md = c_buffer(32)
  164. LTC.sha256_done(byref(self.state), byref(md))
  165. return md.raw
  166. # - - - - - - - - - - - - -
  167. # an app fragment...
  168. # from wrapper import * # uncomment in real life
  169. data = 'hello world'
  170. sha256 = SHA256()
  171. sha256.update(data)
  172. md = sha256.digest()
  173. template = '\n\n the SHA256 digest for "%s" is %s \n'
  174. print template % (data, md.encode('hex'))
  175. #---------------------------------------------------------------
  176. #---------------------------------------------------------------
  177. #---------------------------------------------------------------