diff options
author | lloyd <[email protected]> | 2015-02-16 20:12:38 +0000 |
---|---|---|
committer | lloyd <[email protected]> | 2015-02-16 20:12:38 +0000 |
commit | 3b9a0c1535e40f8f9fc4cfbc734144ee229df65d (patch) | |
tree | 30c1d4363b4c85561204d26344f40de3e78f6d9d /src/python | |
parent | 85caef829c9eeb7c224ad3b2e3ffbcfe981c2428 (diff) |
Add new module `ffi` which provides a plain C interface, plus a new
ctypes Python wrapper that uses it. The API is intentionally designed
to have a very simple ABI (extern "C", all structs are opaque, no
memory ownership passing the FFI boundary, limited set of simple types
as args) so the ctypes wrapper is quite simple.
Currently ffi provides ciphers, hashes, MACs, RNGs, PBKDF, KDF,
bcrypt, and most public key operations.
Remove the old boost.python wrapper and all the build code for it.
Diffstat (limited to 'src/python')
-rw-r--r-- | src/python/__init__.py | 1 | ||||
-rwxr-xr-x | src/python/botan.py | 517 | ||||
-rw-r--r-- | src/python/core.cpp | 230 | ||||
-rw-r--r-- | src/python/filter.cpp | 177 | ||||
-rw-r--r-- | src/python/python_botan.h | 86 | ||||
-rw-r--r-- | src/python/rsa.cpp | 220 | ||||
-rw-r--r-- | src/python/x509.cpp | 88 |
7 files changed, 517 insertions, 802 deletions
diff --git a/src/python/__init__.py b/src/python/__init__.py deleted file mode 100644 index f98b5a0ec..000000000 --- a/src/python/__init__.py +++ /dev/null @@ -1 +0,0 @@ -from _botan import * diff --git a/src/python/botan.py b/src/python/botan.py new file mode 100755 index 000000000..8414308ec --- /dev/null +++ b/src/python/botan.py @@ -0,0 +1,517 @@ +#!/usr/bin/python + +""" +Python wrapper of the botan crypto library +http://botan.randombit.net + +(C) 2015 Jack Lloyd + +Botan is released under the Simplified BSD License (see license.txt) +""" + +import sys +from ctypes import * + +""" +Module initialization +""" +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 = 'user'): + botan.botan_rng_init.argtypes = [c_void_p, c_char_p] + self.rng = c_void_p(0) + rc = botan.botan_rng_init(byref(self.rng), rng_type) + 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) + return str(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 = 0 # always zero in this API version + self.hash = c_void_p(0) + rc = botan.botan_hash_init(byref(self.hash), algo, 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) + return str(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 = 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.hash 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, k, len(k)) + + 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) + return str(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) + rc = botan.botan_cipher_init(byref(self.cipher), algo, 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 tag_length(self): + botan.botan_cipher_tag_length.argtypes = [c_void_p,POINTER(c_size_t)] + l = c_size_t(0) + botan.botan_cipher_tag_size(self.cipher, byref(l)) + return l.value + + def default_nonce_length(self): + botan.botan_cipher_default_nonce_length.argtypes = [c_void_p, POINTER(c_size_t)] + l = c_size_t(0) + botan.botan_cipher_default_nonce_length(self.cipher, byref(l)) + return l.value + + def update_granularity(self): + botan.botan_cipher_update_granularity.argtypes = [c_void_p, POINTER(c_size_t)] + l = c_size_t(0) + botan.botan_cipher_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 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)) + 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 generate_bcrypt(passwd, rng, work_factor = 10): + botan.botan_bcrypt_generate.argtypes = [POINTER(c_char), c_size_t, c_char_p, c_void_p, c_size_t] + out = create_string_buffer(61) + rc = botan.botan_bcrypt_generate(out, sizeof(out), passwd, rng.rng, c_size_t(work_factor)) + + if rc != 0: + raise Exception('botan bcrypt failed, error %s' % (rc)) + return str(out.raw) + +def check_bcrypt(passwd, bcrypt): + rc = botan.botan_bcrypt_is_valid(passwd, bcrypt) + return (rc == 0) + +""" +PBKDF +""" +def pbkdf(algo, password, out_len, iterations, salt): + 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 out_buf.raw + +def pbkdf_timed(algo, password, out_len, rng, ms_to_run, salt_len = 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) + salt = rng.get(salt_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 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) + botan.botan_pubkey_fingerprint(self.pubkey, hash, buf, byref(buf_len)) + return buf[0:buf_len.value].encode('hex') + +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, rng): + 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 = 0 # always zero in this ABI + 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) + botan.botan_pk_op_encrypt(self.op, rng.rng, outbuf, byref(outbuf_sz), msg, len(msg)) + 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 = 0 # always zero in this ABI + 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) + botan.botan_pk_op_decrypt(self.op, outbuf, byref(outbuf_sz), msg, len(msg)) + 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 = 0 # always zero in this ABI + 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 = 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 + +""" +Tests and examples +""" +def test(): + print version_string() + print version_major(), version_minor(), version_patch() + + + print kdf('KDF2(SHA-1)', '701F3480DFE95F57941F804B1B2413EF'.decode('hex'), 7, '55A4E9DD5F4CA2EF82'.decode('hex')).encode('hex') + + print pbkdf('PBKDF2(SHA-1)', '', 32, 10000, '0001020304050607'.decode('hex')).encode('hex').upper() + print '59B2B1143B4CB1059EC58D9722FB1C72471E0D85C6F7543BA5228526375B0127' + + r = rng("user") + (salt,iterations,psk) = pbkdf_timed('PBKDF2(SHA-256)', 'xyz', 32, r, 200, 12) + print salt.encode('hex'), iterations + print 'x', psk.encode('hex') + print 'y', pbkdf('PBKDF2(SHA-256)', 'xyz', 32, iterations, salt).encode('hex') + + print r.get(42).encode('hex'), r.get(13).encode('hex'), r.get(9).encode('hex') + + h = hash_function('MD5') + assert h.output_length() == 16 + h.update('h') + h.update('i') + print "md5", h.final().encode('hex') + + gcm = cipher('AES-128/GCM') + gcm.set_key('00000000000000000000000000000000'.decode('hex')) + gcm.start('000000000000000000000000'.decode('hex')) + gcm.update('') + gcm.update('') + print 'gcm', gcm.finish('00000000000000000000000000000000'.decode('hex')).encode('hex') + + rsapriv = private_key('rsa', 1536, r) + + dec = pk_op_decrypt(rsapriv, "EME1(SHA-256)") + + rsapub = rsapriv.get_public_key() + print rsapub.fingerprint("SHA-1") + + enc = pk_op_encrypt(rsapub, "EME1(SHA-256)", r) + + ctext = enc.encrypt('foof', r) + print ctext.encode('hex') + print dec.decrypt(ctext) + + signer = pk_op_sign(rsapriv, 'EMSA4(SHA-384)') + + signer.update('mess') + signer.update('age') + sig = signer.finish(r) + + r.reseed(200) + print sig.encode('hex') + + verify = pk_op_verify(rsapub, 'EMSA4(SHA-384)') + + verify.update('mess') + verify.update('age') + print "correct sig accepted?", verify.check_signature(sig) + + verify.update('mess of things') + verify.update('age') + print "bad sig accepted?", verify.check_signature(sig) + + key = private_key('ecdsa', 'secp256r1', r) + blob = key.export() + + #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()) diff --git a/src/python/core.cpp b/src/python/core.cpp deleted file mode 100644 index cb395ee60..000000000 --- a/src/python/core.cpp +++ /dev/null @@ -1,230 +0,0 @@ -/* -* Boost.Python module definition -* (C) 1999-2007 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <botan/pipe.h> -#include <botan/lookup.h> -#include <botan/cryptobox.h> -#include <botan/pbkdf2.h> -#include <botan/hmac.h> -using namespace Botan; - -#include "python_botan.h" - -class Py_Cipher - { - public: - Py_Cipher(std::string algo_name, std::string direction, - std::string key); - - std::string cipher_noiv(const std::string& text); - - std::string cipher(const std::string& text, - const std::string& iv); - - std::string name() const { return algo_name; } - private: - std::string algo_name; - Keyed_Filter* filter; - Pipe pipe; - }; - -std::string Py_Cipher::cipher(const std::string& input, - const std::string& iv_str) - { - if(iv_str.size()) - { - const byte* iv_bytes = reinterpret_cast<const byte*>(iv_str.data()); - u32bit iv_len = iv_str.size(); - filter->set_iv(InitializationVector(iv_bytes, iv_len)); - } - - pipe.process_msg(input); - return pipe.read_all_as_string(Pipe::LAST_MESSAGE); - } - -// For IV-less algorithms -std::string Py_Cipher::cipher_noiv(const std::string& input) - { - pipe.process_msg(input); - return pipe.read_all_as_string(Pipe::LAST_MESSAGE); - } - -Py_Cipher::Py_Cipher(std::string algo_name, - std::string direction, - std::string key_str) - { - const byte* key_bytes = reinterpret_cast<const byte*>(key_str.data()); - u32bit key_len = key_str.size(); - - Cipher_Dir dir; - - if(direction == "encrypt") - dir = ENCRYPTION; - else if(direction == "decrypt") - dir = DECRYPTION; - else - throw std::invalid_argument("Bad cipher direction " + direction); - - filter = get_cipher(algo_name, dir); - filter->set_key(SymmetricKey(key_bytes, key_len)); - pipe.append(filter); - } - -class Py_HashFunction - { - public: - Py_HashFunction(const std::string& algo_name) - { - hash = get_hash(algo_name); - } - - ~Py_HashFunction() { delete hash; } - - void update(const std::string& input) - { - hash->update(input); - } - - std::string final() - { - std::string out(output_length(), 0); - hash->final(reinterpret_cast<byte*>(&out[0])); - return out; - } - - std::string name() const - { - return hash->name(); - } - - u32bit output_length() const - { - return hash->output_length(); - } - - private: - HashFunction* hash; - }; - -class Py_MAC - { - public: - - Py_MAC(const std::string& name, const std::string& key_str) - { - mac = get_mac(name); - - mac->set_key(reinterpret_cast<const byte*>(key_str.data()), - key_str.size()); - } - - ~Py_MAC() { delete mac; } - - u32bit output_length() const { return mac->output_length(); } - - std::string name() const { return mac->name(); } - - void update(const std::string& in) { mac->update(in); } - - std::string final() - { - std::string out(output_length(), 0); - mac->final(reinterpret_cast<byte*>(&out[0])); - return out; - } - private: - MessageAuthenticationCode* mac; - }; - -std::string cryptobox_encrypt(const std::string& in, - const std::string& passphrase, - Python_RandomNumberGenerator& rng) - { - const byte* in_bytes = reinterpret_cast<const byte*>(in.data()); - - return CryptoBox::encrypt(in_bytes, in.size(), - passphrase, rng.get_underlying_rng()); - } - -std::string cryptobox_decrypt(const std::string& in, - const std::string& passphrase) - { - const byte* in_bytes = reinterpret_cast<const byte*>(in.data()); - - return CryptoBox::decrypt(in_bytes, in.size(), - passphrase); - } - -std::string python_pbkdf2(const std::string& passphrase, - const std::string& salt, - u32bit iterations, - u32bit output_size, - const std::string& hash_fn) - { - PKCS5_PBKDF2 pbkdf2(new HMAC(get_hash(hash_fn))); - - return make_string( - pbkdf2.derive_key(output_size, - passphrase, - reinterpret_cast<const byte*>(salt.data()), - salt.size(), - iterations).bits_of()); - } - -std::string python_kdf2(const std::string& param, - const std::string& masterkey, - u32bit outputlength) - { - std::unique_ptr<KDF> kdf(get_kdf("KDF2(SHA-1)")); - - return make_string( - kdf->derive_key(outputlength, - reinterpret_cast<const byte*>(masterkey.data()), - masterkey.length(), - param)); - } - -BOOST_PYTHON_MODULE(_botan) - { - python::class_<Python_RandomNumberGenerator>("RandomNumberGenerator") - .def(python::init<>()) - .def("__str__", &Python_RandomNumberGenerator::name) - .def("name", &Python_RandomNumberGenerator::name) - .def("reseed", &Python_RandomNumberGenerator::reseed) - .def("add_entropy", &Python_RandomNumberGenerator::add_entropy) - .def("gen_random_byte", &Python_RandomNumberGenerator::gen_random_byte) - .def("gen_random", &Python_RandomNumberGenerator::gen_random); - - python::class_<Py_Cipher, boost::noncopyable> - ("Cipher", python::init<std::string, std::string, std::string>()) - .def("name", &Py_Cipher::name) - .def("cipher", &Py_Cipher::cipher) - .def("cipher", &Py_Cipher::cipher_noiv); - - python::class_<Py_HashFunction, boost::noncopyable> - ("HashFunction", python::init<std::string>()) - .def("update", &Py_HashFunction::update) - .def("final", &Py_HashFunction::final) - .def("name", &Py_HashFunction::name) - .def("output_length", &Py_HashFunction::output_length); - - python::class_<Py_MAC, boost::noncopyable> - ("MAC", python::init<std::string, std::string>()) - .def("update", &Py_MAC::update) - .def("final", &Py_MAC::final) - .def("name", &Py_MAC::name) - .def("output_length", &Py_MAC::output_length); - - python::def("cryptobox_encrypt", cryptobox_encrypt); - python::def("cryptobox_decrypt", cryptobox_decrypt); - python::def("pbkdf2", python_pbkdf2); - python::def("derive_key", python_kdf2); - - export_filters(); - export_rsa(); - export_x509(); - } diff --git a/src/python/filter.cpp b/src/python/filter.cpp deleted file mode 100644 index dc02a05e1..000000000 --- a/src/python/filter.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/* -* Boost.Python module definition -* (C) 1999-2007 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <boost/python.hpp> -using namespace boost::python; - -#include <botan/pipe.h> -#include <botan/lookup.h> -using namespace Botan; - -class Py_Filter : public Filter - { - public: - virtual void write_str(const std::string&) = 0; - - std::string name() const { return "Py_Filter_FIXME"; } - - void write(const byte data[], size_t length) - { - write_str(std::string((const char*)data, length)); - } - - void send_str(const std::string& str) - { - send((const byte*)str.data(), str.length()); - } - }; - -class FilterWrapper : public Py_Filter, public wrapper<Py_Filter> - { - public: - void start_msg() - { - if(override start_msg = this->get_override("start_msg")) - start_msg(); - } - - void end_msg() - { - if(override end_msg = this->get_override("end_msg")) - end_msg(); - } - - void default_start_msg() {} - void default_end_msg() {} - - virtual void write_str(const std::string& str) - { - this->get_override("write")(str); - } - }; - -Filter* return_or_raise(Filter* filter, const std::string& name) - { - if(filter) - return filter; - throw Invalid_Argument("Filter " + name + " could not be found"); - } - -Filter* make_filter1(const std::string& name) - { - Filter* filter = 0; - - if(have_hash(name)) filter = new Hash_Filter(name); - else if(name == "Hex_Encoder") filter = new Hex_Encoder; - else if(name == "Hex_Decoder") filter = new Hex_Decoder; - else if(name == "Base64_Encoder") filter = new Base64_Encoder; - else if(name == "Base64_Decoder") filter = new Base64_Decoder; - - return return_or_raise(filter, name); - } - -Filter* make_filter2(const std::string& name, - const SymmetricKey& key) - { - Filter* filter = 0; - - if(have_mac(name)) - filter = new MAC_Filter(name, key); - else if(have_stream_cipher(name)) - filter = new StreamCipher_Filter(name, key); - - return return_or_raise(filter, name); - } - -// FIXME: add new wrapper for Keyed_Filter here -Filter* make_filter3(const std::string& name, - const SymmetricKey& key, - Cipher_Dir direction) - { - return return_or_raise( - get_cipher(name, key, direction), - name); - } - -Filter* make_filter4(const std::string& name, - const SymmetricKey& key, - const InitializationVector& iv, - Cipher_Dir direction) - { - return return_or_raise( - get_cipher(name, key, iv, direction), - name); - } - -void append_filter(Pipe& pipe, std::auto_ptr<Filter> filter) - { - pipe.append(filter.get()); - filter.release(); - } - -void prepend_filter(Pipe& pipe, std::auto_ptr<Filter> filter) - { - pipe.prepend(filter.get()); - filter.release(); - } - -void do_send(std::auto_ptr<FilterWrapper> filter, const std::string& data) - { - filter->send_str(data); - } - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(rallas_ovls, read_all_as_string, 0, 1) - -void export_filters() - { - class_<Filter, std::auto_ptr<Filter>, boost::noncopyable> - ("__Internal_FilterObj", no_init); - - def("make_filter", make_filter1, - return_value_policy<manage_new_object>()); - def("make_filter", make_filter2, - return_value_policy<manage_new_object>()); - def("make_filter", make_filter3, - return_value_policy<manage_new_object>()); - def("make_filter", make_filter4, - return_value_policy<manage_new_object>()); - - // This might not work - Pipe will delete the filter, but Python - // might have allocated the space with malloc() or who-knows-what -> bad - class_<FilterWrapper, std::auto_ptr<FilterWrapper>, - bases<Filter>, boost::noncopyable> - ("FilterObj") - .def("write", pure_virtual(&Py_Filter::write_str)) - .def("send", &do_send) - .def("start_msg", &Filter::start_msg, &FilterWrapper::default_start_msg) - .def("end_msg", &Filter::end_msg, &FilterWrapper::default_end_msg); - - implicitly_convertible<std::auto_ptr<FilterWrapper>, - std::auto_ptr<Filter> >(); - - void (Pipe::*pipe_write_str)(const std::string&) = &Pipe::write; - void (Pipe::*pipe_process_str)(const std::string&) = &Pipe::process_msg; - - class_<Pipe, boost::noncopyable>("PipeObj") - .def(init<>()) - /* - .def_readonly("LAST_MESSAGE", &Pipe::LAST_MESSAGE) - .def_readonly("DEFAULT_MESSAGE", &Pipe::DEFAULT_MESSAGE) - */ - .add_property("default_msg", &Pipe::default_msg, &Pipe::set_default_msg) - .add_property("msg_count", &Pipe::message_count) - .def("append", append_filter) - .def("prepend", prepend_filter) - .def("reset", &Pipe::reset) - .def("pop", &Pipe::pop) - .def("end_of_data", &Pipe::end_of_data) - .def("start_msg", &Pipe::start_msg) - .def("end_msg", &Pipe::end_msg) - .def("write", pipe_write_str) - .def("process_msg", pipe_process_str) - .def("read_all", &Pipe::read_all_as_string, rallas_ovls()); - } diff --git a/src/python/python_botan.h b/src/python/python_botan.h deleted file mode 100644 index c4ee6a9e0..000000000 --- a/src/python/python_botan.h +++ /dev/null @@ -1,86 +0,0 @@ -/* -* (C) 2009 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#ifndef BOTAN_BOOST_PYTHON_COMMON_H__ -#define BOTAN_BOOST_PYTHON_COMMON_H__ - -#include <botan/exceptn.h> -#include <botan/parsing.h> -#include <botan/secmem.h> -using namespace Botan; - -#include <boost/python.hpp> -namespace python = boost::python; - -extern void export_filters(); -extern void export_rsa(); -extern void export_x509(); - -class Bad_Size : public Exception - { - public: - Bad_Size(u32bit got, u32bit expected) : - Exception("Bad size detected in Python/C++ conversion layer: got " + - std::to_string(got) + " bytes, expected " + - std::to_string(expected)) - {} - }; - -inline std::string make_string(const byte input[], u32bit length) - { - return std::string((const char*)input, length); - } - -template<typename Alloc> -inline std::string make_string(const std::vector<byte, Alloc>& in) - { - return make_string(&in[0], in.size()); - } - -inline void string2binary(const std::string& from, byte to[], u32bit expected) - { - if(from.size() != expected) - throw Bad_Size(from.size(), expected); - std::memcpy(to, from.data(), expected); - } - -template<typename T> -inline python::object get_owner(T* me) - { - return python::object( - python::handle<>( - python::borrowed(python::detail::wrapper_base_::get_owner(*me)))); - } - -class Python_RandomNumberGenerator - { - public: - Python_RandomNumberGenerator() - { rng = RandomNumberGenerator::make_rng(); } - ~Python_RandomNumberGenerator() { delete rng; } - - std::string name() const { return rng->name(); } - - void reseed() { rng->reseed(192); } - - int gen_random_byte() { return rng->next_byte(); } - - std::string gen_random(int n) - { - std::string s(n, 0); - rng->randomize(reinterpret_cast<byte*>(&s[0]), n); - return s; - } - - void add_entropy(const std::string& in) - { rng->add_entropy(reinterpret_cast<const byte*>(in.c_str()), in.length()); } - - RandomNumberGenerator& get_underlying_rng() { return *rng; } - private: - RandomNumberGenerator* rng; - }; - -#endif diff --git a/src/python/rsa.cpp b/src/python/rsa.cpp deleted file mode 100644 index 4ba19991c..000000000 --- a/src/python/rsa.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/* -* Boost.Python module definition -* (C) 1999-2007 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <botan/rsa.h> -#include <botan/pubkey.h> -#include <botan/x509_key.h> -using namespace Botan; - -#include "python_botan.h" -#include <sstream> - -std::string bigint2str(const BigInt& n) - { - std::ostringstream out; - out << n; - return out.str(); - } - -class Py_RSA_PrivateKey - { - public: - Py_RSA_PrivateKey(std::string pem_str, - Python_RandomNumberGenerator& rng, - std::string pass); - Py_RSA_PrivateKey(std::string pem_str, - Python_RandomNumberGenerator& rng); - - Py_RSA_PrivateKey(u32bit bits, Python_RandomNumberGenerator& rng); - ~Py_RSA_PrivateKey() { delete rsa_key; } - - std::string to_string() const - { - return PKCS8::PEM_encode(*rsa_key); - } - - std::string to_ber() const - { - secure_vector<byte> bits = PKCS8::BER_encode(*rsa_key); - return std::string(reinterpret_cast<const char*>(&bits[0]), bits.size()); - } - - std::string get_N() const { return bigint2str(get_bigint_N()); } - std::string get_E() const { return bigint2str(get_bigint_E()); } - - const BigInt& get_bigint_N() const { return rsa_key->get_n(); } - const BigInt& get_bigint_E() const { return rsa_key->get_e(); } - - std::string decrypt(const std::string& in, - const std::string& padding); - - std::string sign(const std::string& in, - const std::string& padding, - Python_RandomNumberGenerator& rng); - private: - RSA_PrivateKey* rsa_key; - }; - -std::string Py_RSA_PrivateKey::decrypt(const std::string& in, - const std::string& padding) - { - PK_Decryptor_EME dec(*rsa_key, padding); - - const byte* in_bytes = reinterpret_cast<const byte*>(in.data()); - - return make_string(dec.decrypt(in_bytes, in.size())); - } - -std::string Py_RSA_PrivateKey::sign(const std::string& in, - const std::string& padding, - Python_RandomNumberGenerator& rng) - { - PK_Signer sign(*rsa_key, padding); - const byte* in_bytes = reinterpret_cast<const byte*>(in.data()); - sign.update(in_bytes, in.size()); - return make_string(sign.signature(rng.get_underlying_rng())); - } - -Py_RSA_PrivateKey::Py_RSA_PrivateKey(u32bit bits, - Python_RandomNumberGenerator& rng) - { - rsa_key = new RSA_PrivateKey(rng.get_underlying_rng(), bits); - } - -Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str, - Python_RandomNumberGenerator& rng) - { - DataSource_Memory in(pem_str); - - Private_Key* pkcs8_key = - PKCS8::load_key(in, - rng.get_underlying_rng()); - - rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key); - - if(!rsa_key) - throw std::invalid_argument("Key is not an RSA key"); - } - -Py_RSA_PrivateKey::Py_RSA_PrivateKey(std::string pem_str, - Python_RandomNumberGenerator& rng, - std::string passphrase) - { - DataSource_Memory in(pem_str); - - Private_Key* pkcs8_key = - PKCS8::load_key(in, - rng.get_underlying_rng(), - passphrase); - - rsa_key = dynamic_cast<RSA_PrivateKey*>(pkcs8_key); - - if(!rsa_key) - throw std::invalid_argument("Key is not an RSA key"); - } - -class Py_RSA_PublicKey - { - public: - Py_RSA_PublicKey(std::string pem_str); - Py_RSA_PublicKey(const Py_RSA_PrivateKey&); - ~Py_RSA_PublicKey() { delete rsa_key; } - - std::string get_N() const { return bigint2str(get_bigint_N()); } - std::string get_E() const { return bigint2str(get_bigint_E()); } - - const BigInt& get_bigint_N() const { return rsa_key->get_n(); } - const BigInt& get_bigint_E() const { return rsa_key->get_e(); } - - std::string to_string() const - { - return X509::PEM_encode(*rsa_key); - } - - std::string to_ber() const - { - std::vector<byte> bits = X509::BER_encode(*rsa_key); - - return std::string(reinterpret_cast<const char*>(&bits[0]), - bits.size()); - } - - std::string encrypt(const std::string& in, - const std::string& padding, - Python_RandomNumberGenerator& rng); - - bool verify(const std::string& in, - const std::string& padding, - const std::string& signature); - private: - RSA_PublicKey* rsa_key; - }; - -Py_RSA_PublicKey::Py_RSA_PublicKey(const Py_RSA_PrivateKey& priv) - { - rsa_key = new RSA_PublicKey(priv.get_bigint_N(), priv.get_bigint_E()); - } - -Py_RSA_PublicKey::Py_RSA_PublicKey(std::string pem_str) - { - DataSource_Memory in(pem_str); - Public_Key* x509_key = X509::load_key(in); - - rsa_key = dynamic_cast<RSA_PublicKey*>(x509_key); - - if(!rsa_key) - throw std::invalid_argument("Key is not an RSA key"); - } - -std::string Py_RSA_PublicKey::encrypt(const std::string& in, - const std::string& padding, - Python_RandomNumberGenerator& rng) - { - PK_Encryptor_EME enc(*rsa_key, padding); - - const byte* in_bytes = reinterpret_cast<const byte*>(in.data()); - - return make_string(enc.encrypt(in_bytes, in.size(), - rng.get_underlying_rng())); - } - -bool Py_RSA_PublicKey::verify(const std::string& in, - const std::string& signature, - const std::string& padding) - { - PK_Verifier ver(*rsa_key, padding); - - const byte* in_bytes = reinterpret_cast<const byte*>(in.data()); - const byte* sig_bytes = reinterpret_cast<const byte*>(signature.data()); - - ver.update(in_bytes, in.size()); - return ver.check_signature(sig_bytes, signature.size()); - } - -void export_rsa() - { - python::class_<Py_RSA_PublicKey> - ("RSA_PublicKey", python::init<std::string>()) - .def(python::init<const Py_RSA_PrivateKey&>()) - .def("to_string", &Py_RSA_PublicKey::to_string) - .def("to_ber", &Py_RSA_PublicKey::to_ber) - .def("encrypt", &Py_RSA_PublicKey::encrypt) - .def("verify", &Py_RSA_PublicKey::verify) - .def("get_N", &Py_RSA_PublicKey::get_N) - .def("get_E", &Py_RSA_PublicKey::get_E); - - python::class_<Py_RSA_PrivateKey> - ("RSA_PrivateKey", python::init<std::string, Python_RandomNumberGenerator&, std::string>()) - .def(python::init<std::string, Python_RandomNumberGenerator&>()) - .def(python::init<u32bit, Python_RandomNumberGenerator&>()) - .def("to_string", &Py_RSA_PrivateKey::to_string) - .def("to_ber", &Py_RSA_PrivateKey::to_ber) - .def("decrypt", &Py_RSA_PrivateKey::decrypt) - .def("sign", &Py_RSA_PrivateKey::sign) - .def("get_N", &Py_RSA_PrivateKey::get_N) - .def("get_E", &Py_RSA_PrivateKey::get_E); - } diff --git a/src/python/x509.cpp b/src/python/x509.cpp deleted file mode 100644 index 48cfca2c7..000000000 --- a/src/python/x509.cpp +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Boost.Python module definition -* (C) 2009 Jack Lloyd -* -* Botan is released under the Simplified BSD License (see license.txt) -*/ - -#include <botan/oids.h> -#include <botan/pipe.h> -#include <botan/filters.h> -#include <botan/x509cert.h> -#include <botan/x509_crl.h> -using namespace Botan; - -#include <boost/python.hpp> -namespace python = boost::python; - -template<typename T> -class vector_to_list - { - public: - static PyObject* convert(const std::vector<T>& in) - { - python::list out; - typename std::vector<T>::const_iterator i = in.begin(); - while(i != in.end()) - { - out.append(*i); - ++i; - } - return python::incref(out.ptr()); - } - - vector_to_list() - { - python::to_python_converter<std::vector<T>, vector_to_list<T> >(); - } - }; - -template<typename T> -class memvec_to_hexstr - { - public: - static PyObject* convert(const T& in) - { - Pipe pipe(new Hex_Encoder); - pipe.process_msg(in); - std::string result = pipe.read_all_as_string(); - return python::incref(python::str(result).ptr()); - } - - memvec_to_hexstr() - { - python::to_python_converter<T, memvec_to_hexstr<T> >(); - } - }; - -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(add_cert_ols, add_cert, 1, 2) -BOOST_PYTHON_MEMBER_FUNCTION_OVERLOADS(validate_cert_ols, validate_cert, 1, 2) - -void export_x509() - { - vector_to_list<std::string>(); - vector_to_list<X509_Certificate>(); - memvec_to_hexstr<std::vector<byte> >(); - - python::class_<X509_Certificate> - ("X509_Certificate", python::init<std::string>()) - .def(python::self == python::self) - .def(python::self != python::self) - .add_property("version", &X509_Certificate::x509_version) - .add_property("is_CA", &X509_Certificate::is_CA_cert) - .add_property("self_signed", &X509_Certificate::is_self_signed) - .add_property("pathlimit", &X509_Certificate::path_limit) - .add_property("as_pem", &X509_Object::PEM_encode) - .def("start_time", &X509_Certificate::start_time) - .def("end_time", &X509_Certificate::end_time) - .def("subject_info", &X509_Certificate::subject_info) - .def("issuer_info", &X509_Certificate::issuer_info) - .def("ex_constraints", &X509_Certificate::ex_constraints) - .def("policies", &X509_Certificate::policies) - .def("subject_key_id", &X509_Certificate::subject_key_id) - .def("authority_key_id", &X509_Certificate::authority_key_id); - - python::class_<X509_CRL> - ("X509_CRL", python::init<std::string>()) - .add_property("as_pem", &X509_Object::PEM_encode); - } |