Source

jaraco.crypto / ctypescrypto / evp.py

import itertools
from ctypes import *

from .support import find_library

MAX_MD_SIZE = 64

_digest_type_fields = [
	('type', c_int),
	('pkey_type', c_int),
	('md_size', c_int),
	('flags', c_ulong),
	('init', c_void_p),
	('update', c_void_p),
	('final', c_void_p),
	('copy', c_void_p),
	('cleanup', c_void_p),
	('sign', c_void_p),
	('verify', c_void_p),
	('required_pkey_type', c_int*5),
	('block size', c_int),
	('ctx_size', c_int),
	('md_ctrl', c_void_p),
]

_digest_context_fields = [
	('p_type', c_void_p), # POINTER(DigestType)
	('engine', c_void_p), # todo, POINTER(ENGINE)
	('flags', c_ulong),
	('md_data', c_void_p),
	('pctx', c_void_p), # todo, POINTER(EVP_PKEY_CTX)
	('update_func', c_void_p),
]

def _reg(name):
	"""
	Copy the function by the given name from the EVP library into this
	namespace.
	"""
	libname = 'EVP_' + name
	globals()[name] = getattr(lib, libname)

lib = find_library('libeay32')
## Define the argtypes and result types for the EVP functions
map(_reg, 'get_digestbyname DigestInit DigestInit_ex MD_CTX_init '
	'MD_CTX_create DigestUpdate DigestFinal_ex'.split())

def _set_digest_arg_types(DigestType, Digest):
	get_digestbyname.argtypes = c_char_p,
	get_digestbyname.restype = POINTER(DigestType)
	DigestInit.argtypes = (
		POINTER(Digest), POINTER(DigestType),
		)
	DigestInit_ex.argtypes = lib.EVP_DigestInit.argtypes + (c_void_p,)
	DigestInit_ex.restype = c_int
	MD_CTX_init.argtypes = POINTER(Digest),
	MD_CTX_create.restype = POINTER(Digest)
	DigestUpdate.argtypes = POINTER(Digest), c_char_p, c_int
	DigestUpdate.restype = c_int
	DigestFinal_ex.argtypes = (POINTER(Digest),
		c_char_p, POINTER(c_uint),
		)
	DigestFinal_ex.restype = c_int

_reg('get_cipherbyname')
get_cipherbyname.argtypes = c_char_p,

_cipher_fields = [
	('nid', c_int),
	('block_size', c_int),
	('key_len', c_int),
	('iv_len', c_int),
	('flags', c_ulong),
	('init', c_void_p),
	('do_cipher', c_void_p),
	('cleanup', c_void_p),
	('ctx_size', c_int),
	('set_asn1_parameters', c_void_p),
	('get_asn1_parameters', c_void_p),
	('ctrl', c_void_p),
	('app_data', c_void_p),
]

MAX_IV_LENGTH = 16
MAX_BLOCK_LENGTH = 32
MAX_KEY_LENGTH = 32

_cipher_context_fields = [
	('cipher', c_void_p), # POINTER(CipherType)
	('engine', c_void_p), # POINTER(ENGINE)
	('encrypt', c_int),
	('buf_len', c_int),
	('oiv', c_char*MAX_IV_LENGTH),
	('iv', c_char*MAX_IV_LENGTH),
	('buf', c_char*MAX_BLOCK_LENGTH),
	('num', c_int),
	('app_data', c_void_p),
	('key_len', c_int),
	('flags', c_ulong),
	('cipher_data', c_void_p),
	('final_used', c_int),
	('block_mask', c_int),
	('final', c_char*MAX_BLOCK_LENGTH),
]

CIPHER_CTX_init = lib.EVP_CIPHER_CTX_init

#EncryptInit_ex = lib.EVP_EncryptInit_ex
#DecryptInit_ex = lib.EVP_DecryptInit_ex
#...
for ed, method in itertools.product(
	['Encrypt', 'Decrypt', 'Cipher'],
	['Init_ex', 'Update', 'Final_ex'],
	):
	local_name = ''.join([ed, method])
	lib_name = ''.join(['EVP_', ed, method])
	func = getattr(lib, lib_name)
	func.restype = c_int
	globals()[local_name] = func

## Initialize the engines
lib.OpenSSL_add_all_digests()
lib.OpenSSL_add_all_ciphers()