diff options
Diffstat (limited to 'wrappers')
46 files changed, 3623 insertions, 0 deletions
diff --git a/wrappers/boost-python/Makefile b/wrappers/boost-python/Makefile new file mode 100644 index 000000000..0f5ca68d2 --- /dev/null +++ b/wrappers/boost-python/Makefile @@ -0,0 +1,26 @@ +CXX = g++ +LANG_FLAGS = -fPIC -Wall -Wno-unused -ftemplate-depth-255 +OPT_FLAGS = -g -Os + +PYTHON_ROOT = /usr/lib/python2.4/config +PYTHON_INC = -I/usr/include/python2.4 +PYTHON_DEF = -DBOOST_PYTHON_DYNAMIC_LIB -DBOOST_PYTHON_SOURCE + +WRAPPER_CFLAGS = $(shell botan-config --cflags) +SHARED_CFLAGS = $(LANG_FLAGS) $(OPT_FLAGS) $(PYTHON_INC) + +BOOST_CFLAGS = $(PYTHON_DEF) $(SHARED_CFLAGS) + +WRAP_SRC = $(wildcard src/*.cpp) +WRAP_OBJS = $(patsubst src/%.cpp,%.o,$(WRAP_SRC)) + +all: botan/_botan.so + +%.o: src/%.cpp + $(CXX) -Isrc/ $(SHARED_CFLAGS) $(WRAPPER_CFLAGS) -c $< -o $@ + +botan/_botan.so: $(WRAP_OBJS) + $(CXX) -shared -o $@ $(shell botan-config --libs) -L$(PYTHON_ROOT) $(WRAP_OBJS) -lboost_python -Wl,-rpath-link,. -Wl,-soname,$@ + +clean: + rm -f $(WRAP_OBJS) botan/_botan.so botan/*.pyc diff --git a/wrappers/boost-python/botan/__init__.py b/wrappers/boost-python/botan/__init__.py new file mode 100644 index 000000000..9e136ed39 --- /dev/null +++ b/wrappers/boost-python/botan/__init__.py @@ -0,0 +1,27 @@ +from _botan import * + +# Initialize the library when the module is imported +init = LibraryInitializer() + +class SymmetricKey(OctetString): + pass + +class InitializationVector(OctetString): + pass + +def Filter(name, key = None, iv = None, dir = None): + if key != None and iv != None and dir != None: + return make_filter(name, key, iv, dir) + elif key != None and dir != None: + return make_filter(name, key, dir) + elif key != None: + return make_filter(name, key) + else: + return make_filter(name) + +def Pipe(*filters): + pipe = PipeObj() + for filter in filters: + if filter: + pipe.append(filter) + return pipe diff --git a/wrappers/boost-python/nisttest.py b/wrappers/boost-python/nisttest.py new file mode 100755 index 000000000..a16ebf791 --- /dev/null +++ b/wrappers/boost-python/nisttest.py @@ -0,0 +1,61 @@ +#!/usr/bin/python + +import sys, os, botan +from os.path import join; + +def validate(ca_certs, certs, crls, ee_certs): + store = botan.X509_Store() + for cert in certs: + if cert not in ee_certs: + store.add_cert(botan.X509_Certificate(cert), cert in ca_certs) + + for crl in crls: + r = store.add_crl(botan.X509_CRL(crl)) + if r != botan.verify_result.verified: + return r + + for ee in ee_certs: + r = store.validate(botan.X509_Certificate(ee)) + if r != botan.verify_result.verified: + return r + + return botan.verify_result.verified + +def run_test(files, rootdir, testname, expected): + crls = [join(rootdir,x) for x in files if x.endswith(".crl")] + certs = [join(rootdir,x) for x in files if x.endswith(".crt")] + end_entity = [x for x in certs if x.find("end.crt") != -1] + ca_certs = [x for x in certs if x.find("root.crt") != -1] + + print "%s..." % testname, + + result = validate(ca_certs, certs, crls, end_entity) + result = repr(result).replace('botan._botan.verify_result.', '') + + if result != expected: + print "FAILED: got %s, expected %s" % (result, expected) + else: + print "passed" + +def main(): + def load_results(file): + results = {} + for line in open(file, 'r'): + line = line[0:line.find('#')].strip() + if line: + test,result = line.split(' ') + results[test] = result + return results + + results = load_results('results.txt') + + for root, dirs, files in os.walk('../nist_tests/tests'): + if files: + thistest = root[root.rfind('/')+1:] + if thistest in results: + run_test(files, root, thistest, results[thistest]) + else: + print "%s... skipping - no expected result set" % thistest + +if __name__ == "__main__": + sys.exit(main()) diff --git a/wrappers/boost-python/results.txt b/wrappers/boost-python/results.txt new file mode 100644 index 000000000..7a3824001 --- /dev/null +++ b/wrappers/boost-python/results.txt @@ -0,0 +1,60 @@ +# This is the file of expected results for nisttest.py +test01 verified +test02 signature_error +test03 signature_error +test04 verified +test05 cert_not_yet_valid +test06 cert_not_yet_valid +test07 verified +test08 cert_not_yet_valid +test09 cert_has_expired +test10 cert_has_expired +test11 cert_has_expired +test12 verified +test13 cert_issuer_not_found +test14 cert_issuer_not_found +test15 verified +test16 verified +test17 verified +test18 verified +# changed; should be no_revocation_data_available, but I don't want to +# force people to use CRLs +test19 verified +test20 cert_is_revoked +test21 cert_is_revoked +test22 ca_cert_not_for_cert_issuer +test23 ca_cert_not_for_cert_issuer +test24 verified +test25 ca_cert_not_for_cert_issuer +test26 verified +test27 verified +test28 ca_cert_not_for_cert_issuer +test29 ca_cert_not_for_cert_issuer +test30 verified +test31 ca_cert_not_for_crl_issuer +test32 ca_cert_not_for_crl_issuer +test33 verified +test54 cert_chain_too_long +test55 cert_chain_too_long +test56 verified +test57 verified +test58 cert_chain_too_long +test59 cert_chain_too_long +test60 cert_chain_too_long +test61 cert_chain_too_long +test62 verified +test63 verified +test64 signature_error +# changed; I have no idea why this test is supposed to fail +test65 verified +test66 crl_issuer_not_found +# changed; one of the CRLs has an unknown creator, so we fail +# prior to getting to the end-entity check +test67 crl_issuer_not_found +test68 cert_is_revoked +test69 cert_is_revoked +test70 cert_is_revoked +test71 cert_is_revoked +test72 crl_has_expired +test73 crl_has_expired +test74 verified diff --git a/wrappers/boost-python/src/block.cpp b/wrappers/boost-python/src/block.cpp new file mode 100644 index 000000000..385376005 --- /dev/null +++ b/wrappers/boost-python/src/block.cpp @@ -0,0 +1,152 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/botan.h> +using namespace Botan; + +#include "common.h" + +class Py_BlockCipher : public BlockCipher + { + public: + virtual std::string enc_str(const std::string&) const = 0; + virtual std::string dec_str(const std::string&) const = 0; + virtual void set_key_obj(const OctetString&) = 0; + + void clear() throw() {} + + void enc(const byte in[], byte out[]) const + { + string2binary( + enc_str(make_string(in, BLOCK_SIZE)), + out, BLOCK_SIZE); + } + + void dec(const byte in[], byte out[]) const + { + string2binary( + dec_str(make_string(in, BLOCK_SIZE)), + out, BLOCK_SIZE); + } + + void key(const byte key[], u32bit len) + { + set_key_obj(OctetString(key, len)); + } + + Py_BlockCipher(u32bit bs, u32bit kmin, u32bit kmax, u32bit kmod) : + BlockCipher(bs, kmin, kmax, kmod) + { + } + }; + +std::string encrypt_string(BlockCipher* cipher, const std::string& in) + { + if(in.size() != cipher->BLOCK_SIZE) + throw Bad_Size(in.size(), cipher->BLOCK_SIZE); + + SecureVector<byte> out(cipher->BLOCK_SIZE); + cipher->encrypt((const byte*)in.data(), out); + return make_string(out); + } + +std::string decrypt_string(BlockCipher* cipher, const std::string& in) + { + if(in.size() != cipher->BLOCK_SIZE) + throw Bad_Size(in.size(), cipher->BLOCK_SIZE); + + SecureVector<byte> out(cipher->BLOCK_SIZE); + cipher->decrypt((const byte*)in.data(), out); + return make_string(out); + } + +class Wrapped_Block_Cipher : public BlockCipher + { + public: + void clear() throw() { cipher->clear(); } + + void enc(const byte in[], byte out[]) const { cipher->encrypt(in, out); } + void dec(const byte in[], byte out[]) const { cipher->decrypt(in, out); } + void key(const byte key[], u32bit len) { cipher->set_key(key, len); } + std::string name() const { return cipher->name(); } + BlockCipher* clone() const { return cipher->clone(); } + + Wrapped_Block_Cipher(python::object py_obj, BlockCipher* c) : + BlockCipher(c->BLOCK_SIZE, c->MINIMUM_KEYLENGTH, + c->MAXIMUM_KEYLENGTH, c->KEYLENGTH_MULTIPLE), + obj(py_obj), cipher(c) {} + private: + python::object obj; + BlockCipher* cipher; + }; + +class Py_BlockCipher_Wrapper : public Py_BlockCipher, + public python::wrapper<Py_BlockCipher> + { + public: + BlockCipher* clone() const + { + python::object self = get_owner(this); + python::object py_clone = self.attr("__class__")(); + BlockCipher* bc = python::extract<BlockCipher*>(py_clone); + return new Wrapped_Block_Cipher(py_clone, bc); + } + + void clear() throw() + { + this->get_override("clear")(); + } + + std::string name() const + { + return this->get_override("name")(); + } + + std::string enc_str(const std::string& in) const + { + return this->get_override("encrypt")(in); + } + + std::string dec_str(const std::string& in) const + { + return this->get_override("decrypt")(in); + } + + void set_key_obj(const OctetString& key) + { + this->get_override("set_key")(key); + } + + Py_BlockCipher_Wrapper(u32bit bs, u32bit kmin, + u32bit kmax, u32bit kmod) : + Py_BlockCipher(bs, kmin, kmax, kmod) {} + }; + +void export_block_ciphers() + { + void (BlockCipher::*set_key_ptr)(const OctetString&) = + &BlockCipher::set_key; + + python::class_<BlockCipher, boost::noncopyable> + ("BlockCipher", python::no_init) + .def("__init__", python::make_constructor(get_block_cipher)) + .def_readonly("block_size", &BlockCipher::BLOCK_SIZE) + .def_readonly("keylength_min", &BlockCipher::MINIMUM_KEYLENGTH) + .def_readonly("keylength_max", &BlockCipher::MAXIMUM_KEYLENGTH) + .def_readonly("keylength_mod", &BlockCipher::KEYLENGTH_MULTIPLE) + .def("valid_keylength", &BlockCipher::valid_keylength) + .def("name", &BlockCipher::name) + .def("set_key", set_key_ptr) + .def("encrypt", encrypt_string) + .def("decrypt", decrypt_string); + + python::class_<Py_BlockCipher_Wrapper, python::bases<BlockCipher>, + boost::noncopyable> + ("BlockCipherImpl", python::init<u32bit, u32bit, u32bit, u32bit>()) + .def("name", python::pure_virtual(&Py_BlockCipher::name)) + .def("encrypt", python::pure_virtual(&Py_BlockCipher::enc_str)) + .def("decrypt", python::pure_virtual(&Py_BlockCipher::dec_str)) + .def("set_key", python::pure_virtual(&Py_BlockCipher::set_key_obj)); + } diff --git a/wrappers/boost-python/src/common.h b/wrappers/boost-python/src/common.h new file mode 100644 index 000000000..968cc3908 --- /dev/null +++ b/wrappers/boost-python/src/common.h @@ -0,0 +1,45 @@ + +#ifndef BOTAN_BOOST_PYTHON_COMMON_H__ +#define BOTAN_BOOST_PYTHON_COMMON_H__ + +#include <botan/base.h> +using namespace Botan; + +#include <boost/python.hpp> +namespace python = boost::python; + +class Bad_Size : public Exception + { + public: + Bad_Size(u32bit got, u32bit expected) : + Exception("Bad size detected in Python/C++ conversion layer: got " + + to_string(got) + " bytes, expected " + to_string(expected)) + {} + }; + +inline std::string make_string(const byte input[], u32bit length) + { + return std::string((const char*)input, length); + } + +inline std::string make_string(const MemoryRegion<byte>& in) + { + return make_string(in.begin(), 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)))); + } + +#endif diff --git a/wrappers/boost-python/src/core.cpp b/wrappers/boost-python/src/core.cpp new file mode 100644 index 000000000..3bca5330f --- /dev/null +++ b/wrappers/boost-python/src/core.cpp @@ -0,0 +1,43 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/botan.h> +using namespace Botan; + +#include <boost/python.hpp> +namespace python = boost::python; + +extern void export_block_ciphers(); +extern void export_stream_ciphers(); +extern void export_hash_functions(); +extern void export_macs(); +extern void export_filters(); +extern void export_pk(); +extern void export_x509(); + +BOOST_PYTHON_MODULE(_botan) + { + python::class_<LibraryInitializer>("LibraryInitializer") + .def(python::init< python::optional<std::string> >()); + + python::class_<OctetString>("OctetString") + .def(python::init< python::optional<std::string> >()) + //.def(python::init< u32bit >()) + .def("__str__", &OctetString::as_string) + .def("__len__", &OctetString::length); + + python::enum_<Cipher_Dir>("cipher_dir") + .value("encryption", ENCRYPTION) + .value("decryption", DECRYPTION); + + export_block_ciphers(); + export_stream_ciphers(); + export_hash_functions(); + export_macs(); + + export_filters(); + export_pk(); + export_x509(); + } diff --git a/wrappers/boost-python/src/filter.cpp b/wrappers/boost-python/src/filter.cpp new file mode 100644 index 000000000..262622eef --- /dev/null +++ b/wrappers/boost-python/src/filter.cpp @@ -0,0 +1,176 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#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; + + void write(const byte data[], u32bit length) + { + write_str(std::string((const char*)data, length)); + } + + void send_str(const std::string& str) + { + printf("Py_Filter::send_str\n"); + send((const byte*)str.data(), str.length()); + } + }; + +class FilterWrapper : public Py_Filter, public wrapper<Py_Filter> + { + public: + void start_msg() + { + printf("wrapper start_msg\n"); + if(override start_msg = this->get_override("start_msg")) + start_msg(); + } + + void end_msg() + { + printf("wrapper end_msg\n"); + 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) + { + printf("wrapper write\n"); + 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(global_state(), 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(global_state(), 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) + { + printf("Sending %s to %p\n", data.c_str(), filter.get()); + 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/wrappers/boost-python/src/hash.cpp b/wrappers/boost-python/src/hash.cpp new file mode 100644 index 000000000..69c107c32 --- /dev/null +++ b/wrappers/boost-python/src/hash.cpp @@ -0,0 +1,108 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/botan.h> +using namespace Botan; + +#include "common.h" + +class Py_HashFunction : public HashFunction + { + public: + virtual void hash_str(const std::string&) = 0; + virtual std::string final_str() = 0; + + void clear() throw() {} + + void add_data(const byte input[], u32bit length) + { + hash_str(make_string(input, length)); + } + + void final_result(byte output[]) + { + string2binary(final_str(), output, OUTPUT_LENGTH); + } + + Py_HashFunction(u32bit digest_size, u32bit block_size) : + HashFunction(digest_size, block_size) {} + }; + +class Wrapped_HashFunction : public HashFunction + { + public: + void add_data(const byte in[], u32bit len) { hash->update(in, len); } + void final_result(byte out[]) { hash->final(out); } + + void clear() throw() {} + + std::string name() const { return hash->name(); } + HashFunction* clone() const { return hash->clone(); } + + Wrapped_HashFunction(python::object py_obj, HashFunction* h) : + HashFunction(h->OUTPUT_LENGTH, h->HASH_BLOCK_SIZE), + obj(py_obj), hash(h) {} + private: + python::object obj; + HashFunction* hash; + }; + +class Py_HashFunction_Wrapper : public Py_HashFunction, + public python::wrapper<Py_HashFunction> + { + public: + HashFunction* clone() const + { + python::object self = get_owner(this); + python::object py_clone = self.attr("__class__")(); + HashFunction* hf = python::extract<HashFunction*>(py_clone); + return new Wrapped_HashFunction(py_clone, hf); + } + + std::string name() const + { + return this->get_override("name")(); + } + + void hash_str(const std::string& in) + { + this->get_override("update")(in); + } + + std::string final_str() + { + return this->get_override("final")(); + } + + Py_HashFunction_Wrapper(u32bit digest_size, u32bit block_size) : + Py_HashFunction(digest_size, block_size) {} + }; + +std::string final_str(HashFunction* hash) + { + SecureVector<byte> digest = hash->final(); + return std::string((const char*)digest.begin(), digest.size()); + } + +void export_hash_functions() + { + void (HashFunction::*update_str)(const std::string&) = + &HashFunction::update; + + python::class_<HashFunction, boost::noncopyable> + ("HashFunction", python::no_init) + .def("__init__", python::make_constructor(get_hash)) + .def_readonly("digest_size", &HashFunction::OUTPUT_LENGTH) + .def("name", &HashFunction::name) + .def("update", update_str) + .def("final", final_str); + + python::class_<Py_HashFunction_Wrapper, python::bases<HashFunction>, + boost::noncopyable> + ("HashFunctionImpl", python::init<u32bit, u32bit>()) + .def("name", python::pure_virtual(&Py_HashFunction::name)) + .def("update", python::pure_virtual(&Py_HashFunction::hash_str)) + .def("final", python::pure_virtual(&Py_HashFunction::final_str)); + } diff --git a/wrappers/boost-python/src/macs.cpp b/wrappers/boost-python/src/macs.cpp new file mode 100644 index 000000000..54a55afe2 --- /dev/null +++ b/wrappers/boost-python/src/macs.cpp @@ -0,0 +1,59 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/botan.h> +using namespace Botan; + +#include <boost/python.hpp> +namespace python = boost::python; + +class Py_MAC + { + public: + u32bit output_length() const { return mac->OUTPUT_LENGTH; } + u32bit keylength_min() const { return mac->MINIMUM_KEYLENGTH; } + u32bit keylength_max() const { return mac->MAXIMUM_KEYLENGTH; } + u32bit keylength_mod() const { return mac->KEYLENGTH_MULTIPLE; } + std::string name() const { return mac->name(); } + void clear() throw() { mac->clear(); } + + void set_key(const OctetString& key) { mac->set_key(key); } + + bool valid_keylength(u32bit kl) const + { + return mac->valid_keylength(kl); + } + + void update(const std::string& in) { mac->update(in); } + + std::string final() + { + SecureVector<byte> result = mac->final(); + return std::string((const char*)result.begin(), result.size()); + } + + Py_MAC(const std::string& name) + { + mac = get_mac(name); + } + ~Py_MAC() { delete mac; } + private: + MessageAuthenticationCode* mac; + }; + +void export_macs() + { + python::class_<Py_MAC>("MAC", python::init<std::string>()) + .add_property("output_length", &Py_MAC::output_length) + .add_property("keylength_min", &Py_MAC::keylength_min) + .add_property("keylength_max", &Py_MAC::keylength_max) + .add_property("keylength_mod", &Py_MAC::keylength_mod) + .add_property("name", &Py_MAC::name) + .def("valid_keylength", &Py_MAC::valid_keylength) + .def("set_key", &Py_MAC::set_key) + .def("clear", &Py_MAC::clear) + .def("update", &Py_MAC::update) + .def("final", &Py_MAC::final); + } diff --git a/wrappers/boost-python/src/pk.cpp b/wrappers/boost-python/src/pk.cpp new file mode 100644 index 000000000..72d3294b8 --- /dev/null +++ b/wrappers/boost-python/src/pk.cpp @@ -0,0 +1,125 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/rsa.h> +#include <botan/dsa.h> +#include <botan/dh.h> +#include <botan/look_pk.h> +using namespace Botan; + +#include <boost/python.hpp> +namespace python = boost::python; + +std::string encode_pub(const Public_Key* key, + const std::string& type) + { + if(type == "DER") + { + Pipe pipe; + pipe.start_msg(); + X509::encode(*key, pipe, RAW_BER); + pipe.end_msg(); + return pipe.read_all_as_string(); + } + else if(type == "PEM") + return X509::PEM_encode(*key); + else + throw Encoding_Error("Unknown key encoding method " + type); + } + +std::string encode_priv(const Private_Key* key, + const std::string& type) + { + if(type == "DER") + { + Pipe pipe; + PKCS8::encode(*key, pipe, RAW_BER); + return pipe.read_all_as_string(); + } + else if(type == "PEM") + return PKCS8::PEM_encode(*key); + else + throw Encoding_Error("Unknown key encoding method " + type); + } + +/* +Private_Key* load_priv(const std::string& file, const std::string& pass) + { + return PKCS8::load_key(file, pass); + } + +Public_Key* load_public(const std::string& file) + { + return X509::load_key(file); + } +*/ + +/* +std::string encrypt_string(const PK_Encryptor* enc, const std::string& in) + { + SecureVector<byte> cipher = enc->encrypt((const byte*)in.data(), in.length()); + return std::string((const char*)cipher.begin(), cipher.size()); + } + +std::string decrypt_string(const PK_Decryptor* dec, const std::string& in) + { + SecureVector<byte> plain = dec->decrypt((const byte*)in.data(), in.length()); + return std::string((const char*)plain.begin(), plain.size()); + } +*/ + +void export_pk() + { + /* + python::def("private_key", load_priv, + python::return_value_policy<python::manage_new_object>()); + python::def("public_key", load_public, + python::return_value_policy<python::manage_new_object>()); + */ + + python::class_<Public_Key, boost::noncopyable> + ("Public_Key", python::no_init) + .add_property("name", &Public_Key::algo_name) + .add_property("max_input_bits", &Public_Key::max_input_bits) + .def("public_key", encode_pub); + + python::class_<PK_Encrypting_Key, python::bases<Public_Key>, boost::noncopyable> + ("PK_Encrypting_Key", python::no_init); + + python::class_<Private_Key, python::bases<Public_Key>, boost::noncopyable> + ("Private_Key", python::no_init) + .def("private_key", encode_priv); + + python::class_<PK_Decrypting_Key, python::bases<Private_Key>, boost::noncopyable> + ("PK_Decrypting_Key", python::no_init); + + python::class_<RSA_PublicKey, python::bases<PK_Encrypting_Key> > + ("RSA_PublicKey", python::no_init); + + python::class_<DSA_PublicKey, python::bases<Public_Key> > + ("DSA_PublicKey", python::no_init); + + /* + python::class_<RSA_PrivateKey, python::bases<RSA_PublicKey, PK_Decrypting_Key> > + ("RSA_PrivateKey", python::init<u32bit>()); + */ + + /* + python::class_<PK_Encryptor, boost::noncopyable> + ("PK_Encryptor", python::no_init) + .def("__init__", + python::make_constructor(get_pk_encryptor, + python::with_custodian_and_ward_postcall<0, 1>())) + .def("max_input", &PK_Encryptor::maximum_input_size) + .def("encrypt", encrypt_string); + */ + + /* + python::class_<PK_Decryptor, boost::noncopyable> + ("PK_Decryptor", python::no_init) + .def("__init__", python::make_constructor(get_pk_decryptor)) + .def("decrypt", decrypt_string); + */ + } diff --git a/wrappers/boost-python/src/stream.cpp b/wrappers/boost-python/src/stream.cpp new file mode 100644 index 000000000..97ea9ae04 --- /dev/null +++ b/wrappers/boost-python/src/stream.cpp @@ -0,0 +1,54 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/botan.h> +using namespace Botan; + +#include "common.h" + +class Py_StreamCipher + { + public: + u32bit keylength_min() const { return cipher->MINIMUM_KEYLENGTH; } + u32bit keylength_max() const { return cipher->MAXIMUM_KEYLENGTH; } + u32bit keylength_mod() const { return cipher->KEYLENGTH_MULTIPLE; } + + void set_key(const OctetString& key) { cipher->set_key(key); } + bool valid_keylength(u32bit kl) const + { + return cipher->valid_keylength(kl); + } + + std::string name() const { return cipher->name(); } + void clear() throw() { cipher->clear(); } + + std::string crypt(const std::string& in) const + { + SecureVector<byte> out(in.size()); + cipher->encrypt((const byte*)in.data(), out.begin(), in.size()); + return std::string((const char*)out.begin(), out.size()); + } + + Py_StreamCipher(const std::string& name) + { + cipher = get_stream_cipher(name); + } + ~Py_StreamCipher() { delete cipher; } + private: + StreamCipher* cipher; + }; + +void export_stream_ciphers() + { + python::class_<Py_StreamCipher>("StreamCipher", python::init<std::string>()) + .add_property("keylength_min", &Py_StreamCipher::keylength_min) + .add_property("keylength_max", &Py_StreamCipher::keylength_max) + .add_property("keylength_mod", &Py_StreamCipher::keylength_mod) + .add_property("name", &Py_StreamCipher::name) + .def("clear", &Py_StreamCipher::clear) + .def("valid_keylength", &Py_StreamCipher::valid_keylength) + .def("set_key", &Py_StreamCipher::set_key) + .def("crypt", &Py_StreamCipher::crypt); + } diff --git a/wrappers/boost-python/src/x509.cpp b/wrappers/boost-python/src/x509.cpp new file mode 100644 index 000000000..90c2bba1c --- /dev/null +++ b/wrappers/boost-python/src/x509.cpp @@ -0,0 +1,140 @@ +/************************************************* +* Boost.Python module definition * +* (C) 1999-2007 Jack Lloyd * +*************************************************/ + +#include <botan/oids.h> +#include <botan/pipe.h> +#include <botan/filters.h> +#include <botan/x509cert.h> +#include <botan/x509_crl.h> +#include <botan/x509stor.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> >(); + } + }; + +class X509_Store_Search_Wrap : public X509_Store::Search_Func, + public python::wrapper<X509_Store::Search_Func> + { + public: + bool match(const X509_Certificate& cert) const + { + return this->get_override("match")(cert); + } + }; + +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<MemoryVector<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); + + python::enum_<X509_Code>("verify_result") + .value("verified", VERIFIED) + .value("unknown_x509_error", UNKNOWN_X509_ERROR) + .value("cannot_establish_trust", CANNOT_ESTABLISH_TRUST) + .value("cert_chain_too_long", CERT_CHAIN_TOO_LONG) + .value("signature_error", SIGNATURE_ERROR) + .value("policy_error", POLICY_ERROR) + .value("invalid_usage", INVALID_USAGE) + .value("cert_format_error", CERT_FORMAT_ERROR) + .value("cert_issuer_not_found", CERT_ISSUER_NOT_FOUND) + .value("cert_not_yet_valid", CERT_NOT_YET_VALID) + .value("cert_has_expired", CERT_HAS_EXPIRED) + .value("cert_is_revoked", CERT_IS_REVOKED) + .value("crl_format_error", CRL_FORMAT_ERROR) + .value("crl_issuer_not_found", CRL_ISSUER_NOT_FOUND) + .value("crl_not_yet_valid", CRL_NOT_YET_VALID) + .value("crl_has_expired", CRL_HAS_EXPIRED) + .value("ca_cert_cannot_sign", CA_CERT_CANNOT_SIGN) + .value("ca_cert_not_for_cert_issuer", CA_CERT_NOT_FOR_CERT_ISSUER) + .value("ca_cert_not_for_crl_issuer", CA_CERT_NOT_FOR_CRL_ISSUER); + + python::enum_<X509_Store::Cert_Usage>("cert_usage") + .value("any", X509_Store::ANY) + .value("tls_server", X509_Store::TLS_SERVER) + .value("tls_client", X509_Store::TLS_CLIENT) + .value("code_signing", X509_Store::CODE_SIGNING) + .value("email_protection", X509_Store::EMAIL_PROTECTION) + .value("time_stamping", X509_Store::TIME_STAMPING) + .value("crl_signing", X509_Store::CRL_SIGNING); + + { + python::scope in_class = + python::class_<X509_Store>("X509_Store") + .def("add_cert", &X509_Store::add_cert, add_cert_ols()) + .def("validate", &X509_Store::validate_cert, validate_cert_ols()) + .def("get_certs", &X509_Store::get_certs) + .def("add_crl", &X509_Store::add_crl); + + python::class_<X509_Store_Search_Wrap, boost::noncopyable> + ("Search_Func") + .def("match", python::pure_virtual(&X509_Store::Search_Func::match)); + } + } diff --git a/wrappers/perl-xs/Botan.pm b/wrappers/perl-xs/Botan.pm new file mode 100644 index 000000000..ac4ad91fb --- /dev/null +++ b/wrappers/perl-xs/Botan.pm @@ -0,0 +1,117 @@ +package Botan; + +use strict; +use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $AUTOLOAD); + +require DynaLoader; +require AutoLoader; +use Carp; + +@ISA = qw(DynaLoader); +$VERSION = '0.01'; + +@EXPORT_OK = qw( + NONE + IGNORE_WS + FULL_CHECK +); + +%EXPORT_TAGS = ( + 'all' => [ @EXPORT_OK ], + 'decoder_checking' => [ qw( + NONE + IGNORE_WS + FULL_CHECK + )], + +); + + +sub AUTOLOAD +{ + # This AUTOLOAD is used to 'autoload' constants from the constant() + # XS function. If a constant is not found then control is passed + # to the AUTOLOAD in AutoLoader. + + my $constname = $AUTOLOAD; + $constname =~ s/.*:://; + croak '& not defined' if $constname eq 'constant'; +# my $val = constant($constname, @_ ? $_[0] : 0); + my $val = constant($constname); + if ($! != 0) { + if ( $! =~ /Invalid/ ) + { + $AutoLoader::AUTOLOAD = $AUTOLOAD; + goto &AutoLoader::AUTOLOAD; + } + else + { + croak "Your vendor has not defined Botan symbol $constname"; + } + } + no strict 'refs'; + *$AUTOLOAD = sub { $val }; + goto &$AUTOLOAD; +} + + +bootstrap Botan $VERSION; + +# to setup inheritance... + +package Botan::Filter; +use vars qw(@ISA); +@ISA = qw(); + +package Botan::Chain; +use vars qw(@ISA); +@ISA = qw( Botan::Filter ); + +package Botan::Fork; +use vars qw(@ISA); +@ISA = qw( Botan::Filter ); + +package Botan::Hex_Encoder; +use vars qw(@ISA); +@ISA = qw( Botan::Filter ); + +package Botan::Hex_Decoder; +use vars qw(@ISA); +@ISA = qw( Botan::Filter ); + +package Botan::Base64_Decoder; +use vars qw(@ISA); +@ISA = qw( Botan::Filter ); + +package Botan::Base64_Encoder; +use vars qw(@ISA); +@ISA = qw( Botan::Filter ); + + +package Botan; + +1; +__END__ + +=head1 NAME + +Botan - Perl extension for access to Botan ... + +=head1 SYNOPSIS + + use Botan; + blah blah blah + +=head1 DESCRIPTION + +Blah blah blah. + +=head1 AUTHOR + +Vaclav Ovsik <[email protected]> + +=head1 SEE ALSO + +Bla + +=cut diff --git a/wrappers/perl-xs/Botan.xs b/wrappers/perl-xs/Botan.xs new file mode 100644 index 000000000..ded129d2e --- /dev/null +++ b/wrappers/perl-xs/Botan.xs @@ -0,0 +1,829 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#include "EXTERN.h" +#include "perl.h" +#include "XSUB.h" + +#ifdef __cplusplus +} +#endif + +#include <botan/asn1_obj.h> +#include <botan/asn1_oid.h> +#include <botan/base64.h> +#include <botan/basefilt.h> +#include <botan/hex.h> +#include <botan/init.h> +#include <botan/oids.h> +#include <botan/x509cert.h> +#include <botan/x509_ext.h> + + +/* xsubpp converts ':' to '_' in typemap. We create our types without ':' */ + +typedef Botan::ASN1_String Botan__ASN1_String; +typedef Botan::AlgorithmIdentifier Botan__AlgorithmIdentifier; +typedef Botan::AlternativeName Botan__AlternativeName; +typedef Botan::Attribute Botan__Attribute; +typedef Botan::Base64_Decoder Botan__Base64_Decoder; +typedef Botan::Base64_Encoder Botan__Base64_Encoder; +typedef Botan::Chain Botan__Chain; +typedef Botan::Certificate_Extension Botan__Extension; +typedef Botan::Filter Botan__Filter; +typedef Botan::Fork Botan__Fork; +typedef Botan::Hex_Decoder Botan__Hex_Decoder; +typedef Botan::Hex_Encoder Botan__Hex_Encoder; +typedef Botan::OID Botan__OID; +typedef Botan::Pipe Botan__Pipe; +typedef Botan::X509_Certificate Botan__X509_Certificate; +typedef Botan::X509_DN Botan__X509_DN; +typedef Botan::X509_Time Botan__X509_Time; +typedef Botan::u32bit Botan__u32bit; + + +/* Types to keep track of destruction C++ objects passed + * into other objects... + * An Botan object is deleted by his parent object into which is passed, + * e.g. some Filter is deleted when his Pipe is destructed. We must + * track this and not to delete object again in Perls destructor. + */ + +class ObjectInfo +{ +private: + I32 d_signature; + bool d_del; +public: + static I32 const SIGNVAL = 0x696a626f; + ObjectInfo() : d_signature(SIGNVAL), + d_del(true) {}; + ~ObjectInfo() {}; + void set_delete(bool del = true) { d_del = del; }; + void set_delete_no() { set_delete(false); }; + void set_delete_yes() { set_delete(true); }; + bool should_delete() const { return d_del; }; +}; + +/* Constant object in initial state - template */ + +ObjectInfo const oi_init; + + +/* Botan library initializer ... */ + +Botan::LibraryInitializer botan_init; + + + +/*============================================================================*/ + +MODULE = Botan PACKAGE = Botan + +PROTOTYPES: ENABLE + +void +constant(char *name) + CODE: + using namespace Botan; + errno = 0; + switch (name[0]) + { + case 'F': + if ( strEQ(name, "FULL_CHECK") ) + XSRETURN_IV( FULL_CHECK ); // Decoder_Checking enum + break; + case 'I': + if ( strEQ(name, "IGNORE_WS") ) + XSRETURN_IV( IGNORE_WS ); // Decoder_Checking enum + break; + case 'N': + if ( strEQ(name, "NONE") ) + XSRETURN_IV( NONE ); // Decoder_Checking enum + break; + } + errno = EINVAL; + XSRETURN_UNDEF; + + +# =========================== Botan::Chain ========================== + +MODULE = Botan PACKAGE = Botan::Chain + +Botan__Chain * +Botan__Chain::new(f1 = 0, f2 = 0, f3 = 0, f4 = 0) + Botan__Filter *f1; + Botan__Filter *f2; + Botan__Filter *f3; + Botan__Filter *f4; + PREINIT: + ObjectInfo *f1_oi; + ObjectInfo *f2_oi; + ObjectInfo *f3_oi; + ObjectInfo *f4_oi; + CODE: + try { + RETVAL = new Botan__Chain(f1, f2, f3, f4); + if ( f1 ) f1_oi->set_delete_no(); + if ( f2 ) f2_oi->set_delete_no(); + if ( f3 ) f3_oi->set_delete_no(); + if ( f4 ) f4_oi->set_delete_no(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Chain::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + if ( THIS_oi->should_delete() ) + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# =========================== Botan::Fork ========================== + +MODULE = Botan PACKAGE = Botan::Fork + +Botan__Fork * +Botan__Fork::new(f1 = 0, f2 = 0, f3 = 0, f4 = 0) + Botan__Filter *f1; + Botan__Filter *f2; + Botan__Filter *f3; + Botan__Filter *f4; + PREINIT: + ObjectInfo *f1_oi; + ObjectInfo *f2_oi; + ObjectInfo *f3_oi; + ObjectInfo *f4_oi; + CODE: + try { + RETVAL = new Botan__Fork(f1, f2, f3, f4); + if ( f1 ) f1_oi->set_delete_no(); + if ( f2 ) f2_oi->set_delete_no(); + if ( f3 ) f3_oi->set_delete_no(); + if ( f4 ) f4_oi->set_delete_no(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Fork::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + if ( THIS_oi->should_delete() ) + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# ============================ Botan::Base64_Decoder ============================ + +MODULE = Botan PACKAGE = Botan::Base64_Decoder + +Botan__Base64_Decoder * +Botan__Base64_Decoder::new(checking = Botan::NONE) + int checking; + CODE: + try { + using namespace Botan; + RETVAL = new Base64_Decoder((Decoder_Checking)checking); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Base64_Decoder::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + if ( THIS_oi->should_delete() ) + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# =========================== Botan::Base64_Encoder ========================== + +MODULE = Botan PACKAGE = Botan::Base64_Encoder + +Botan__Base64_Encoder * +Botan__Base64_Encoder::new(breaks = false, length = 72) + bool breaks; + Botan__u32bit length; + CODE: + try { + RETVAL = new Botan__Base64_Encoder(breaks, length); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Base64_Encoder::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + if ( THIS_oi->should_delete() ) + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# ============================ Botan::Hex_Decoder ============================ + +MODULE = Botan PACKAGE = Botan::Hex_Decoder + +Botan__Hex_Decoder * +Botan__Hex_Decoder::new(checking = Botan::NONE) + int checking; + CODE: + try { + using namespace Botan; + RETVAL = new Hex_Decoder((Decoder_Checking)checking); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Hex_Decoder::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + if ( THIS_oi->should_delete() ) + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# ============================ Botan::Hex_Encoder ============================ + +MODULE = Botan PACKAGE = Botan::Hex_Encoder + +Botan__Hex_Encoder * +Botan__Hex_Encoder::new(breaks = false, length = 72, lcase = false) + bool breaks; + Botan__u32bit length; + bool lcase; + CODE: + try { + using Botan::Hex_Encoder; + RETVAL = new Hex_Encoder(breaks, length, + lcase ? Hex_Encoder::Lowercase : Hex_Encoder::Uppercase); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Hex_Encoder::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + if ( THIS_oi->should_delete() ) + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# ================================ Botan::OID ================================ + +MODULE = Botan PACKAGE = Botan::OID + +Botan__OID * +Botan__OID::new(s) + char *s; + CODE: + try { + RETVAL = new Botan__OID(s); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__OID::DESTROY() + CODE: + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + +char * +Botan__OID::as_string() + CODE: + try { + RETVAL = const_cast<char *>(THIS->as_string().c_str()); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + + +# ================================ Botan::OIDS ================================ + +MODULE = Botan PACKAGE = Botan::OIDS + +void +add_oid(oid, name) + Botan__OID *oid; + char *name; + CODE: + try { + Botan::OIDS::add_oid(*oid, name); + } + catch (const std::exception &e) { + croak(e.what()); + } + +char * +lookup_by_oid(oid) + Botan__OID *oid; + CODE: + try { + RETVAL = const_cast<char *>(Botan::OIDS::lookup(*oid).c_str()); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +Botan__OID * +lookup_by_name(name) + char *name; + CODE: + try { + RETVAL = new Botan__OID(Botan::OIDS::lookup(name)); + } + catch (const std::exception &e) { + croak(e.what()); + } + char const * CLASS = "Botan::OID"; + OUTPUT: + RETVAL + +int +have_oid(name) + char *name; + CODE: + try { + RETVAL = Botan::OIDS::have_oid(name); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + + +# ================================ Botan::Pipe ================================ + +MODULE = Botan PACKAGE = Botan::Pipe + +Botan__Pipe * +Botan__Pipe::new(...) + CODE: + for (I32 i = 1; i < items; i++) + { + if ( !sv_isobject(ST(i)) || (SvTYPE(SvRV(ST(i))) != SVt_PVMG) ) + croak("Botan::Pipe::new() -- arg %u is not " + "a blessed SV reference", i +1); + if ( !sv_derived_from(ST(i), "Botan::Filter") ) + croak("Botan::Pipe::new() -- arg %u is not " + "an object derived from Botan::Filter", i +1); + MAGIC *mg = mg_find(SvRV(ST(i)), '~'); + if ( mg == 0 + || mg->mg_len != sizeof(ObjectInfo) + || *(I32 *)(mg->mg_ptr) != ObjectInfo::SIGNVAL ) + croak("Botan::Pipe::new() -- arg %u has no " + "valid private magic data (ObjectInfo)", i +1); + } + try { + RETVAL = new Botan__Pipe(); + for (I32 i = 1; i < items; i++) + { + SV *osv = (SV *)SvRV(ST(i)); + ObjectInfo *oi = (ObjectInfo *)(mg_find(osv, '~')->mg_ptr); + RETVAL->append((Botan__Filter *)(SvIV(osv))); + oi->set_delete_no(); + } + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Pipe::DESTROY() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + +void +Botan__Pipe::write(s) + SV *s; + PREINIT: + ObjectInfo *THIS_oi; + CODE: + STRLEN len; + char *ptr = SvPV(s, len); + try { + THIS->write((unsigned char *)ptr, len); + } + catch (const std::exception &e) { + croak(e.what()); + } + +void +Botan__Pipe::process_msg(s) + SV *s; + PREINIT: + ObjectInfo *THIS_oi; + CODE: + STRLEN len; + char *ptr = SvPV(s, len); + try { + THIS->process_msg((unsigned char *)ptr, len); + } + catch (const std::exception &e) { + croak(e.what()); + } + +Botan__u32bit +Botan__Pipe::remaining(msgno = Botan::Pipe::DEFAULT_MESSAGE) + Botan__u32bit msgno; + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + RETVAL = THIS->remaining(msgno); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +SV * +Botan__Pipe::read(len = 0xFFFFFFFF, msgno = Botan::Pipe::DEFAULT_MESSAGE) + Botan__u32bit len; + Botan__u32bit msgno; + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + if ( len > THIS->remaining(msgno) ) + len = THIS->remaining(msgno); + RETVAL = NEWSV(0, len); + SvPOK_on(RETVAL); + if ( len > 0 ) + SvCUR_set(RETVAL, THIS->read((unsigned char *)SvPVX(RETVAL), + len, msgno)); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +SV * +Botan__Pipe::peek(len = 0xFFFFFFFF, offset = 0, \ + msgno = Botan::Pipe::DEFAULT_MESSAGE) + Botan__u32bit len; + Botan__u32bit offset; + Botan__u32bit msgno; + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + if ( len > THIS->remaining(msgno) ) + len = THIS->remaining(msgno); + RETVAL = NEWSV(0, len); + SvPOK_on(RETVAL); + if ( len > 0 ) + SvCUR_set(RETVAL, THIS->peek((unsigned char *)SvPVX(RETVAL), + len, offset, msgno)); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +Botan__u32bit +Botan__Pipe::default_msg() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + RETVAL = THIS->default_msg(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Pipe::set_default_msg(msgno) + Botan__u32bit msgno; + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + THIS->set_default_msg(msgno); + } + catch (const std::exception &e) { + croak(e.what()); + } + +Botan__u32bit +Botan__Pipe::message_count() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + RETVAL = THIS->message_count(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +bool +Botan__Pipe::end_of_data() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + RETVAL = THIS->end_of_data(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__Pipe::start_msg() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + THIS->start_msg(); + } + catch (const std::exception &e) { + croak(e.what()); + } + +void +Botan__Pipe::end_msg() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + THIS->end_msg(); + } + catch (const std::exception &e) { + croak(e.what()); + } + +void +Botan__Pipe::reset() + PREINIT: + ObjectInfo *THIS_oi; + CODE: + try { + THIS->reset(); + } + catch (const std::exception &e) { + croak(e.what()); + } + + +# ========================== Botan::X509_Certificate ========================== + +MODULE = Botan PACKAGE = Botan::X509_Certificate + +Botan__X509_Certificate * +Botan__X509_Certificate::new(char *fn) + CODE: + try { + RETVAL = new Botan__X509_Certificate(fn); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__X509_Certificate::DESTROY() + CODE: + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + +unsigned int +Botan__X509_Certificate::x509_version() + CODE: + try { + RETVAL = THIS->x509_version(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +char * +Botan__X509_Certificate::start_time() + CODE: + try { + RETVAL = const_cast<char *>(THIS->start_time().c_str()); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +char * +Botan__X509_Certificate::end_time() + CODE: + try { + RETVAL = const_cast<char *>(THIS->end_time().c_str()); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +char * +Botan__X509_Certificate::subject_info(char *info) + CODE: + try { + std::vector<std::string> s = THIS->subject_info(info); + + if(s.size() > 0) + RETVAL = const_cast<char *>(s[0].c_str()); + else + RETVAL = "err"; + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +char * +Botan__X509_Certificate::issuer_info(char *info) + CODE: + try { + std::vector<std::string> s = THIS->subject_info(info); + + if(s.size() > 0) + RETVAL = const_cast<char *>(s[0].c_str()); + else + RETVAL = "err"; + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +Botan__X509_DN * +Botan__X509_Certificate::subject_dn() + CODE: + try { + RETVAL = new Botan__X509_DN(THIS->subject_dn()); + } + catch (const std::exception &e) { + croak(e.what()); + } + char const * CLASS = "Botan::X509_DN"; + OUTPUT: + RETVAL + +Botan__X509_DN * +Botan__X509_Certificate::issuer_dn() + CODE: + try { + RETVAL = new Botan__X509_DN(THIS->issuer_dn()); + } + catch (const std::exception &e) { + croak(e.what()); + } + char const * CLASS = "Botan::X509_DN"; + OUTPUT: + RETVAL + + +# ============================== Botan::X509_DN ============================== + +MODULE = Botan PACKAGE = Botan::X509_DN + +Botan__X509_DN * +Botan__X509_DN::new() + CODE: + try { + RETVAL = new Botan__X509_DN(); + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL + +void +Botan__X509_DN::DESTROY() + CODE: + try { + delete THIS; + } + catch (const std::exception &e) { + croak(e.what()); + } + +AV * +Botan__X509_DN::get_attributes() + CODE: + try { + using namespace std; + using namespace Botan; + + typedef multimap<OID, string>::const_iterator rdn_iter; + + multimap<OID, string> const &atrmmap = THIS->get_attributes(); + RETVAL = newAV(); + for(rdn_iter i = atrmmap.begin(); i != atrmmap.end(); i++) + { + string const &atr = i->first.as_string(); + string const &val = i->second; + av_push(RETVAL, newSVpvn(atr.c_str(), atr.length())); + av_push(RETVAL, newSVpvn(val.c_str(), val.length())); + } + } + catch (const std::exception &e) { + croak(e.what()); + } + OUTPUT: + RETVAL diff --git a/wrappers/perl-xs/Changes b/wrappers/perl-xs/Changes new file mode 100644 index 000000000..5f32b0c63 --- /dev/null +++ b/wrappers/perl-xs/Changes @@ -0,0 +1,4 @@ +Revision history for Perl extension to Botan. + +0.01 Fri, 20 Feb 2004 15:10:50 +0100 + - first version diff --git a/wrappers/perl-xs/MANIFEST b/wrappers/perl-xs/MANIFEST new file mode 100644 index 000000000..b9d8454d6 --- /dev/null +++ b/wrappers/perl-xs/MANIFEST @@ -0,0 +1,15 @@ +Botan.pm +Botan.xs +Changes +MANIFEST +Makefile.PL +data/ca.cert.der +data/ca.cert.pem +t/base64.t +t/filt.t +t/hex.t +t/oid.t +t/pipe.t +t/testutl.pl +t/x509cert.t +typemap diff --git a/wrappers/perl-xs/Makefile.PL b/wrappers/perl-xs/Makefile.PL new file mode 100644 index 000000000..d35c99168 --- /dev/null +++ b/wrappers/perl-xs/Makefile.PL @@ -0,0 +1,29 @@ +use ExtUtils::MakeMaker; + +my ($cc, $cflags, $lids); +if ( $^O eq 'MSWin32' ) +{ +# $cflags = ''; +# $libs = ':nosearch -lgdi32 -llibeay32'; +} +else +{ + $cc = 'g++'; + $cflags = '-fexceptions ' . qx( botan-config --cflags ); + $libs = qx( botan-config --libs ); +} + +WriteMakefile( + 'NAME' => 'Botan', + 'DISTNAME' => 'Botan-XS', + 'VERSION_FROM' => 'Botan.pm', # finds $VERSION + 'XSOPT' => '-C++', + 'CC' => $cc, + 'LD' => '$(CC)', + 'CCFLAGS' => $cflags, + 'LIBS' => [ $libs ], + 'OPTIMIZE' => '-g', +# 'clean' => { +# 'FILES' => 'neco.p12 rnd', +# }, +); diff --git a/wrappers/perl-xs/data/ca.cert.der b/wrappers/perl-xs/data/ca.cert.der Binary files differnew file mode 100644 index 000000000..d6ed8aeaf --- /dev/null +++ b/wrappers/perl-xs/data/ca.cert.der diff --git a/wrappers/perl-xs/data/ca.cert.pem b/wrappers/perl-xs/data/ca.cert.pem new file mode 100644 index 000000000..012913b26 --- /dev/null +++ b/wrappers/perl-xs/data/ca.cert.pem @@ -0,0 +1,17 @@ +-----BEGIN CERTIFICATE----- +MIICxDCCAi2gAwIBAgIBEjANBgkqhkiG9w0BAQUFADBSMQswCQYDVQQGEwJDWjER +MA8GA1UEChMISUNaIGEucy4xGDAWBgNVBAMTD1Rlc3QgcHJpbWFyeSBDQTEWMBQG +CSqGSIb3DQEJARYHY2FAaS5jejAeFw0wMDA4MjAyMTQ4MDBaFw0wMjA4MTAyMTQ4 +MDBaME8xCzAJBgNVBAYTAkNaMREwDwYDVQQKEwhJQ1ogYS5zLjEVMBMGA1UEAxMM +VGVzdCBzaWduIENBMRYwFAYJKoZIhvcNAQkBFgdjYUBpLmN6MIGfMA0GCSqGSIb3 +DQEBAQUAA4GNADCBiQKBgQCo2GReNqwU0/8bZZua5hgYaVHvD9QAmfILNXD25jRk +C8lqe5m/GzbmftSUso5HyUy1t+qzvRDTmxK8uRn0P00Mqj9gjwF8PGQvZE/FrDF7 +rta9GCcH4n2GfQ0iexlhRZW44AfOD4HCgq38Z0bzBclsvUslBWe1AT+S5+chZ5Wb +UwIDAQABo4GsMIGpMAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFLXqc1b1DOfGehii +k4Z+/ih9BYZmMHoGA1UdIwRzMHGAFL7x2ToS4RDAbDJu4fHnzzGjfGmgoVakVDBS +MQswCQYDVQQGEwJDWjERMA8GA1UEChMISUNaIGEucy4xGDAWBgNVBAMTD1Rlc3Qg +cHJpbWFyeSBDQTEWMBQGCSqGSIb3DQEJARYHY2FAaS5jeoIBADANBgkqhkiG9w0B +AQUFAAOBgQAKD9ku9kKXUGhSw8KuWJXTnEsIUzDtgmREBEUOtEvGfU45vogWN7ZL +9fQZ1deywN4RJ4T5ZTTcCTPodOdG+IXLJ+uPn/m9iQ/D86c3GKS3yx4JNAn5PH1m +qLsMYVjbFD2uREZQsqbg3RT6L1D8+oK0pN379u3bD6oJx/qa7+F4Jg== +-----END CERTIFICATE----- diff --git a/wrappers/perl-xs/t/base64.t b/wrappers/perl-xs/t/base64.t new file mode 100644 index 000000000..f0973e13e --- /dev/null +++ b/wrappers/perl-xs/t/base64.t @@ -0,0 +1,273 @@ +# vim: set ft=perl: +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..24\n"; } +END { print "not ok 1\n" unless $loaded; } + +require 't/testutl.pl'; +use Botan; + +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +use strict; + +# Data prep + +my $botan_lic_b64_garbage = <<'EOF'; +Q29weXJpZ2h0IChDKSAxOTk5LTIwMDQgVGhlIEJvdGFuIFByb2plY3QuIEFsbCBy__� +aWdodHMgcmVzZXJ2ZWQuCgpSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJj$$*: +ZSBhbmQgYmluYXJ5IGZvcm1zLCBmb3IgYW55IHVzZSwgd2l0aCBvciB3aXRob3V0!@#$%^&*( +Cm1vZGlmaWNhdGlvbiwgaXMgcGVybWl0dGVkIHByb3ZpZGVkIHRoYXQgdGhlIGZv[\] +bGxvd2luZyBjb25kaXRpb25zIGFyZSBtZXQ6CgoxLiBSZWRpc3RyaWJ1dGlvbnMg'~` +b2Ygc291cmNlIGNvZGUgbXVzdCByZXRhaW4gdGhlIGFib3ZlIGNvcHlyaWdodCBu() +b3RpY2UsIHRoaXMKbGlzdCBvZiBjb25kaXRpb25zLCBhbmQgdGhlIGZvbGxvd2lu +ZyBkaXNjbGFpbWVyLgoKMi4gUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3Jt +IG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlLAp0aGlz +IGxpc3Qgb2YgY29uZGl0aW9ucywgYW5kIHRoZSBmb2xsb3dpbmcgZGlzY2xhaW1l +ciBpbiB0aGUgZG9jdW1lbnRhdGlvbgphbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHBy_,^ +b3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi4KClRISVMgU09GVFdBUkUgSVMg{|}~~~~~ +UFJPVklERUQgQlkgVEhFIEFVVEhPUihTKSAiQVMgSVMiIEFORCBBTlkgRVhQUkVT~~~~~~~~ +UyBPUiBJTVBMSUVECldBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1J__:; +VEVEIFRPLCBUSEUgSU1QTElFRCBXQVJSQU5USUVTIE9GCk1FUkNIQU5UQUJJTElU +WSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UsIEFSRSBESVND +TEFJTUVELgoKSU4gTk8gRVZFTlQgU0hBTEwgVEhFIEFVVEhPUihTKSBPUiBDT05U +UklCVVRPUihTKSBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsCklORElSRUNULCBJ +TkNJREVOVEFMLCBTUEVDSUFMLCBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwg +REFNQUdFUyAoSU5DTFVESU5HLApCVVQgTk9UIExJTUlURUQgVE8sIFBST0NVUkVN +RU5UIE9GIFNVQlNUSVRVVEUgR09PRFMgT1IgU0VSVklDRVM7IExPU1MgT0YgVVNF +LApEQVRBLCBPUiBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhP +V0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZIE9GCkxJQUJJTElUWSwgV0hF +VEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVCAoSU5D +TFVESU5HIE5FR0xJR0VOQ0UKT1IgT1RIRVJXSVNFKSBBUklTSU5HIElOIEFOWSBX +QVkgT1VUIE9GIFRIRSBVU0UgT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRgpBRFZJ +U0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS4K +EOF + +my $botan_lic_b64_ws = $botan_lic_b64_garbage; +$botan_lic_b64_ws =~ s/[^A-Za-z0-9+\/= \n]//g; + +my $botan_lic_b64 = $botan_lic_b64_ws; +$botan_lic_b64 =~ s/[ \n]//g; + + +my $botan_lic = <<'EOF'; +Copyright (C) 1999-2004 The Botan Project. All rights reserved. + +Redistribution and use in source and binary forms, for any use, with or without +modification, is permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions, and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions, and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE DISCLAIMED. + +IN NO EVENT SHALL THE AUTHOR(S) OR CONTRIBUTOR(S) BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +EOF + + +# Decoder... + +my $f; + +eval { $f = Botan::Base64_Decoder->new(&Botan::NONE); }; +print "not " if $@ || !defined $f; +print "ok 2\n"; + +my $dec; +eval { $dec = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $dec; +print "ok 3\n"; + +eval { $f = Botan::Base64_Decoder->new(&Botan::IGNORE_WS); }; +print "not " if $@ || !defined $f; +print "ok 4\n"; + +my $dec_is; +eval { $dec_is = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $dec_is; +print "ok 5\n"; + +eval { $f = Botan::Base64_Decoder->new(&Botan::FULL_CHECK); }; +print "not " if $@ || !defined $f; +print "ok 6\n"; + +my $dec_fc; +eval { $dec_fc = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $dec_fc; +print "ok 7\n"; + + +# Testing clean base64 input + +my $data; + +undef $data; +eval { + $dec->process_msg($botan_lic_b64); + $data = $dec->read(); +}; + +print "not " if $@ || $data ne $botan_lic; +print "ok 8\n"; + +undef $data; +eval { + $dec_is->process_msg($botan_lic_b64); + $data = $dec_is->read(); +}; + +print "not " if $@ || $data ne $botan_lic; +print "ok 9\n"; + +undef $data; +eval { + $dec_fc->process_msg($botan_lic_b64); + $data = $dec_fc->read(); +}; + +print "not " if $@ || $data ne $botan_lic; +print "ok 10\n"; + + +# Testing base64 input with whitespaces + +undef $data; +eval { + $dec->process_msg($botan_lic_b64_ws); + $dec->set_default_msg(1); + $data = $dec->read(); +}; + +print "not " if $@ || $data ne $botan_lic; +print "ok 11\n"; + +undef $data; +eval { + $dec_is->process_msg($botan_lic_b64_ws); + $dec_is->set_default_msg(1); + $data = $dec_is->read(); +}; + +print "not " if $@ || $data ne $botan_lic; +print "ok 12\n"; + +undef $data; +eval { + $dec_fc->process_msg($botan_lic_b64_ws); + $dec_fc->set_default_msg(1); + $data = $dec_fc->read(); +}; + +print "not " unless $@ && !defined $data; +print "ok 13\n"; + + +# Testing base64 input with garbage + +undef $data; +eval { + $dec->process_msg($botan_lic_b64_garbage); + $dec->set_default_msg(2); + $data = $dec->read(); +}; + +print "not " if $@ || $data ne $botan_lic; +print "ok 14\n"; + +undef $data; +eval { + $dec_is->process_msg($botan_lic_b64_garbage); + $dec_is->set_default_msg(2); + $data = $dec_is->read(); +}; + +print "not " unless $@ && !defined $data; +print "ok 15\n"; + +undef $data; +eval { + $dec_fc->process_msg($botan_lic_b64_garbage); + $dec_fc->set_default_msg(2); + $data = $dec_fc->read(); +}; + +print "not " unless $@ && !defined $data; +print "ok 16\n"; + + +# Encoder... + +eval { $f = Botan::Base64_Encoder->new(); }; +print "not " if $@ || !defined $f; +print "ok 17\n"; + +my $enc; +eval { $enc = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $enc; +print "ok 18\n"; + +eval { $f = Botan::Base64_Encoder->new(1, 5); }; +print "not " if $@ || !defined $f; +print "ok 19\n"; + +my $enc2; +eval { $enc2 = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $enc2; +print "ok 20\n"; + +undef $data; +eval { + $enc->process_msg("Hello\n"); + $data = $enc->read(); +}; +print "not " if $@ || $data ne "SGVsbG8K"; +print "ok 21\n"; + +undef $data; +eval { + $enc2->process_msg("Hello\n"); + $data = $enc2->read(); +}; +print "not " if $@ || $data ne "SGVsb\nG8K\n"; +print "ok 22\n"; + + +# Encoder with decoder... + +my $p; +eval { + $p = Botan::Pipe->new( + Botan::Base64_Encoder->new(), + Botan::Base64_Decoder->new(), + ); +}; +print "not " if $@ || !defined $p; +print "ok 23\n"; + +print "not " unless random_message_ok($p); +print "ok 24\n"; diff --git a/wrappers/perl-xs/t/filt.t b/wrappers/perl-xs/t/filt.t new file mode 100644 index 000000000..2a7b4c8ba --- /dev/null +++ b/wrappers/perl-xs/t/filt.t @@ -0,0 +1,56 @@ +# vim: set ft=perl: +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..5\n"; } +END { print "not ok 1\n" unless $loaded; } + +use Botan; + +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +use strict; + +my $pipe = Botan::Pipe->new(Botan::Hex_Encoder->new()); + +print "not " unless $pipe; +print "ok 2\n"; + +$pipe->process_msg('FOO'); + +print "not " if $pipe->read() ne '464F4F'; +print "ok 3\n"; + +$pipe = Botan::Pipe->new(Botan::Hex_Encoder->new(0, 0, 1)); + +print "not " unless $pipe; +print "ok 4\n"; + +$pipe->process_msg('FOO'); + +print "not " if $pipe->read() ne '464f4f'; +print "ok 5\n"; + + + + + + +#my $pipe = Botan::Pipe->new(Botan::Base64_Encoder->new()); +#$pipe->process_msg('FOO'); +# +#print "not " if $pipe->read() ne 'Rk9P'; +#print "ok 4\n"; + diff --git a/wrappers/perl-xs/t/hex.t b/wrappers/perl-xs/t/hex.t new file mode 100644 index 000000000..6f447b25c --- /dev/null +++ b/wrappers/perl-xs/t/hex.t @@ -0,0 +1,256 @@ +# vim: set ft=perl: +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..24\n"; } +END { print "not ok 1\n" unless $loaded; } + +require 't/testutl.pl'; +use Botan; + +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +use strict; + +# Data prep + +my ($hex, $hex_ws, $hex_garbage); +while ( $_ = <DATA> ) +{ + $hex_garbage .= $_; + s/[^[:xdigit:][:space:]]//g; + $hex_ws .= $_; + s/[^[:xdigit:]]//g; + $hex .= $_; +} +my $data_test = pack("H*", $hex); + +# Decoder... + +my $f; + +eval { $f = Botan::Hex_Decoder->new(&Botan::NONE); }; +print "not " if $@ || !defined $f; +print "ok 2\n"; + +my $dec; +eval { $dec = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $dec; +print "ok 3\n"; + +eval { $f = Botan::Hex_Decoder->new(&Botan::IGNORE_WS); }; +print "not " if $@ || !defined $f; +print "ok 4\n"; + +my $dec_is; +eval { $dec_is = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $dec_is; +print "ok 5\n"; + +eval { $f = Botan::Hex_Decoder->new(&Botan::FULL_CHECK); }; +print "not " if $@ || !defined $f; +print "ok 6\n"; + +my $dec_fc; +eval { $dec_fc = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $dec_fc; +print "ok 7\n"; + + +# Testing clean hexadecimal input + +my $data; + +undef $data; +eval { + $dec->process_msg($hex); + $data = $dec->read(); +}; + +print "not " if $@ || $data ne $data_test; +print "ok 8\n"; + +undef $data; +eval { + $dec_is->process_msg($hex); + $data = $dec_is->read(); +}; + +print "not " if $@ || $data ne $data_test; +print "ok 9\n"; + +undef $data; +eval { + $dec_fc->process_msg($hex); + $data = $dec_fc->read(); +}; + +print "not " if $@ || $data ne $data_test; +print "ok 10\n"; + + +# Testing hexadecimal input with whitespaces + +undef $data; +eval { + $dec->process_msg($hex_ws); + $dec->set_default_msg(1); + $data = $dec->read(); +}; + +print "not " if $@ || $data ne $data_test; +print "ok 11\n"; + +undef $data; +eval { + $dec_is->process_msg($hex_ws); + $dec_is->set_default_msg(1); + $data = $dec_is->read(); +}; + +print "not " if $@ || $data ne $data_test; +print "ok 12\n"; + +undef $data; +eval { + $dec_fc->process_msg($hex_ws); + $dec_fc->set_default_msg(1); + $data = $dec_fc->read(); +}; + +print "not " unless $@ && !defined $data; +print "ok 13\n"; + + +# Testing hexadecimal input with garbage + +undef $data; +eval { + $dec->process_msg($hex_garbage); + $dec->set_default_msg(2); + $data = $dec->read(); +}; + +print "not " if $@ || $data ne $data_test; +print "ok 14\n"; + +undef $data; +eval { + $dec_is->process_msg($hex_garbage); + $dec_is->set_default_msg(2); + $data = $dec_is->read(); +}; + +print "not " unless $@ && !defined $data; +print "ok 15\n"; + +undef $data; +eval { + $dec_fc->process_msg($hex_garbage); + $dec_fc->set_default_msg(2); + $data = $dec_fc->read(); +}; + +print "not " unless $@ && !defined $data; +print "ok 16\n"; + + +# Encoder... + +eval { $f = Botan::Hex_Encoder->new(); }; +print "not " if $@ || !defined $f; +print "ok 17\n"; + +my $enc; +eval { $enc = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $enc; +print "ok 18\n"; + +eval { $f = Botan::Hex_Encoder->new(1, 5, 1); }; +print "not " if $@ || !defined $f; +print "ok 19\n"; + +my $enc2; +eval { $enc2 = Botan::Pipe->new($f); }; +print "not " if $@ || !defined $enc2; +print "ok 20\n"; + +undef $data; +eval { + $enc->process_msg("Hello\n"); + $data = $enc->read(); +}; +print "not " if $@ || $data ne "48656C6C6F0A"; +print "ok 21\n"; + +undef $data; +eval { + $enc2->process_msg("Hello\n"); + $data = $enc2->read(); +}; +print "not " if $@ || $data ne "48656\nc6c6f\n0a\n"; +print "ok 22\n"; + + +# Encoder with decoder... + +my $p; +eval { + $p = Botan::Pipe->new( + Botan::Hex_Encoder->new(), + Botan::Hex_Decoder->new(), + ); +}; +print "not " if $@ || !defined $p; +print "ok 23\n"; + +print "not " unless random_message_ok($p); +print "ok 24\n"; + + + +__DATA__ +cb13 4a4d 7522 1fd3 c6f6 7786 d04b 3043 ..JMu"....w..K.. +4552 4bcf 4d2b 9d71 0cfe 4d6a 1caf bcfd .RK.M+.q..Mj.... +8f91 6151 ff85 e900 7e6a bafc 15e9 ae51 ...Q....~j.....Q +b14b 7210 bb40 5958 2b82 d49e b808 68a5 .Kr..@YX+.....h. +7945 9dec f686 9b98 989e 826d 8088 6ee7 y..........m..n. +d066 1eac 8c34 c461 bb54 7726 87ab d681 .........Tw&.... +a0be 52e5 1128 0cf2 759e cb2d e690 4ed9 ..R..(..u..-..N. +7e88 bda7 2523 4a0f 185a 02b1 f898 fc41 ~...%#J..Z...... +dd48 fa87 945d 7611 b8c9 a50a 2de2 b670 .H...]v.....-..p +0056 c8be 2cbb e7d0 1e70 4a3d 79f0 dce9 .V..,....pJ=y... +b57f 154b 2b3a db73 f086 de11 9f3e 1641 ...K+:.s.....>.. +3a28 8b9b bb0f 682b 80db b791 89e0 62c0 :(....h+........ +7204 db97 5432 2eb0 a04e f38e 809f 7223 r...T....N....r# +912e e552 1452 6dd2 e09f dd06 c715 7c1a ...R.Rm.......|. +fe3d d6cc b6d0 a17a 27d7 4327 4e43 8af3 .=.....z'..'N... +6eb5 e9f8 bfe9 34c3 6636 8243 358f 966d n..............m +7d87 d17b 5c37 6acb 4972 f4ec 6806 bbde }..{\.j.Ir..h... +2689 a019 a9e2 4101 7fe2 de72 bc03 eb5e &..........r...^ +b699 2d6b f8cd a08e 6e01 edfc a81a 94b6 ..-k....n....... +9073 15fb efb2 c8d9 9f85 6633 85f1 e9d0 .s.............. +20ce 578b ab9d 2e51 b947 69bf fba5 82c6 .W....Q.Gi..... +2ed0 dd36 d679 a399 7db3 8a0d cdef 0eda .....y..}....... +e761 e7f1 5b17 3f67 0c83 215a eddf 9d2a ....[.?g..!Z...* +5e70 0a77 c92e 94e1 a82b fd7c f10a 894f ^p.w.....+.|...O +2955 f0e8 7398 f409 2040 b797 da03 a5a6 )U..s... @...... +7ba4 c3c9 2659 b9f7 6a56 e17a b481 983f {...&Y..jV.z...? +00ed 3cc8 5a22 ad5c b6e0 3566 d717 35a6 ..<.Z".\........ +1523 4104 de63 477e fd24 68e5 e816 98df .#....G~.$h..... +1747 417e db72 a76a be5b b9dc 3dfb 2d05 .G.~.r.j.[..=.-. +d27f e597 eafc 9a29 15c5 792d 9c88 9aea .......)..y-.... +485e e431 96c3 7723 da6d 28b2 477a fd12 H^....w#.m(.Gz.. +e645 5dcd 7d5a d8b4 7acc 10b2 b41a e11d ..].}Z..z....... diff --git a/wrappers/perl-xs/t/oid.t b/wrappers/perl-xs/t/oid.t new file mode 100644 index 000000000..66204541f --- /dev/null +++ b/wrappers/perl-xs/t/oid.t @@ -0,0 +1,45 @@ +# vim: set ft=perl: +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..6\n"; } +END { print "not ok 1\n" unless $loaded; } + +use Botan; + +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +use strict; + +print "not " unless Botan::OIDS::have_oid('X520.CommonName'); +print "ok 2\n"; + +my $oid_c = Botan::OID->new('2.5.4.3'); +print "not " if Botan::OIDS::lookup_by_oid($oid_c) ne 'X520.CommonName'; +print "ok 3\n"; + +my $oid_x = Botan::OIDS::lookup_by_name('X520.CommonName'); +print "not " if $oid_x->as_string() ne '2.5.4.3'; +print "ok 4\n"; + +my $oid_foo_num = '1.2.3.4.5.6.7.8.9.10.11.12.13.14.15'; +my $oid_foo = Botan::OID->new($oid_foo_num); +print "not " if Botan::OIDS::lookup_by_oid($oid_foo) ne $oid_foo_num; +print "ok 5\n"; + +Botan::OIDS::add_oid($oid_foo, 'Zito.Foo'); + +print "not " if Botan::OIDS::lookup_by_oid($oid_foo) ne 'Zito.Foo'; +print "ok 6\n"; diff --git a/wrappers/perl-xs/t/pipe.t b/wrappers/perl-xs/t/pipe.t new file mode 100644 index 000000000..f850d8519 --- /dev/null +++ b/wrappers/perl-xs/t/pipe.t @@ -0,0 +1,98 @@ +# vim: set ft=perl: +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..20\n"; } +END { print "not ok 1\n" unless $loaded; } + +use Botan; + +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +use strict; + +my $pipe = Botan::Pipe->new(); + +print "not " unless $pipe; +print "ok 2\n"; + +$pipe->start_msg(); +$pipe->write('Hello world'); +$pipe->end_msg(); + +print "not " if $pipe->message_count() != 1; +print "ok 3\n"; + +print "not " if $pipe->remaining() != 11; +print "ok 4\n"; + +print "not " if $pipe->end_of_data(); +print "ok 5\n"; + +print "not " if $pipe->read() ne 'Hello world'; +print "ok 6\n"; + +print "not " if $pipe->remaining() != 0; +print "ok 7\n"; + +print "not " unless $pipe->end_of_data(); +print "ok 8\n"; + +$pipe->process_msg('Hello world'); + +print "not " if $pipe->message_count() != 2; +print "ok 9\n"; + +my $msg_num = $pipe->message_count() -1; + +print "not " if $pipe->read(5, $msg_num) ne 'Hello'; +print "ok 10\n"; + +print "not " if $pipe->read(6, $msg_num) ne ' world'; +print "ok 11\n"; + +print "not " if $pipe->remaining() != 0; +print "ok 12\n"; + +print "not " unless $pipe->end_of_data(); +print "ok 13\n"; + +$pipe->process_msg("The\0string\0with\0null\0chars\0"); +$msg_num = $pipe->message_count() -1; + +print "not " if $pipe->read(80, $msg_num) ne "The\0string\0with\0null\0chars\0"; +print "ok 14\n"; + +$pipe->process_msg('FOO BAR'); +$pipe->set_default_msg($pipe->message_count() -1); + +print "not " if $pipe->peek(3) ne 'FOO'; +print "ok 15\n"; + +print "not " if $pipe->peek(3, 4) ne 'BAR'; +print "ok 16\n"; + +print "not " if $pipe->peek() ne 'FOO BAR'; +print "ok 17\n"; + +print "not " if $pipe->read() ne 'FOO BAR'; +print "ok 18\n"; + +print "not " if $pipe->remaining() != 0; +print "ok 19\n"; + +print "not " unless $pipe->end_of_data(); +print "ok 20\n"; + diff --git a/wrappers/perl-xs/t/testutl.pl b/wrappers/perl-xs/t/testutl.pl new file mode 100644 index 000000000..add6f6a45 --- /dev/null +++ b/wrappers/perl-xs/t/testutl.pl @@ -0,0 +1,26 @@ +#!/usr/bin/perl + +sub random_message_ok +{ + my ($pipe, $iter, $chunkmax) = @_; + $iter = 100 unless defined $iter; + $chunkmax = 300 unless defined $chunkmax; + eval { + my $input = ''; + $pipe->start_msg(); + for(my $i = 0; $i < $iter; $i++) + { + my $chunk = ''; + my $chunklen = int(rand($chunkmax)); + $chunk .= pack("C", int(rand(256))) while $chunklen--; + $input .= $chunk; + $pipe->write($chunk); + } + $pipe->end_msg(); + my $msg_num = $pipe->message_count() -1; + my $output = $pipe->read(0xFFFFFFFF, $msg_num); + return $input eq $output; + }; +} + +1; diff --git a/wrappers/perl-xs/t/x509cert.t b/wrappers/perl-xs/t/x509cert.t new file mode 100644 index 000000000..2a943aeac --- /dev/null +++ b/wrappers/perl-xs/t/x509cert.t @@ -0,0 +1,42 @@ +# vim: set ft=perl: +# Before `make install' is performed this script should be runnable with +# `make test'. After `make install' it should work as `perl test.pl' + +######################### We start with some black magic to print on failure. + +# Change 1..1 below to 1..last_test_to_print . +# (It may become useful if the test is moved to ./t subdirectory.) + +BEGIN { $| = 1; print "1..4\n"; } +END { print "not ok 1\n" unless $loaded; } + +use Botan; + +$loaded = 1; +print "ok 1\n"; + +######################### End of black magic. + +# Insert your test code below (better if it prints "ok 13" +# (correspondingly "not ok 13") depending on the success of chunk 13 +# of the test code): + +use strict; + +my $cert = Botan::X509_Certificate->new('data/ca.cert.der'); + +print "not " if $cert->x509_version() != 3; +print "ok 2\n"; + +print "not " if $cert->start_time() ne '2000/8/20 21:48:00 UTC'; +print "ok 3\n"; + +print "not " if $cert->end_time() ne '2002/8/10 21:48:00 UTC'; +print "ok 4\n"; + +#my $subject = $cert->subject_dn()->get_attributes(); +#print STDERR "subject=", join(',', @{$subject}), "\n"; +# +#my $issuer = $cert->issuer_dn()->get_attributes(); +#print STDERR "issuer=", join(',', @{$issuer}), "\n"; +# diff --git a/wrappers/perl-xs/typemap b/wrappers/perl-xs/typemap new file mode 100644 index 000000000..d7403d40d --- /dev/null +++ b/wrappers/perl-xs/typemap @@ -0,0 +1,62 @@ +TYPEMAP + +Botan__ASN1_String * O_OBJECT +Botan__AlgorithmIdentifier * O_OBJECT +Botan__AlternativeName * O_OBJECT +Botan__Attribute * O_OBJECT +Botan__Base64_Decoder * O_EXTOBJECT +Botan__Base64_Encoder * O_EXTOBJECT +Botan__Chain * O_EXTOBJECT +Botan__Extension * O_OBJECT +Botan__Filter * O_EXTOBJECT +Botan__Fork * O_EXTOBJECT +Botan__Hex_Decoder * O_EXTOBJECT +Botan__Hex_Encoder * O_EXTOBJECT +Botan__OID * O_OBJECT +Botan__Pipe * O_OBJECT +Botan__X509_Certificate * O_OBJECT +Botan__X509_DN * O_OBJECT +Botan__X509_Time * O_OBJECT +Botan__u32bit T_UV + + +###################################################################### +OUTPUT + +# The Perl object is blessed into 'CLASS', which should be a +# char* having the name of the package for the blessing. +O_OBJECT + sv_setref_pv($arg, CLASS, (void*)$var); + +O_EXTOBJECT + sv_setref_pv($arg, CLASS, (void*)$var); + sv_magic(SvRV($arg), 0, '~', (char *)&oi_init, sizeof(oi_init)); + + +###################################################################### +INPUT + +O_OBJECT + if ( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) + $var = ($type)SvIV((SV*)SvRV( $arg )); + else + croak(\"${Package}::$func_name() -- \" + \"$var is not a blessed SV reference\"); + +# The pointer variable "ObjectInfo *${var}_oi;" must be declared +# in PREINIT section. I don't know how to emit this declaration safely here. +O_EXTOBJECT + if ( sv_isobject($arg) && (SvTYPE(SvRV($arg)) == SVt_PVMG) ) + $var = ($type)SvIV((SV*)SvRV($arg)); + else + croak(\"${Package}::$func_name() -- \" + \"$var is not a blessed SV reference\"); + { + MAGIC *mg = mg_find(SvRV($arg), '~'); + if ( mg == 0 + || mg->mg_len != sizeof(ObjectInfo) + || *(I32 *)(mg->mg_ptr) != ObjectInfo::SIGNVAL ) + croak(\"${Package}::$func_name() -- \" + \"private magic data for $var invalid\"); + ${var}_oi = (ObjectInfo *)(mg->mg_ptr); + } diff --git a/wrappers/swig/Makefile b/wrappers/swig/Makefile new file mode 100644 index 000000000..ff55c793c --- /dev/null +++ b/wrappers/swig/Makefile @@ -0,0 +1,32 @@ +LANG=-python +LANG_INC=/usr/include/python2.3 + +CFLAGS=$(shell botan-config --cflags) +LIBS=$(shell botan-config --libs) + +CXX = g++ -g +SWIG = swig -Wall + +all: _botan.so + +_botan.so: base.o pipe.o filter.o botan_wrap.o + $(CXX) -shared $^ $(LIBS) -o $@ + +botan_wrap.cpp: botan.swg base.h + $(SWIG) $(LANG) -c++ -o $@ $< + +botan_wrap.o: botan_wrap.cpp + $(CXX) $(CFLAGS) -I$(LANG_INC) -c $^ -o $@ + +base.o: base.cpp base.h + $(CXX) $(CFLAGS) -c $< -o $@ + +pipe.o: pipe.cpp base.h + $(CXX) $(CFLAGS) -c $< -o $@ + +filter.o: filter.cpp base.h + $(CXX) $(CFLAGS) -c $< -o $@ + +clean: + rm -f *.o _botan.so botan.py botan.pyc + rm -f *_wrap.o *_wrap.cpp diff --git a/wrappers/swig/base.cpp b/wrappers/swig/base.cpp new file mode 100644 index 000000000..2550b915b --- /dev/null +++ b/wrappers/swig/base.cpp @@ -0,0 +1,61 @@ +/************************************************* +* SWIG Interface for basic Botan interface * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include "base.h" +#include <botan/init.h> + +#include <stdio.h> + +/************************************************* +* Initialize the library * +*************************************************/ +LibraryInitializer::LibraryInitializer(const char* args) + { + Botan::Init::initialize(args); + } + +/************************************************* +* Shut down the library * +*************************************************/ +LibraryInitializer::~LibraryInitializer() + { + Botan::Init::deinitialize(); + } + +/************************************************* +* Create a SymmetricKey * +*************************************************/ +SymmetricKey::SymmetricKey(const std::string& str) + { + key = new Botan::SymmetricKey(str); + printf("STR CON: %p %p\n", this, key); + } + +/************************************************* +* Create a SymmetricKey * +*************************************************/ +SymmetricKey::SymmetricKey(u32bit n) + { + key = new Botan::SymmetricKey(n); + printf("N CON: %p %p\n", this, key); + } + +/************************************************* +* Destroy a SymmetricKey * +*************************************************/ +SymmetricKey::~SymmetricKey() + { + printf("DESTR: %p %p\n", this, key); + delete key; + key = 0; + //printf("deleted\n"); + } + +/************************************************* +* Create an InitializationVector * +*************************************************/ +InitializationVector::InitializationVector(const std::string& str) : iv(str) + { + } diff --git a/wrappers/swig/base.h b/wrappers/swig/base.h new file mode 100644 index 000000000..c3fd8426e --- /dev/null +++ b/wrappers/swig/base.h @@ -0,0 +1,102 @@ +/************************************************* +* SWIG Interface for Botan * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#ifndef BOTAN_WRAP_BASE_H__ +#define BOTAN_WRAP_BASE_H__ + +#include <botan/pipe.h> + +#if !defined(SWIG) + #define OUTPUT + #define INOUT +#endif + +/************************************************* +* Typedefs * +*************************************************/ +typedef unsigned char byte; +typedef unsigned int u32bit; + +/************************************************* +* Library Initalization/Shutdown Object * +*************************************************/ +class LibraryInitializer + { + public: + LibraryInitializer(const char*); + ~LibraryInitializer(); + }; + +/************************************************* +* Symmetric Key Object * +*************************************************/ +class SymmetricKey + { + public: + std::string as_string() const { return key->as_string(); } + u32bit length() const { return key->length(); } + SymmetricKey(u32bit = 0); + SymmetricKey(const std::string&); + ~SymmetricKey(); + private: + Botan::SymmetricKey* key; + }; + +/************************************************* +* Initialization Vector Object * +*************************************************/ +class InitializationVector + { + public: + std::string as_string() const { return iv.as_string(); } + u32bit length() const { return iv.length(); } + InitializationVector(u32bit n = 0) { iv.change(n); } + InitializationVector(const std::string&); + private: + Botan::InitializationVector iv; + }; + +/************************************************* +* Filter Object * +*************************************************/ +class Filter + { + public: + Filter(const char*); + //Filter(const char*, const SymmetricKey&); + //Filter(const char*, const SymmetricKey&, const InitializationVector&); + ~Filter(); + private: + friend class Pipe; + Botan::Filter* filter; + bool pipe_owns; + }; + +/************************************************* +* Pipe Object * +*************************************************/ +class Pipe + { + public: + static const u32bit DEFAULT_MESSAGE = 0xFFFFFFFF; + + void write_file(const char*); + void write_string(const char*); + + u32bit read(byte*, u32bit, u32bit = DEFAULT_MESSAGE); + std::string read_all_as_string(u32bit = DEFAULT_MESSAGE); + + u32bit remaining(u32bit = DEFAULT_MESSAGE); + + void start_msg(); + void end_msg(); + + Pipe(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + ~Pipe(); + private: + Botan::Pipe* pipe; + }; + +#endif diff --git a/wrappers/swig/botan.swg b/wrappers/swig/botan.swg new file mode 100644 index 000000000..9088f4272 --- /dev/null +++ b/wrappers/swig/botan.swg @@ -0,0 +1,26 @@ +/************************************************* +* SWIG Interface for Botan * +*************************************************/ +%module botan + +%include "typemaps.i" +%include "std_string.i" +%include "exception.i" +%include "constraints.i" +%include "carrays.i" + +%{ +#include "base.h" +%} + +%exception { + try { + $action + } + catch(std::exception& e) + { + SWIG_exception(SWIG_RuntimeError, e.what()); + } +} + +%include "base.h" diff --git a/wrappers/swig/doit.py b/wrappers/swig/doit.py new file mode 100755 index 000000000..98bc97087 --- /dev/null +++ b/wrappers/swig/doit.py @@ -0,0 +1,49 @@ +#!/usr/bin/python2 + +import botan + +def hash_it(hash, input): + f1 = botan.Filter("MD5") + f2 = botan.Filter("Hex_Encoder") + pipe = botan.Pipe(f1, f2) + + pipe.start_msg() + pipe.write_string(input) + pipe.end_msg() + + print pipe.remaining() + + out = pipe.read(0) + + + + +def main: + init = botan.LibraryInitializer + + print hash_it("MD5", "foo") + + + key1 = botan.SymmetricKey("ABCD") + print key1.as_string() + key2 = botan.SymmetricKey(16) + print key2.as_string() + + iv1 = botan.InitializationVector(8) + print iv1.as_string() + + + f3 = pipe.read(pipe.remaining()) + + size = pipe.remaining() + out = botan.byte_array(size) + pipe.read(out.cast,size) + + for i in range (0,size): + print "%02X" % out[i] + + print pipe.read_all_as_string() + +if __name__ == "__main__": + sys.exit(main()) + diff --git a/wrappers/swig/filter.cpp b/wrappers/swig/filter.cpp new file mode 100644 index 000000000..ec9ce6603 --- /dev/null +++ b/wrappers/swig/filter.cpp @@ -0,0 +1,39 @@ +/************************************************* +* SWIG Interface for Filter Retrieval * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include "base.h" +#include <botan/lookup.h> +#include <botan/filters.h> + +/************************************************* +* Filter Creation * +*************************************************/ +Filter::Filter(const char* filt_string) + { + filter = 0; + pipe_owns = false; + + /* + Fixme: This is all so totally wrong. It needs to have full argument + processing for everything, all that kind of crap. + */ + const std::string filt_name = filt_string; + + if(Botan::have_hash(filt_name)) + filter = new Botan::Hash_Filter(filt_name); + else if(filt_name == "Hex_Encoder") + filter = new Botan::Hex_Encoder; + } + +/************************************************* +* Filter Destruction * +*************************************************/ +Filter::~Filter() + { + /* + if(!pipe_owns) + delete filter; + */ + } diff --git a/wrappers/swig/pipe.cpp b/wrappers/swig/pipe.cpp new file mode 100644 index 000000000..2ccdd5dfd --- /dev/null +++ b/wrappers/swig/pipe.cpp @@ -0,0 +1,89 @@ +/************************************************* +* SWIG Interface for Botan Pipe API * +* (C) 1999-2003 The Botan Project * +*************************************************/ + +#include "base.h" +#include <botan/pipe.h> + +#include <stdio.h> + +/************************************************* +* Write the contents of a file into a Pipe * +*************************************************/ +void Pipe::write_file(const char* filename) + { + Botan::DataSource_Stream in(filename); + pipe->write(in); + } + +/************************************************* +* Write the contents of a string into a Pipe * +*************************************************/ +void Pipe::write_string(const char* string) + { + pipe->write(string); + } + +/************************************************* +* Read the contents of a Pipe into a buffer * +*************************************************/ +u32bit Pipe::read(byte* buf, u32bit length, u32bit msg) + { + printf("read %p %d\n", buf, length); + return 0; + //return pipe->read(buf, length, msg); + } + +/************************************************* +* Read the contents of a Pipe as a string * +*************************************************/ +std::string Pipe::read_all_as_string(u32bit msg) + { + return pipe->read_all_as_string(msg); + } + +/************************************************* +* Find out how much stuff the Pipe still has * +*************************************************/ +u32bit Pipe::remaining(u32bit msg) + { + return pipe->remaining(); + } + +/************************************************* +* Start a new message * +*************************************************/ +void Pipe::start_msg() + { + pipe->start_msg(); + } + +/************************************************* +* End the current msessage * +*************************************************/ +void Pipe::end_msg() + { + pipe->end_msg(); + } + +/************************************************* +* Create a new Pipe * +*************************************************/ +Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + pipe = new Botan::Pipe(); + + if(f1) { pipe->append(f1->filter); f1->pipe_owns = true; } + if(f2) { pipe->append(f2->filter); f2->pipe_owns = true; } + if(f3) { pipe->append(f3->filter); f3->pipe_owns = true; } + if(f4) { pipe->append(f4->filter); f4->pipe_owns = true; } + } + +/************************************************* +* Destroy this Pipe * +*************************************************/ +Pipe::~Pipe() + { + delete pipe; + } diff --git a/wrappers/swig/pk.swg b/wrappers/swig/pk.swg new file mode 100644 index 000000000..8e03cf120 --- /dev/null +++ b/wrappers/swig/pk.swg @@ -0,0 +1,8 @@ +%module botan + +%{ +#undef ANY +#include "botan/pubkey.h" +%} + +%include "botan/pubkey.h" diff --git a/wrappers/swig/readme.txt b/wrappers/swig/readme.txt new file mode 100644 index 000000000..a9965d914 --- /dev/null +++ b/wrappers/swig/readme.txt @@ -0,0 +1,34 @@ +This is the beginning of an attempt to SWIG-ify Botan so it can be accessed by +other languages. You should use the latest SWIG 1.3 release (I am currently +using SWIG 1.3.19). Currently I am only testing this code with Python 2.2.1, +since that is the language I am mainly interested in at this point. Feel free +to send me patches so this is usable with Perl or whatever. + +I'm not attempting to make everything in Botan usable from a script - +basically, I just want the parts that *I* want to use. Most things are not +supported yet, and there are lots of bugs in the stuff that does exist. If +there is something in particular that you would like to be able to use from a +script, let me know (patches are good, too). + +Todo: + * Why does it seg fault if we don't create a LibraryInitializer. It should + throw an exception, like it does in C++. Maybe have it init Botan when the + module is loaded? That seems a lot cleaner/nicer, but I don't know how to + do it yet. + * Lots of problems with exceptions + * Use constraints to prevent bad args when possible + * Pipe/Filter + - Better argument processing for all filters + - Support for ciphers, MACs, etc + - Chain + Fork + - Support for append/prepend/pop/reset in Pipe? + * Public Key Crypto + - RSA + - DSA + - DH + - Generic X.509 and PKCS #8 stuff + * PKI + - X.509 certs + CRLs + - PKCS #10 requests + - X.509 stores + - X.509 CA diff --git a/wrappers/swig/tests/block.py b/wrappers/swig/tests/block.py new file mode 100644 index 000000000..593937c81 --- /dev/null +++ b/wrappers/swig/tests/block.py @@ -0,0 +1,52 @@ +#!/usr/bin/python + +import botan, base64 + +class MyCipher(botan.BlockCipher): + def __init__(self): + botan.BlockCipher.__init__(self, 16, 16, 32, 8) + def encrypt(self, val): + print "encrypt", val + return val.swapcase() + def decrypt(self, val): + print "decrypt", val + return val.swapcase() + def set_key(self, key): + print "set_key", key + def clone(self): + print "cloning" + return MyCipher() + def name(self): + print "naming" + return "MyCipher" + +cipher = botan.BlockCipher("AES-128") + +print cipher.block_size +print cipher.keylength_min +print cipher.keylength_max +print cipher.keylength_mod +print cipher.name() + +for kl in range(1, 128): + if cipher.valid_keylength(kl): + print "1", + else: + print "0", +print +key = botan.SymmetricKey(16) + +cipher.set_key(key) +ciphertext = cipher.encrypt("ABCDEFGH12345678") +print base64.b16encode(ciphertext) + +cipher2 = cipher.clone() +cipher2.set_key(key) + +plaintext = cipher2.decrypt(ciphertext) +print plaintext + +botan.get_info(cipher) + +mycipher = MyCipher() +botan.get_info(mycipher) diff --git a/wrappers/swig/tests/block2.py b/wrappers/swig/tests/block2.py new file mode 100644 index 000000000..5faccaf9a --- /dev/null +++ b/wrappers/swig/tests/block2.py @@ -0,0 +1,44 @@ +#!/usr/bin/python + +import botan, base64 + +class MyCipher(botan.BlockCipherImpl): + def __init__(self): + botan.BlockCipherImpl.__init__(self, 8, 8, 16, 1) + + def name(self): + return "MyCipher" + + def encrypt(self, input): + return input.swapcase() + + def decrypt(self, input): + return input.swapcase() + + def set_key(self, key): + print "Got key",key + +def test(cipher): + print + print cipher + print "Testing", cipher.name() + print cipher.block_size + print cipher.keylength_min, cipher.keylength_max, cipher.keylength_mod + for i in range(1, 64): + if cipher.valid_keylength(i): + print "1", + else: + print "0", + print + cipher.set_key(botan.SymmetricKey(16)) + ciphertext = cipher.encrypt("aBcDeFgH" * (cipher.block_size / 8)) + print repr(ciphertext) + print cipher.decrypt(ciphertext) + +def main(): + test(botan.BlockCipher("Blowfish")) + test(MyCipher()) + test(botan.BlockCipher("AES")) + +if __name__ == "__main__": + main() diff --git a/wrappers/swig/tests/encrypt.py b/wrappers/swig/tests/encrypt.py new file mode 100644 index 000000000..9896777d4 --- /dev/null +++ b/wrappers/swig/tests/encrypt.py @@ -0,0 +1,37 @@ +#!/usr/bin/python + +import sys, botan + +def encrypt(input): + cipher_key = botan.SymmetricKey("AABB") + print cipher_key.length + cipher_key = botan.SymmetricKey("AABBCCDD") + print cipher_key.length + + cipher = botan.Filter("ARC4", key = cipher_key) + + pipe = botan.Pipe(cipher, botan.Filter("Hex_Encoder")) + + pipe.start_msg() + pipe.write(input) + pipe.end_msg() + + str = pipe.read_all() + print str + return str + +def decrypt(input): + pipe = botan.Pipe(botan.Filter("Hex_Decoder"), + botan.Filter("ARC4", + key = botan.SymmetricKey("AABBCCDD"))) + + pipe.process_msg(input) + return pipe.read_all() + +def main(): + ciphertext = encrypt("hi chappy") + print ciphertext + print decrypt(ciphertext) + +if __name__ == "__main__": + sys.exit(main()) diff --git a/wrappers/swig/tests/filter.py b/wrappers/swig/tests/filter.py new file mode 100644 index 000000000..2b65d9ff2 --- /dev/null +++ b/wrappers/swig/tests/filter.py @@ -0,0 +1,27 @@ +#!/usr/bin/python + +import sys, botan + +class MyFilter(botan.FilterObj): + def write(self, input): + print "MyFilter::write",input + self.send(input) + def start_msg(self): + print "MyFilter::start_msg" + def end_msg(self): + print "MyFilter::end_msg" + def __del__(self): + print "~MyFilter" + +def main(): + filter = MyFilter() + + pipe = botan.Pipe(botan.Filter("Hex_Encoder"), filter, + botan.Filter("Hex_Decoder")) + pipe.start_msg() + pipe.write("hi chappy") + pipe.end_msg() + print pipe.read_all() + +if __name__ == "__main__": + sys.exit(main()) diff --git a/wrappers/swig/tests/hash.py b/wrappers/swig/tests/hash.py new file mode 100644 index 000000000..930b8c81a --- /dev/null +++ b/wrappers/swig/tests/hash.py @@ -0,0 +1,30 @@ +#!/usr/bin/python + +import botan, base64, md5 + +class PyMD5(botan.HashFunctionImpl): + def name(self): + return "PyMD5" + def update(self, input): + self.md5.update(input) + def final(self): + output = self.md5.digest() + self.md5 = md5.new() + return output + def __init__(self): + botan.HashFunctionImpl.__init__(self, 16, 64) + self.md5 = md5.new() + +hash = botan.HashFunction("SHA-256") + +print hash.name() +print hash.digest_size + +hash.update("hi") +hash.update(" ") +hash.update("chappy") +print base64.b16encode(hash.final()) + +hash2 = PyMD5() +hash2.update("hi chappy") +print base64.b16encode(hash2.final()) diff --git a/wrappers/swig/tests/mac.py b/wrappers/swig/tests/mac.py new file mode 100644 index 000000000..6110b6102 --- /dev/null +++ b/wrappers/swig/tests/mac.py @@ -0,0 +1,12 @@ +#!/usr/bin/python + +import botan, base64 + +mac = botan.MAC("HMAC(SHA-512)") + +print mac.name +print mac.output_length + +mac.set_key(botan.SymmetricKey("abcd")) +mac.update("hi chappy") +print base64.b16encode(mac.final()) diff --git a/wrappers/swig/tests/pubkey.py b/wrappers/swig/tests/pubkey.py new file mode 100644 index 000000000..456c52069 --- /dev/null +++ b/wrappers/swig/tests/pubkey.py @@ -0,0 +1,10 @@ +#!/usr/bin/python + +import botan + +key = botan.X509_PublicKey("rsapub.pem") +print key +print key.key_id() +print key.max_input_bits +print key.algo +print key.oid diff --git a/wrappers/swig/tests/stream.py b/wrappers/swig/tests/stream.py new file mode 100644 index 000000000..59d3ffa16 --- /dev/null +++ b/wrappers/swig/tests/stream.py @@ -0,0 +1,17 @@ +#!/usr/bin/python + +import botan, base64 + +cipher = botan.StreamCipher("ARC4") + +print cipher.name + +key = botan.SymmetricKey(16) + +cipher.set_key(key) +ciphertext = cipher.crypt("hi chappy") + +cipher.set_key(key) +plaintext = cipher.crypt(ciphertext) + +print plaintext diff --git a/wrappers/swig/x509.swg b/wrappers/swig/x509.swg new file mode 100644 index 000000000..736d3a385 --- /dev/null +++ b/wrappers/swig/x509.swg @@ -0,0 +1,9 @@ +%module botan + +class X509_Certificate + { + public: + + + private: + }; |