#!/usr/bin/env python """ Python wrapper of the botan crypto library http://botan.randombit.net (C) 2015 Jack Lloyd (C) 2015 Uri Blumenthal (extensions and patches) Botan is released under the Simplified BSD License (see license.txt) """ import sys from ctypes import * from binascii import hexlify, unhexlify """ Module initialization """ if sys.platform == 'darwin': botan = CDLL('libbotan-1.11.dylib') else: botan = CDLL('libbotan-1.11.so') expected_api_rev = 20150210 botan_api_rev = botan.botan_ffi_api_version() if botan_api_rev != expected_api_rev: raise Exception("Bad botan API rev got %d expected %d" % (botan_api_rev, expected_api_rev)) """ Versions """ def version_major(): return botan.botan_version_major() def version_minor(): return botan.botan_version_minor() def version_patch(): return botan.botan_version_patch() def version_string(): botan.botan_version_string.restype = c_char_p return botan.botan_version_string() """ RNG """ class rng(object): # Can also use type "system" def __init__(self, rng_type = 'system'): botan.botan_rng_init.argtypes = [c_void_p, c_char_p] self.rng = c_void_p(0) if sys.version_info[0] < 3: rc = botan.botan_rng_init(byref(self.rng), rng_type) else: rc = botan.botan_rng_init(byref(self.rng), rng_type.encode('ascii')) if rc != 0 or self.rng is None: raise Exception("No rng " + algo + " for you!") def __del__(self): botan.botan_rng_destroy.argtypes = [c_void_p] botan.botan_rng_destroy(self.rng) def reseed(self, bits = 256): botan.botan_rng_reseed.argtypes = [c_void_p, c_size_t] botan.botan_rng_reseed(self.rng, bits) def get(self, length): botan.botan_rng_get.argtypes = [c_void_p, POINTER(c_char), c_size_t] out = create_string_buffer(length) l = c_size_t(length) rc = botan.botan_rng_get(self.rng, out, l) if sys.version_info[0] < 3: return str(out.raw) else: return out.raw """ Hash function """ class hash_function(object): def __init__(self, algo): botan.botan_hash_init.argtypes = [c_void_p, c_char_p, c_uint32] flags = c_uint32(0) # always zero in this API version self.hash = c_void_p(0) if sys.version_info[0] < 3: rc = botan.botan_hash_init(byref(self.hash), algo, flags) else: rc = botan.botan_hash_init(byref(self.hash), algo.encode('utf-8'), flags) if rc != 0 or self.hash is None: raise Exception("No hash " + algo + " for you!") def __del__(self): botan.botan_hash_destroy.argtypes = [c_void_p] botan.botan_hash_destroy(self.hash) def clear(self): botan.botan_hash_clear.argtypes = [c_void_p] return botan.botan_hash_clear(self.hash) def output_length(self): botan.botan_hash_output_length.argtypes = [c_void_p,POINTER(c_size_t)] l = c_size_t(0) rc = botan.botan_hash_output_length(self.hash, byref(l)) return l.value def update(self, x): botan.botan_hash_update.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_hash_update(self.hash, x, len(x)) def final(self): botan.botan_hash_final.argtypes = [c_void_p, POINTER(c_char)] out = create_string_buffer(self.output_length()) botan.botan_hash_final(self.hash, out) if sys.version_info[0] < 3: return str(out.raw) else: return out.raw """ Message authentication codes """ class message_authentication_code(object): def __init__(self, algo): botan.botan_mac_init.argtypes = [c_void_p, c_char_p, c_uint32] flags = c_uint32(0) # always zero in this API version self.mac = c_void_p(0) rc = botan.botan_mac_init(byref(self.mac), algo, flags) if rc != 0 or self.mac is None: raise Exception("No mac " + algo + " for you!") def __del__(self): botan.botan_mac_destroy.argtypes = [c_void_p] botan.botan_mac_destroy(self.mac) def clear(self): botan.botan_mac_clear.argtypes = [c_void_p] return botan.botan_mac_clear(self.mac) def output_length(self): botan.botan_mac_output_length.argtypes = [c_void_p, POINTER(c_size_t)] l = c_size_t(0) rc = botan.botan_mac_output_length(self.mac, byref(l)) return l.value def set_key(self, key): botan.botan_mac_set_key.argtypes = [c_void_p, POINTER(c_char), c_size_t] return botan.botan_mac_set_key(self.mac, key, len(key)) def update(self, x): botan.botan_mac_update.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_mac_update(self.mac, x, len(x)) def final(self): botan.botan_mac_final.argtypes = [c_void_p, POINTER(c_char)] out = create_string_buffer(self.output_length()) botan.botan_mac_final(self.mac, out) if sys.version_info[0] < 3: return str(out.raw) else: return out.raw class cipher(object): def __init__(self, algo, encrypt = True): botan.botan_cipher_init.argtypes = [c_void_p,c_char_p, c_uint32] flags = 0 if encrypt else 1 self.cipher = c_void_p(0) if sys.version_info[0] < 3: rc = botan.botan_cipher_init(byref(self.cipher), algo, flags) else: rc = botan.botan_cipher_init(byref(self.cipher), algo.encode('utf-8'), flags) if rc != 0 or self.cipher is None: raise Exception("No cipher " + algo + " for you!") def __del__(self): botan.botan_cipher_destroy.argtypes = [c_void_p] botan.botan_cipher_destroy(self.cipher) def default_nonce_length(self): botan.botan_cipher_get_default_nonce_length.argtypes = [c_void_p, POINTER(c_size_t)] l = c_size_t(0) botan.botan_cipher_get_default_nonce_length(self.cipher, byref(l)) return l.value def update_granularity(self): botan.botan_cipher_get_update_granularity.argtypes = [c_void_p, POINTER(c_size_t)] l = c_size_t(0) botan.botan_cipher_get_update_granularity(self.cipher, byref(l)) return l.value def tag_length(self): botan.botan_cipher_get_tag_length.argtypes = [c_void_p, POINTER(c_size_t)] l = c_size_t(0) botan.botan_cipher_get_tag_length(self.cipher, byref(l)) return l.value def is_authenticated(self): return self.tag_length() > 0 def valid_nonce_length(self, nonce_len): botan.botan_cipher_valid_nonce_length.argtypes = [c_void_p, c_size_t] rc = botan.botan_cipher_valid_nonce_length(self.cipher, nonce_len) if rc < 0: raise Exception('Error calling valid_nonce_length') return True if rc == 1 else False def clear(self): botan.botan_cipher_clear.argtypes = [c_void_p] botan.botan_cipher_clear(self.cipher) def set_key(self, key): botan.botan_cipher_set_key.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_cipher_set_key(self.cipher, key, len(key)) def set_assoc_data(self, ad): botan.botan_cipher_set_associated_data.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_cipher_set_associated_data(self.cipher, ad, len(ad)) def start(self, nonce): botan.botan_cipher_start.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_cipher_start(self.cipher, nonce, len(nonce)) def _update(self, txt, final): botan.botan_cipher_update.argtypes = [c_void_p, c_uint32, POINTER(c_char), c_size_t, POINTER(c_size_t), POINTER(c_char), c_size_t, POINTER(c_size_t)] inp = txt if txt else '' inp_sz = c_size_t(len(inp)) if sys.version_info[0] >= 3: inp = cast(inp, c_char_p) inp_consumed = c_size_t(0) out = create_string_buffer(inp_sz.value + (self.tag_length() if final else 0)) out_sz = c_size_t(len(out)) out_written = c_size_t(0) flags = c_uint32(1 if final else 0) botan.botan_cipher_update(self.cipher, flags, out, out_sz, byref(out_written), inp, inp_sz, byref(inp_consumed)) # buffering not supported yet assert inp_consumed.value == inp_sz.value return out.raw[0:out_written.value] def update(self, txt): return self._update(txt, False) def finish(self, txt = None): return self._update(txt, True) """ Bcrypt TODO: might not be enabled - handle that gracefully! """ def bcrypt(passwd, rng, work_factor = 10): botan.botan_bcrypt_generate.argtypes = [POINTER(c_char), POINTER(c_size_t), c_char_p, c_void_p, c_size_t, c_uint32] out_len = c_size_t(64) out = create_string_buffer(out_len.value) flags = c_uint32(0) rc = botan.botan_bcrypt_generate(out, byref(out_len), passwd, rng.rng, c_size_t(work_factor), flags) if rc != 0: raise Exception('botan bcrypt failed, error %s' % (rc)) b = out.raw[0:out_len.value] if b[-1] == '\x00': b = b[:-1] return b def check_bcrypt(passwd, bcrypt): rc = botan.botan_bcrypt_is_valid(passwd, bcrypt) return (rc == 0) """ PBKDF """ def pbkdf(algo, password, out_len, iterations = 10000, salt = rng().get(12)): botan.botan_pbkdf.argtypes = [c_char_p, POINTER(c_char), c_size_t, c_char_p, c_void_p, c_size_t, c_size_t] out_buf = create_string_buffer(out_len) botan.botan_pbkdf(algo, out_buf, out_len, password, salt, len(salt), iterations) return (salt,iterations,out_buf.raw) def pbkdf_timed(algo, password, out_len, ms_to_run = 300, salt = rng().get(12)): botan.botan_pbkdf_timed.argtypes = [c_char_p, POINTER(c_char), c_size_t, c_char_p, c_void_p, c_size_t, c_size_t, POINTER(c_size_t)] out_buf = create_string_buffer(out_len) iterations = c_size_t(0) botan.botan_pbkdf_timed(algo, out_buf, out_len, password, salt, len(salt), ms_to_run, byref(iterations)) return (salt,iterations.value,out_buf.raw) """ KDF """ def kdf(algo, secret, out_len, salt): botan.botan_kdf.argtypes = [c_char_p, POINTER(c_char), c_size_t, POINTER(c_char), c_size_t, POINTER(c_char), c_size_t] out_buf = create_string_buffer(out_len) out_sz = c_size_t(out_len) botan.botan_kdf(algo, out_buf, out_sz, secret, len(secret), salt, len(salt)) return out_buf.raw[0:out_sz.value] """ Public and private keys """ class public_key(object): def __init__(self, obj = c_void_p(0)): self.pubkey = obj def __del__(self): botan.botan_pubkey_destroy.argtypes = [c_void_p] botan.botan_pubkey_destroy(self.pubkey) def estimated_strength(self): botan.botan_pubkey_estimated_strength.argtypes = [c_void_p, POINTER(c_size_t)] r = c_size_t(0) botan.botan_pubkey_estimated_strength(self.pubkey, byref(r)) return r.value def algo_name(self): botan.botan_pubkey_algo_name.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] buf = create_string_buffer(64) buf_len = c_size_t(len(buf)) botan.botan_pubkey_algo_name(self.pubkey, buf, byref(buf_len)) assert buf_len.value <= len(buf) return buf.raw[0:buf_len.value] def fingerprint(self, hash = 'SHA-256'): botan.botan_pubkey_fingerprint.argtypes = [c_void_p, c_char_p, POINTER(c_char), POINTER(c_size_t)] n = hash_function(hash).output_length() buf = create_string_buffer(n) buf_len = c_size_t(n) if sys.version_info[0] > 2: hash = hash.encode('utf-8') botan.botan_pubkey_fingerprint(self.pubkey, hash, buf, byref(buf_len)) return hexlify(buf[0:buf_len.value]) class private_key(object): def __init__(self, alg, param, rng): botan.botan_privkey_create_rsa.argtypes = [c_void_p, c_void_p, c_size_t] botan.botan_privkey_create_ecdsa.argtypes = [c_void_p, c_void_p, c_char_p] botan.botan_privkey_create_ecdh.argtypes = [c_void_p, c_void_p, c_char_p] self.privkey = c_void_p(0) if alg == 'rsa': botan.botan_privkey_create_rsa(byref(self.privkey), rng.rng, param) elif alg == 'ecdsa': botan.botan_privkey_create_ecdsa(byref(self.privkey), rng.rng, param) elif alg == 'ecdh': botan.botan_privkey_create_ecdh(byref(self.privkey), rng.rng, param) else: raise Exception('Unknown public key algo ' + alg) if self.privkey is None: raise Exception('Error creating ' + alg + ' key') def __del__(self): botan.botan_privkey_destroy.argtypes = [c_void_p] botan.botan_privkey_destroy(self.privkey) def get_public_key(self): botan.botan_privkey_export_pubkey.argtypes = [c_void_p, c_void_p] pub = c_void_p(0) botan.botan_privkey_export_pubkey(byref(pub), self.privkey) return public_key(pub) def export(self): botan.botan_privkey_export.argtypes = [c_void_p,POINTER(c_char),c_void_p] n = 4096 buf = create_string_buffer(n) buf_len = c_size_t(n) rc = botan.botan_privkey_export(self.privkey, buf, byref(buf_len)) if rc != 0: buf = create_string_buffer(buf_len.value) botan.botan_privkey_export(self.privkey, buf, byref(buf_len)) return buf[0:buf_len.value] class pk_op_encrypt(object): def __init__(self, key, padding): botan.botan_pk_op_encrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] self.op = c_void_p(0) flags = c_uint32(0) # always zero in this ABI if sys.version_info[0] > 2: padding = cast(padding, c_char_p) botan.botan_pk_op_encrypt_create(byref(self.op), key.pubkey, padding, flags) if not self.op: raise Exception("No pk op for you") def __del__(self): botan.botan_pk_op_encrypt_destroy.argtypes = [c_void_p] botan.botan_pk_op_encrypt_destroy(self.op) def encrypt(self, msg, rng): botan.botan_pk_op_encrypt.argtypes = [c_void_p, c_void_p, POINTER(c_char), POINTER(c_size_t), POINTER(c_char), c_size_t] outbuf_sz = c_size_t(4096) #?!?! outbuf = create_string_buffer(outbuf_sz.value) ll = len(msg) #print("encrypt: len=%d" % ll) if sys.version_info[0] > 2: msg = cast(msg, c_char_p) ll = c_size_t(ll) botan.botan_pk_op_encrypt(self.op, rng.rng, outbuf, byref(outbuf_sz), msg, ll) #print("encrypt: outbuf_sz.value=%d" % outbuf_sz.value) return outbuf.raw[0:outbuf_sz.value] class pk_op_decrypt(object): def __init__(self, key, padding): botan.botan_pk_op_decrypt_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] self.op = c_void_p(0) flags = c_uint32(0) # always zero in this ABI if sys.version_info[0] > 2: padding = cast(padding, c_char_p) botan.botan_pk_op_decrypt_create(byref(self.op), key.privkey, padding, flags) if not self.op: raise Exception("No pk op for you") def __del__(self): botan.botan_pk_op_decrypt_destroy.argtypes = [c_void_p] botan.botan_pk_op_decrypt_destroy(self.op) def decrypt(self, msg): botan.botan_pk_op_decrypt.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t), POINTER(c_char), c_size_t] outbuf_sz = c_size_t(4096) #?!?! outbuf = create_string_buffer(outbuf_sz.value) ll = len(msg) if sys.version_info[0] > 2: msg = cast(msg, c_char_p) ll = c_size_t(ll) botan.botan_pk_op_decrypt(self.op, outbuf, byref(outbuf_sz), msg, ll) return outbuf.raw[0:outbuf_sz.value] class pk_op_sign(object): def __init__(self, key, padding): botan.botan_pk_op_sign_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] self.op = c_void_p(0) flags = c_uint32(0) # always zero in this ABI if sys.version_info[0] > 2: padding = cast(padding, c_char_p) botan.botan_pk_op_sign_create(byref(self.op), key.privkey, padding, flags) if not self.op: raise Exception("No pk op for you") def __del__(self): botan.botan_pk_op_sign_destroy.argtypes = [c_void_p] botan.botan_pk_op_sign_destroy(self.op) def update(self, msg): botan.botan_pk_op_sign_update.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_pk_op_sign_update(self.op, msg, len(msg)) def finish(self, rng): botan.botan_pk_op_sign_finish.argtypes = [c_void_p, c_void_p, POINTER(c_char), POINTER(c_size_t)] outbuf_sz = c_size_t(4096) #?!?! outbuf = create_string_buffer(outbuf_sz.value) botan.botan_pk_op_sign_finish(self.op, rng.rng, outbuf, byref(outbuf_sz)) return outbuf.raw[0:outbuf_sz.value] class pk_op_verify(object): def __init__(self, key, padding): botan.botan_pk_op_verify_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] self.op = c_void_p(0) flags = c_uint32(0) # always zero in this ABI botan.botan_pk_op_verify_create(byref(self.op), key.pubkey, padding, flags) if not self.op: raise Exception("No pk op for you") def __del__(self): botan.botan_pk_op_verify_destroy.argtypes = [c_void_p] botan.botan_pk_op_verify_destroy(self.op) def update(self, msg): botan.botan_pk_op_verify_update.argtypes = [c_void_p, POINTER(c_char), c_size_t] botan.botan_pk_op_verify_update(self.op, msg, len(msg)) def check_signature(self, signature): botan.botan_pk_op_verify_finish.argtypes = [c_void_p, POINTER(c_char), c_size_t] rc = botan.botan_pk_op_verify_finish(self.op, signature, len(signature)) if rc == 0: return True return False class pk_op_key_agreement(object): def __init__(self, key, kdf): botan.botan_pk_op_key_agreement_create.argtypes = [c_void_p, c_void_p, c_char_p, c_uint32] botan.botan_pk_op_key_agreement_export_public.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t)] self.op = c_void_p(0) flags = c_uint32(0) # always zero in this ABI botan.botan_pk_op_key_agreement_create(byref(self.op), key.privkey, kdf, flags) if not self.op: raise Exception("No key agreement for you") pub = create_string_buffer(4096) pub_len = c_size_t(len(pub)) botan.botan_pk_op_key_agreement_export_public(key.privkey, pub, byref(pub_len)) self.m_public_value = pub.raw[0:pub_len.value] def __del__(self): botan.botan_pk_op_key_agreement_destroy.argtypes = [c_void_p] botan.botan_pk_op_key_agreement_destroy(self.op) def public_value(self): return self.m_public_value def agree(self, other, key_len, salt): botan.botan_pk_op_key_agreement.argtypes = [c_void_p, POINTER(c_char), POINTER(c_size_t), POINTER(c_char), c_size_t, POINTER(c_char), c_size_t] outbuf_sz = c_size_t(key_len) outbuf = create_string_buffer(outbuf_sz.value) rc = botan.botan_pk_op_key_agreement(self.op, outbuf, byref(outbuf_sz), other, len(other), salt, len(salt)) if rc == -1 and outbuf_sz.value > len(outbuf): outbuf = create_string_buffer(outbuf_sz.value) botan.botan_pk_op_key_agreement(self.op, outbuf, byref(outbuf_sz), other, len(other), salt, len(salt)) return outbuf.raw[0:outbuf_sz.value] """ Tests and examples """ def test(): r = rng("user") print("\n%s" % version_string().decode('utf-8')) print("v%d.%d.%d\n" % (version_major(), version_minor(), version_patch())) print("KDF2(SHA-1) %s" % hexlify(kdf('KDF2(SHA-1)'.encode('ascii'), unhexlify('701F3480DFE95F57941F804B1B2413EF'), 7, unhexlify('55A4E9DD5F4CA2EF82')) ).decode('ascii') ) print("PBKDF2(SHA-1) %s" % hexlify(pbkdf('PBKDF2(SHA-1)'.encode('ascii'), ''.encode('ascii'), 32, 10000, unhexlify('0001020304050607')) [2] ).upper().decode('ascii')) print("good output %s\n" % '59B2B1143B4CB1059EC58D9722FB1C72471E0D85C6F7543BA5228526375B0127') (salt,iterations,psk) = pbkdf_timed('PBKDF2(SHA-256)'.encode('ascii'), 'xyz'.encode('utf-8'), 32, 200) if sys.version_info[0] < 3: print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" % (hexlify(salt), len(salt), iterations) ) else: print("PBKDF2(SHA-256) x=timed, y=iterated; salt = %s (len=%d) #iterations = %d\n" % (hexlify(salt).decode('ascii'), len(salt), iterations) ) print('x %s' % hexlify(psk).decode('utf-8')) print('y %s\n' % (hexlify(pbkdf('PBKDF2(SHA-256)'.encode('utf-8'), 'xyz'.encode('ascii'), 32, iterations, salt)[2]).decode('utf-8'))) hmac = message_authentication_code('HMAC(SHA-256)'.encode('ascii')) hmac.set_key(unhexlify('0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20')) hmac.update(unhexlify('616263')) hmac_output = hmac.final() if hmac_output != unhexlify('A21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181'): print("Bad HMAC:\t%s" % hexlify(bytes(hmac_output, 'utf-8')).decode('utf-8')) print("vs good: \tA21B1F5D4CF4F73A4DD939750F7A066A7F98CC131CB16A6692759021CFAB8181"); else: print("HMAC output (good): %s\n" % hexlify(hmac_output).decode('utf-8')) print("rng output:\n\t%s\n\t%s\n\t%s\n" % (hexlify(r.get(42)).decode('utf-8'), hexlify(r.get(13)).decode('utf-8'), hexlify(r.get(9)).decode('utf-8') ) ) h = hash_function('MD5') assert h.output_length() == 16 h.update('h'.encode('utf-8')) h.update('i'.encode('utf-8')) print("md5 hash: %s\n" % (hexlify(h.final())).decode('utf-8')) gcm = cipher('AES-128/GCM') print("AES-128/GCM: default nonce=%d update_size=%d" % (gcm.default_nonce_length(), gcm.update_granularity())) gcm_dec = cipher('AES-128/GCM', encrypt=False) iv = r.get(12) key = r.get(16) pt = r.get(21) gcm.set_key(key) gcm.start(iv) assert len(gcm.update('')) == 0 ct = gcm.finish(pt) print("GCM ct %s" % hexlify(ct).decode('utf-8')) gcm_dec.set_key(key) gcm_dec.start(iv) dec = gcm_dec.finish(ct) print("GCM pt %s %d" % (hexlify(pt).decode('utf-8'), len(pt))) print("GCM de %s %d\n" % (hexlify(dec).decode('utf-8'), len(dec))) ocb = cipher('AES-128/OCB') print("AES-128/OCB: default nonce=%d update_size=%d" % (ocb.default_nonce_length(), ocb.update_granularity())) ocb_dec = cipher('AES-128/OCB', encrypt=False) iv = r.get(12) key = r.get(16) pt = r.get(21) ocb.set_key(key) ocb.start(iv) assert len(ocb.update('')) == 0 ct = ocb.finish(pt) print("OCB ct %s" % hexlify(ct).decode('utf-8')) ocb_dec.set_key(key) ocb_dec.start(iv) dec = ocb_dec.finish(ct) print("OCB pt %s %d" % (hexlify(pt).decode('utf-8'), len(pt))) print("OCB de %s %d\n" % (hexlify(dec).decode('utf-8'), len(dec))) rsapriv = private_key('rsa', 1536, r) rsapub = rsapriv.get_public_key() print("rsapub %s/SHA-1 fingerprint: %s (estimated strength %s)" % (rsapub.algo_name().decode('utf-8'), rsapub.fingerprint("SHA-1").decode('utf-8'), rsapub.estimated_strength() ) ) dec = pk_op_decrypt(rsapriv, "EME1(SHA-256)".encode('utf-8')) enc = pk_op_encrypt(rsapub, "EME1(SHA-256)".encode('utf-8')) ctext = enc.encrypt('foof'.encode('utf-8'), r) print("ptext \'%s\'" % 'foof') print("ctext \'%s\'" % hexlify(ctext).decode('utf-8')) print("decrypt \'%s\'\n" % dec.decrypt(ctext).decode('utf-8')) signer = pk_op_sign(rsapriv, 'EMSA4(SHA-384)'.encode('utf-8')) signer.update('messa'.encode('utf-8')) signer.update('ge'.encode('utf-8')) sig = signer.finish(r) r.reseed(200) print("EMSA4(SHA-384) signature: %s" % hexlify(sig).decode('utf-8')) verify = pk_op_verify(rsapub, 'EMSA4(SHA-384)'.encode('utf-8')) verify.update('mess'.encode('utf-8')) verify.update('age'.encode('utf-8')) print("good sig accepted? %s" % verify.check_signature(sig)) verify.update('mess of things'.encode('utf-8')) verify.update('age'.encode('utf-8')) print("bad sig accepted? %s" % verify.check_signature(sig)) verify.update('message'.encode('utf-8')) print("good sig accepted? %s\n" % verify.check_signature(sig)) dh_grp = 'secp256r1'.encode('utf-8') #dh_grp = 'curve25519'.encode('utf-8') dh_kdf = 'KDF2(SHA-384)'.encode('utf-8') a_dh_priv = private_key('ecdh', dh_grp, r) a_dh_pub = a_dh_priv.get_public_key() b_dh_priv = private_key('ecdh', dh_grp, r) b_dh_pub = b_dh_priv.get_public_key() a_dh = pk_op_key_agreement(a_dh_priv, dh_kdf) b_dh = pk_op_key_agreement(b_dh_priv, dh_kdf) print("ecdh pubs:\n %s\n %s\n" % (hexlify(a_dh.public_value()).decode('utf-8'), hexlify(b_dh.public_value()).decode('utf-8'))) a_key = a_dh.agree(b_dh.public_value(), 20, 'salt'.encode('utf-8')) b_key = b_dh.agree(a_dh.public_value(), 20, 'salt'.encode('utf-8')) print("ecdh shared:\n %s\n %s\n" % (hexlify(a_key).decode('utf-8'), hexlify(b_key).decode('utf-8'))) #f = open('key.ber','wb') #f.write(blob) #f.close() def main(args = None): if args is None: args = sys.argv test() if __name__ == '__main__': sys.exit(main())