diff options
Diffstat (limited to 'botan/src/filters')
25 files changed, 2724 insertions, 0 deletions
diff --git a/botan/src/filters/algo_filt.cpp b/botan/src/filters/algo_filt.cpp new file mode 100644 index 0000000..23f7a20 --- /dev/null +++ b/botan/src/filters/algo_filt.cpp @@ -0,0 +1,124 @@ +/* +* Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/filters.h> +#include <botan/libstate.h> +#include <algorithm> + +namespace Botan { + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name) : + buffer(DEFAULT_BUFFERSIZE) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + base_ptr = cipher = af.make_stream_cipher(sc_name); + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(StreamCipher* stream_cipher) : + buffer(DEFAULT_BUFFERSIZE) + { + base_ptr = cipher = stream_cipher; + } + +/* +* StreamCipher_Filter Constructor +*/ +StreamCipher_Filter::StreamCipher_Filter(const std::string& sc_name, + const SymmetricKey& key) : + buffer(DEFAULT_BUFFERSIZE) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + base_ptr = cipher = af.make_stream_cipher(sc_name); + cipher->set_key(key); + } + +/* +* Set the IV of a stream cipher +*/ +void StreamCipher_Filter::set_iv(const InitializationVector& iv) + { + cipher->resync(iv.begin(), iv.length()); + } + +/* +* Write data into a StreamCipher_Filter +*/ +void StreamCipher_Filter::write(const byte input[], u32bit length) + { + while(length) + { + u32bit copied = std::min(length, buffer.size()); + cipher->encrypt(input, buffer, copied); + send(buffer, copied); + input += copied; + length -= copied; + } + } + +/* +* Hash_Filter Constructor +*/ +Hash_Filter::Hash_Filter(const std::string& algo_spec, + u32bit len) : + OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + hash = af.make_hash_function(algo_spec); + } + +/* +* Complete a calculation by a Hash_Filter +*/ +void Hash_Filter::end_msg() + { + SecureVector<byte> output = hash->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +/* +* MAC_Filter Constructor +*/ +MAC_Filter::MAC_Filter(const std::string& mac_name, u32bit len) : + OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + base_ptr = mac = af.make_mac(mac_name); + } + +/* +* MAC_Filter Constructor +*/ +MAC_Filter::MAC_Filter(const std::string& mac_name, const SymmetricKey& key, + u32bit len) : OUTPUT_LENGTH(len) + { + Algorithm_Factory& af = global_state().algorithm_factory(); + base_ptr = mac = af.make_mac(mac_name); + mac->set_key(key); + } + +/* +* Complete a calculation by a MAC_Filter +*/ +void MAC_Filter::end_msg() + { + SecureVector<byte> output = mac->final(); + if(OUTPUT_LENGTH) + send(output, std::min(OUTPUT_LENGTH, output.size())); + else + send(output); + } + +} diff --git a/botan/src/filters/basefilt.cpp b/botan/src/filters/basefilt.cpp new file mode 100644 index 0000000..02dbd8a --- /dev/null +++ b/botan/src/filters/basefilt.cpp @@ -0,0 +1,74 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/basefilt.h> + +namespace Botan { + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + if(f1) { attach(f1); incr_owns(); } + if(f2) { attach(f2); incr_owns(); } + if(f3) { attach(f3); incr_owns(); } + if(f4) { attach(f4); incr_owns(); } + } + +/* +* Chain Constructor +*/ +Chain::Chain(Filter* filters[], u32bit count) + { + for(u32bit j = 0; j != count; ++j) + if(filters[j]) + { + attach(filters[j]); + incr_owns(); + } + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + Filter* filters[4] = { f1, f2, f3, f4 }; + set_next(filters, 4); + } + +/* +* Fork Constructor +*/ +Fork::Fork(Filter* filters[], u32bit count) + { + set_next(filters, count); + } + +/* +* Set the algorithm key +*/ +void Keyed_Filter::set_key(const SymmetricKey& key) + { + if(base_ptr) + base_ptr->set_key(key); + else + throw Invalid_State("Keyed_Filter::set_key: No base algorithm set"); + } + +/* +* Check if a keylength is valid +*/ +bool Keyed_Filter::valid_keylength(u32bit n) const + { + if(base_ptr) + return base_ptr->valid_keylength(n); + throw Invalid_State("Keyed_Filter::valid_keylength: No base algorithm set"); + } + +} diff --git a/botan/src/filters/basefilt.h b/botan/src/filters/basefilt.h new file mode 100644 index 0000000..75625ab --- /dev/null +++ b/botan/src/filters/basefilt.h @@ -0,0 +1,99 @@ +/* +* Basic Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BASEFILT_H__ +#define BOTAN_BASEFILT_H__ + +#include <botan/filter.h> +#include <botan/sym_algo.h> + +namespace Botan { + +/** +* This class represents Filter chains. A Filter chain is an ordered +* concatenation of Filters, the input to a Chain sequentially passes +* through all the Filters contained in the Chain. +*/ + +class BOTAN_DLL Chain : public Fanout_Filter + { + public: + void write(const byte input[], u32bit length) { send(input, length); } + + /** + * Construct a chain of up to four filters. The filters are set + * up in the same order as the arguments. + */ + Chain(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + + /** + * Construct a chain from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Chain(Filter* filter_arr[], u32bit length); + }; + +/** +* This class represents a fork filter, whose purpose is to fork the +* flow of data. It causes an input message to result in n messages at +* the end of the filter, where n is the number of forks. +*/ +class BOTAN_DLL Fork : public Fanout_Filter + { + public: + void write(const byte input[], u32bit length) { send(input, length); } + void set_port(u32bit n) { Fanout_Filter::set_port(n); } + + /** + * Construct a Fork filter with up to four forks. + */ + Fork(Filter*, Filter*, Filter* = 0, Filter* = 0); + + /** + * Construct a Fork from range of filters + * @param filter_arr the list of filters + * @param length how many filters + */ + Fork(Filter* filter_arr[], u32bit length); + }; + +/** +* This class represents keyed filters, i.e. filters that have to be +* fed with a key in order to function. +*/ +class BOTAN_DLL Keyed_Filter : public Filter + { + public: + + /** + * Set the key of this filter. + * @param key the key to set + */ + virtual void set_key(const SymmetricKey& key); + + /** + * Set the initialization vector of this filter. + * @param iv the initialization vector to set + */ + virtual void set_iv(const InitializationVector&) {} + + /** + * Check whether a key length is valid for this filter. + * @param length the key length to be checked for validity + * @return true if the key length is valid, false otherwise + */ + virtual bool valid_keylength(u32bit length) const; + + Keyed_Filter() { base_ptr = 0; } + protected: + SymmetricAlgorithm* base_ptr; + }; + +} + +#endif diff --git a/botan/src/filters/buf_filt.cpp b/botan/src/filters/buf_filt.cpp new file mode 100644 index 0000000..53352b5 --- /dev/null +++ b/botan/src/filters/buf_filt.cpp @@ -0,0 +1,71 @@ +/* +* Buffering Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/buf_filt.h> +#include <botan/exceptn.h> +#include <algorithm> + +namespace Botan { + +/* +* Buffering_Filter Constructor +*/ +Buffering_Filter::Buffering_Filter(u32bit b, u32bit i) : INITIAL_BLOCK_SIZE(i), + BLOCK_SIZE(b) + { + initial_block_pos = block_pos = 0; + initial.create(INITIAL_BLOCK_SIZE); + block.create(BLOCK_SIZE); + } + +/* +* Reset the Buffering Filter +*/ +void Buffering_Filter::end_msg() + { + if(initial_block_pos != INITIAL_BLOCK_SIZE) + throw Exception("Buffering_Filter: Not enough data for first block"); + final_block(block, block_pos); + initial_block_pos = block_pos = 0; + initial.clear(); + block.clear(); + } + +/* +* Buffer input into blocks +*/ +void Buffering_Filter::write(const byte input[], u32bit length) + { + if(initial_block_pos != INITIAL_BLOCK_SIZE) + { + u32bit copied = std::min(INITIAL_BLOCK_SIZE - initial_block_pos, length); + initial.copy(initial_block_pos, input, copied); + input += copied; + length -= copied; + initial_block_pos += copied; + if(initial_block_pos == INITIAL_BLOCK_SIZE) + initial_block(initial); + } + block.copy(block_pos, input, length); + if(block_pos + length >= BLOCK_SIZE) + { + main_block(block); + input += (BLOCK_SIZE - block_pos); + length -= (BLOCK_SIZE - block_pos); + while(length >= BLOCK_SIZE) + { + main_block(input); + input += BLOCK_SIZE; + length -= BLOCK_SIZE; + } + block.copy(input, length); + block_pos = 0; + } + block_pos += length; + } + +} diff --git a/botan/src/filters/buf_filt.h b/botan/src/filters/buf_filt.h new file mode 100644 index 0000000..ce3dbc9 --- /dev/null +++ b/botan/src/filters/buf_filt.h @@ -0,0 +1,39 @@ +/* +* Buffering Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_BUFFERING_FILTER_H__ +#define BOTAN_BUFFERING_FILTER_H__ + +#include <botan/filter.h> + +namespace Botan { + +/** +* Buffering_Filter: This class represents filters for operations that +* maintain an internal state. +*/ + +class BOTAN_DLL Buffering_Filter : public Filter + { + public: + void write(const byte[], u32bit); + virtual void end_msg(); + Buffering_Filter(u32bit, u32bit = 0); + virtual ~Buffering_Filter() {} + protected: + virtual void initial_block(const byte[]) {} + virtual void main_block(const byte[]) = 0; + virtual void final_block(const byte[], u32bit) = 0; + private: + const u32bit INITIAL_BLOCK_SIZE, BLOCK_SIZE; + SecureVector<byte> initial, block; + u32bit initial_block_pos, block_pos; + }; + +} + +#endif diff --git a/botan/src/filters/data_snk.cpp b/botan/src/filters/data_snk.cpp new file mode 100644 index 0000000..f8ee9f8 --- /dev/null +++ b/botan/src/filters/data_snk.cpp @@ -0,0 +1,62 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/data_snk.h> +#include <botan/exceptn.h> +#include <fstream> + +namespace Botan { + +/* +* Write to a stream +*/ +void DataSink_Stream::write(const byte out[], u32bit length) + { + sink->write(reinterpret_cast<const char*>(out), length); + if(!sink->good()) + throw Stream_IO_Error("DataSink_Stream: Failure writing to " + + identifier); + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(std::ostream& out, + const std::string& name) : + identifier(name != "" ? name : "<std::ostream>"), owner(false) + { + sink = &out; + } + +/* +* DataSink_Stream Constructor +*/ +DataSink_Stream::DataSink_Stream(const std::string& path, + bool use_binary) : + identifier(path), owner(true) + { + if(use_binary) + sink = new std::ofstream(path.c_str(), std::ios::binary); + else + sink = new std::ofstream(path.c_str()); + + if(!sink->good()) + throw Stream_IO_Error("DataSink_Stream: Failure opening " + path); + } + +/* +* DataSink_Stream Destructor +*/ +DataSink_Stream::~DataSink_Stream() + { + if(owner) + delete sink; + sink = 0; + } + +} diff --git a/botan/src/filters/data_snk.h b/botan/src/filters/data_snk.h new file mode 100644 index 0000000..61ddf6e --- /dev/null +++ b/botan/src/filters/data_snk.h @@ -0,0 +1,65 @@ +/* +* DataSink +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DATA_SINK_H__ +#define BOTAN_DATA_SINK_H__ + +#include <botan/filter.h> +#include <iosfwd> + +namespace Botan { + +/** +* This class represents abstract data sink objects. +*/ +class BOTAN_DLL DataSink : public Filter + { + public: + bool attachable() { return false; } + DataSink() {} + virtual ~DataSink() {} + private: + DataSink& operator=(const DataSink&) { return (*this); } + DataSink(const DataSink&); + }; + +/** +* This class represents a data sink which writes its output to a stream. +*/ +class BOTAN_DLL DataSink_Stream : public DataSink + { + public: + void write(const byte[], u32bit); + + /** + * Construct a DataSink_Stream from a stream. + * @param stream the stream to write to + * @param name identifier + */ + DataSink_Stream(std::ostream& stream, + const std::string& name = ""); + + /** + * Construct a DataSink_Stream from a stream. + * @param file the name of the file to open a stream to + * @param use_binary indicates whether to treat the file + * as a binary file or not + */ + DataSink_Stream(const std::string& filename, + bool use_binary = false); + + ~DataSink_Stream(); + private: + const std::string identifier; + const bool owner; + + std::ostream* sink; + }; + +} + +#endif diff --git a/botan/src/filters/data_src.cpp b/botan/src/filters/data_src.cpp new file mode 100644 index 0000000..e6387c4 --- /dev/null +++ b/botan/src/filters/data_src.cpp @@ -0,0 +1,207 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* 2005 Matthew Gregan +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/data_src.h> +#include <botan/exceptn.h> + +#include <fstream> +#include <algorithm> + +namespace Botan { + +/* +* Read a single byte from the DataSource +*/ +u32bit DataSource::read_byte(byte& out) + { + return read(&out, 1); + } + +/* +* Peek a single byte from the DataSource +*/ +u32bit DataSource::peek_byte(byte& out) const + { + return peek(&out, 1, 0); + } + +/* +* Discard the next N bytes of the data +*/ +u32bit DataSource::discard_next(u32bit n) + { + u32bit discarded = 0; + byte dummy; + for(u32bit j = 0; j != n; ++j) + discarded += read_byte(dummy); + return discarded; + } + +/* +* Read from a memory buffer +*/ +u32bit DataSource_Memory::read(byte out[], u32bit length) + { + u32bit got = std::min(source.size() - offset, length); + copy_mem(out, source + offset, got); + offset += got; + return got; + } + +/* +* Peek into a memory buffer +*/ +u32bit DataSource_Memory::peek(byte out[], u32bit length, + u32bit peek_offset) const + { + const u32bit bytes_left = source.size() - offset; + if(peek_offset >= bytes_left) return 0; + + u32bit got = std::min(bytes_left - peek_offset, length); + copy_mem(out, source + offset + peek_offset, got); + return got; + } + +/* +* Check if the memory buffer is empty +*/ +bool DataSource_Memory::end_of_data() const + { + return (offset == source.size()); + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const byte in[], u32bit length) + { + source.set(in, length); + offset = 0; + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const MemoryRegion<byte>& in) + { + source = in; + offset = 0; + } + +/* +* DataSource_Memory Constructor +*/ +DataSource_Memory::DataSource_Memory(const std::string& in) + { + source.set(reinterpret_cast<const byte*>(in.data()), in.length()); + offset = 0; + } + +/* +* Read from a stream +*/ +u32bit DataSource_Stream::read(byte out[], u32bit length) + { + source->read(reinterpret_cast<char*>(out), length); + if(source->bad()) + throw Stream_IO_Error("DataSource_Stream::read: Source failure"); + + u32bit got = source->gcount(); + total_read += got; + return got; + } + +/* +* Peek into a stream +*/ +u32bit DataSource_Stream::peek(byte out[], u32bit length, u32bit offset) const + { + if(end_of_data()) + throw Invalid_State("DataSource_Stream: Cannot peek when out of data"); + + u32bit got = 0; + + if(offset) + { + SecureVector<byte> buf(offset); + source->read(reinterpret_cast<char*>(buf.begin()), buf.size()); + if(source->bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = source->gcount(); + } + + if(got == offset) + { + source->read(reinterpret_cast<char*>(out), length); + if(source->bad()) + throw Stream_IO_Error("DataSource_Stream::peek: Source failure"); + got = source->gcount(); + } + + if(source->eof()) + source->clear(); + source->seekg(total_read, std::ios::beg); + + return got; + } + +/* +* Check if the stream is empty or in error +*/ +bool DataSource_Stream::end_of_data() const + { + return (!source->good()); + } + +/* +* Return a human-readable ID for this stream +*/ +std::string DataSource_Stream::id() const + { + return identifier; + } + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(const std::string& path, + bool use_binary) : + identifier(path), owner(true) + { + if(use_binary) + source = new std::ifstream(path.c_str(), std::ios::binary); + else + source = new std::ifstream(path.c_str()); + + if(!source->good()) + throw Stream_IO_Error("DataSource: Failure opening file " + path); + + total_read = 0; + } + +/* +* DataSource_Stream Constructor +*/ +DataSource_Stream::DataSource_Stream(std::istream& in, + const std::string& name) : + identifier(name), owner(false) + { + source = ∈ + total_read = 0; + } + +/* +* DataSource_Stream Destructor +*/ +DataSource_Stream::~DataSource_Stream() + { + if(owner) + delete source; + } + +} diff --git a/botan/src/filters/data_src.h b/botan/src/filters/data_src.h new file mode 100644 index 0000000..e16217e --- /dev/null +++ b/botan/src/filters/data_src.h @@ -0,0 +1,150 @@ +/* +* DataSource +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_DATA_SRC_H__ +#define BOTAN_DATA_SRC_H__ + +#include <botan/secmem.h> +#include <string> +#include <iosfwd> + +namespace Botan { + +/** +* This class represents an abstract data source object. +*/ +class BOTAN_DLL DataSource + { + public: + /** + * Read from the source. Moves the internal offset so that + * every call to read will return a new portion of the source. + * @param out the byte array to write the result to + * @param length the length of the byte array out + * @return the length in bytes that was actually read and put + * into out + */ + virtual u32bit read(byte out[], u32bit length) = 0; + + /** + * Read from the source but do not modify the internal offset. Consecutive + * calls to peek() will return portions of the source starting at the same + * position. + * @param out the byte array to write the output to + * @param length the length of the byte array out + * @return the length in bytes that was actually read and put + * into out + */ + virtual u32bit peek(byte out[], u32bit length, + u32bit peek_offset) const = 0; + + /** + * Test whether the source still has data that can be read. + * @return true if there is still data to read, false otherwise + */ + virtual bool end_of_data() const = 0; + /** + * return the id of this data source + * @return the std::string representing the id of this data source + */ + virtual std::string id() const { return ""; } + + /** + * Read one byte. + * @param the byte to read to + * @return the length in bytes that was actually read and put + * into out + */ + u32bit read_byte(byte& out); + + /** + * Peek at one byte. + * @param the byte to read to + * @return the length in bytes that was actually read and put + * into out + */ + u32bit peek_byte(byte& out) const; + + /** + * Discard the next N bytes of the data + * @param N the number of bytes to discard + * @return the number of bytes actually discarded + */ + u32bit discard_next(u32bit N); + + DataSource() {} + virtual ~DataSource() {} + private: + DataSource& operator=(const DataSource&) { return (*this); } + DataSource(const DataSource&); + }; + +/** +* This class represents a Memory-Based DataSource +*/ +class BOTAN_DLL DataSource_Memory : public DataSource + { + public: + u32bit read(byte[], u32bit); + u32bit peek(byte[], u32bit, u32bit) const; + bool end_of_data() const; + + /** + * Construct a memory source that reads from a string + * @param in the string to read from + */ + DataSource_Memory(const std::string& in); + + /** + * Construct a memory source that reads from a byte array + * @param in the byte array to read from + * @param length the length of the byte array + */ + DataSource_Memory(const byte in[], u32bit length); + + /** + * Construct a memory source that reads from a MemoryRegion + * @param in the MemoryRegion to read from + */ + DataSource_Memory(const MemoryRegion<byte>& in); + private: + SecureVector<byte> source; + u32bit offset; + }; + +/** +* This class represents a Stream-Based DataSource. +*/ +class BOTAN_DLL DataSource_Stream : public DataSource + { + public: + u32bit read(byte[], u32bit); + u32bit peek(byte[], u32bit, u32bit) const; + bool end_of_data() const; + std::string id() const; + + DataSource_Stream(std::istream&, const std::string& id = ""); + + /** + * Construct a Stream-Based DataSource from file + * @param file the name of the file + * @param use_binary whether to treat the file as binary or not + */ + DataSource_Stream(const std::string& file, bool use_binary = false); + + ~DataSource_Stream(); + private: + const std::string identifier; + const bool owner; + + std::istream* source; + u32bit total_read; + }; + +} + +#endif diff --git a/botan/src/filters/fd_unix/fd_unix.cpp b/botan/src/filters/fd_unix/fd_unix.cpp new file mode 100644 index 0000000..7f19b0a --- /dev/null +++ b/botan/src/filters/fd_unix/fd_unix.cpp @@ -0,0 +1,53 @@ +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pipe.h> +#include <botan/exceptn.h> +#include <unistd.h> + +namespace Botan { + +/* +* Write data from a pipe into a Unix fd +*/ +int operator<<(int fd, Pipe& pipe) + { + SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); + while(pipe.remaining()) + { + u32bit got = pipe.read(buffer, buffer.size()); + u32bit position = 0; + while(got) + { + ssize_t ret = write(fd, buffer + position, got); + if(ret == -1) + throw Stream_IO_Error("Pipe output operator (unixfd) has failed"); + position += ret; + got -= ret; + } + } + return fd; + } + +/* +* Read data from a Unix fd into a pipe +*/ +int operator>>(int fd, Pipe& pipe) + { + SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); + while(true) + { + ssize_t ret = read(fd, buffer, buffer.size()); + if(ret == 0) break; + if(ret == -1) + throw Stream_IO_Error("Pipe input operator (unixfd) has failed"); + pipe.write(buffer, ret); + } + return fd; + } + +} diff --git a/botan/src/filters/fd_unix/fd_unix.h b/botan/src/filters/fd_unix/fd_unix.h new file mode 100644 index 0000000..0aed009 --- /dev/null +++ b/botan/src/filters/fd_unix/fd_unix.h @@ -0,0 +1,23 @@ +/* +* Pipe I/O for Unix +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PIPE_UNIXFD_H__ +#define BOTAN_PIPE_UNIXFD_H__ + +#include <botan/pipe.h> + +namespace Botan { + +/* +* Unix I/O Operators for Pipe +*/ +int operator<<(int, Pipe&); +int operator>>(int, Pipe&); + +} + +#endif diff --git a/botan/src/filters/fd_unix/info.txt b/botan/src/filters/fd_unix/info.txt new file mode 100644 index 0000000..d87978c --- /dev/null +++ b/botan/src/filters/fd_unix/info.txt @@ -0,0 +1,28 @@ +realname "Unix I/O support for Pipe" + +define PIPE_UNIXFD_IO +modset unix,beos + +load_on auto + +<add> +fd_unix.h +fd_unix.cpp +</add> + +<os> +aix +beos +cygwin +darwin +freebsd +dragonfly +hpux +irix +linux +netbsd +openbsd +qnx +solaris +tru64 +</os> diff --git a/botan/src/filters/filter.cpp b/botan/src/filters/filter.cpp new file mode 100644 index 0000000..4bf0ef9 --- /dev/null +++ b/botan/src/filters/filter.cpp @@ -0,0 +1,127 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/filter.h> +#include <botan/secqueue.h> +#include <botan/exceptn.h> + +namespace Botan { + +/* +* Filter Constructor +*/ +Filter::Filter() + { + next.resize(1); + port_num = 0; + filter_owns = 0; + owned = false; + } + +/* +* Send data to all ports +*/ +void Filter::send(const byte input[], u32bit length) + { + bool nothing_attached = true; + for(u32bit j = 0; j != total_ports(); ++j) + if(next[j]) + { + if(write_queue.has_items()) + next[j]->write(write_queue, write_queue.size()); + next[j]->write(input, length); + nothing_attached = false; + } + if(nothing_attached) + write_queue.append(input, length); + else if(write_queue.has_items()) + write_queue.destroy(); + } + +/* +* Start a new message +*/ +void Filter::new_msg() + { + start_msg(); + for(u32bit j = 0; j != total_ports(); ++j) + if(next[j]) + next[j]->new_msg(); + } + +/* +* End the current message +*/ +void Filter::finish_msg() + { + end_msg(); + for(u32bit j = 0; j != total_ports(); ++j) + if(next[j]) + next[j]->finish_msg(); + } + +/* +* Attach a filter to the current port +*/ +void Filter::attach(Filter* new_filter) + { + if(new_filter) + { + Filter* last = this; + while(last->get_next()) + last = last->get_next(); + last->next[last->current_port()] = new_filter; + } + } + +/* +* Set the active port on a filter +*/ +void Filter::set_port(u32bit new_port) + { + if(new_port >= total_ports()) + throw Invalid_Argument("Filter: Invalid port number"); + port_num = new_port; + } + +/* +* Return the next Filter in the logical chain +*/ +Filter* Filter::get_next() const + { + if(port_num < next.size()) + return next[port_num]; + return 0; + } + +/* +* Set the next Filters +*/ +void Filter::set_next(Filter* filters[], u32bit size) + { + while(size && filters && filters[size-1] == 0) + --size; + + next.clear(); + next.resize(size); + + port_num = 0; + filter_owns = 0; + + for(u32bit j = 0; j != size; ++j) + next[j] = filters[j]; + } + +/* +* Return the total number of ports +*/ +u32bit Filter::total_ports() const + { + return next.size(); + } + +} diff --git a/botan/src/filters/filter.h b/botan/src/filters/filter.h new file mode 100644 index 0000000..b13a366 --- /dev/null +++ b/botan/src/filters/filter.h @@ -0,0 +1,113 @@ +/* +* Filter +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_FILTER_H__ +#define BOTAN_FILTER_H__ + +#include <botan/secmem.h> +#include <vector> + +namespace Botan { + +/** +* This class represents general abstract filter objects. +*/ +class BOTAN_DLL Filter + { + public: + + /** + * Write a portion of a message to this filter. + * @param input the input as a byte array + * @param length the length of the byte array input + */ + virtual void write(const byte input[], u32bit length) = 0; + + /** + * Start a new message. Must be closed by end_msg() before another + * message can be startet. + */ + virtual void start_msg() {} + + /** + * Tell the Filter that the current message shall be ended. + */ + virtual void end_msg() {} + + /** + * Check whether this filter is an attachable filter. + * @return true if this filter is attachable, false otherwise + */ + virtual bool attachable() { return true; } + + /** + * Start a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void new_msg(); + + /** + * End a new message in *this and all following filters. Only for + * internal use, not intended for use in client applications. + */ + void finish_msg(); + + virtual ~Filter() {} + protected: + void send(const byte[], u32bit); + void send(byte input) { send(&input, 1); } + void send(const MemoryRegion<byte>& in) { send(in.begin(), in.size()); } + Filter(); + private: + Filter(const Filter&) {} + Filter& operator=(const Filter&) { return (*this); } + + friend class Pipe; + friend class Fanout_Filter; + + u32bit total_ports() const; + u32bit current_port() const { return port_num; } + void set_port(u32bit); + + u32bit owns() const { return filter_owns; } + + void attach(Filter*); + void set_next(Filter*[], u32bit); + Filter* get_next() const; + + SecureVector<byte> write_queue; + std::vector<Filter*> next; + u32bit port_num, filter_owns; + + // true if filter belongs to a pipe --> prohibit filter sharing! + bool owned; + }; + +/** +* This is the abstract Fanout_Filter base class. +**/ +class BOTAN_DLL Fanout_Filter : public Filter + { + protected: + void incr_owns() { ++filter_owns; } + + void set_port(u32bit n) { Filter::set_port(n); } + void set_next(Filter* f[], u32bit n) { Filter::set_next(f, n); } + void attach(Filter* f) { Filter::attach(f); } + }; + +/** +* The type of checking to be performed by decoders: +* NONE - no checks, IGNORE_WS - perform checks, but ignore +* whitespaces, FULL_CHECK - perform checks, also complain +* about white spaces. +*/ +enum Decoder_Checking { NONE, IGNORE_WS, FULL_CHECK }; + +} + +#endif diff --git a/botan/src/filters/filters.h b/botan/src/filters/filters.h new file mode 100644 index 0000000..725651f --- /dev/null +++ b/botan/src/filters/filters.h @@ -0,0 +1,189 @@ +/* +* Filters +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_FILTERS_H__ +#define BOTAN_FILTERS_H__ + +#include <botan/block_cipher.h> +#include <botan/stream_cipher.h> +#include <botan/hash.h> +#include <botan/mac.h> + +#include <botan/pipe.h> +#include <botan/basefilt.h> +#include <botan/data_snk.h> +#include <botan/scan_name.h> + +#if defined(BOTAN_HAS_BASE64_CODEC) + #include <botan/base64.h> +#endif + +#if defined(BOTAN_HAS_HEX_CODEC) + #include <botan/hex.h> +#endif + +namespace Botan { + +/** +* Stream Cipher Filter. +*/ +class BOTAN_DLL StreamCipher_Filter : public Keyed_Filter + { + public: + + /** + * Seek in the stream. + * @param position the position to seek ahead + */ + void seek(u32bit position) { cipher->seek(position); } + + /** + * Find out whether the cipher underlying this filter supports + * resyncing. + * @return true if the cipher supports resyncing + */ + bool supports_resync() const { return (cipher->IV_LENGTH != 0); } + + /** + * Set the initialization vector for this filter. + * @param iv the initialization vector to set + */ + void set_iv(const InitializationVector& iv); + void write(const byte[], u32bit); + + /** + * Construct a stream cipher filter. + * @param cipher_obj a cipher object to use + */ + StreamCipher_Filter(StreamCipher* cipher_obj); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + */ + StreamCipher_Filter(const std::string& cipher); + + /** + * Construct a stream cipher filter. + * @param cipher the name of the desired cipher + * @param key the key to use inside this filter + */ + StreamCipher_Filter(const std::string& cipher, const SymmetricKey& key); + + ~StreamCipher_Filter() { delete cipher; } + private: + SecureVector<byte> buffer; + StreamCipher* cipher; + }; + +/** +* Hash Filter. +*/ +class BOTAN_DLL Hash_Filter : public Filter + { + public: + void write(const byte input[], u32bit len) { hash->update(input, len); } + void end_msg(); + + /** + * Construct a hash filter. + * @param hash_fun the hash function to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(HashFunction* hash_fun, u32bit len = 0) : + OUTPUT_LENGTH(len), hash(hash_fun) {} + + /** + * Construct a hash filter. + * @param request the name of the hash algorithm to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the hashfunction + * hash. Otherwise, specify a smaller value here so that the + * output of the hash algorithm will be cut off. + */ + Hash_Filter(const std::string& request, u32bit len = 0); + + ~Hash_Filter() { delete hash; } + private: + const u32bit OUTPUT_LENGTH; + HashFunction* hash; + }; + +/** +* MessageAuthenticationCode Filter. +*/ +class BOTAN_DLL MAC_Filter : public Keyed_Filter + { + public: + void write(const byte input[], u32bit len) { mac->update(input, len); } + void end_msg(); + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the MAC to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac_obj, + u32bit out_len = 0) : OUTPUT_LENGTH(out_len) + { + base_ptr = mac = mac_obj; + } + + /** + * Construct a MAC filter. + * @param mac the MAC to use + * @param key the MAC key to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(MessageAuthenticationCode* mac_obj, + const SymmetricKey& key, + u32bit out_len = 0) : OUTPUT_LENGTH(out_len) + { + base_ptr = mac = mac_obj; + mac->set_key(key); + } + + /** + * Construct a MAC filter. The MAC key will be left empty. + * @param mac the name of the MAC to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, u32bit len = 0); + + /** + * Construct a MAC filter. + * @param mac the name of the MAC to use + * @param key the MAC key to use + * @param len the output length of this filter. Leave the default + * value 0 if you want to use the full output of the + * MAC. Otherwise, specify a smaller value here so that the + * output of the MAC will be cut off. + */ + MAC_Filter(const std::string& mac, const SymmetricKey& key, + u32bit len = 0); + + ~MAC_Filter() { delete mac; } + private: + const u32bit OUTPUT_LENGTH; + MessageAuthenticationCode* mac; + }; + +} + +#endif diff --git a/botan/src/filters/info.txt b/botan/src/filters/info.txt new file mode 100644 index 0000000..79a92a9 --- /dev/null +++ b/botan/src/filters/info.txt @@ -0,0 +1,41 @@ +realname "Pipe/Filter" + +load_on auto + +define FILTERS + +<add> +algo_filt.cpp +basefilt.cpp +basefilt.h +buf_filt.cpp +buf_filt.h +data_snk.cpp +data_snk.h +data_src.cpp +data_src.h +filter.cpp +filter.h +filters.h +out_buf.cpp +out_buf.h +pbe.h +pipe.cpp +pipe.h +pipe_io.cpp +pipe_rw.cpp +secqueue.cpp +secqueue.h +</add> + +<requires> +alloc +asn1 +block +hash +libstate +mac +rng +stream +sym_algo +</requires> diff --git a/botan/src/filters/out_buf.cpp b/botan/src/filters/out_buf.cpp new file mode 100644 index 0000000..6002f4f --- /dev/null +++ b/botan/src/filters/out_buf.cpp @@ -0,0 +1,119 @@ +/* +* Pipe Output Buffer Source file +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/out_buf.h> +#include <botan/secqueue.h> + +namespace Botan { + +/* +* Read data from a message +*/ +u32bit Output_Buffers::read(byte output[], u32bit length, + Pipe::message_id msg) + { + SecureQueue* q = get(msg); + if(q) + return q->read(output, length); + return 0; + } + +/* +* Peek at data in a message +*/ +u32bit Output_Buffers::peek(byte output[], u32bit length, + u32bit stream_offset, + Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->peek(output, length, stream_offset); + return 0; + } + +/* +* Check available bytes in a message +*/ +u32bit Output_Buffers::remaining(Pipe::message_id msg) const + { + SecureQueue* q = get(msg); + if(q) + return q->size(); + return 0; + } + +/* +* Add a new output queue +*/ +void Output_Buffers::add(SecureQueue* queue) + { + if(!queue) + throw Internal_Error("Output_Buffers::add: Argument was NULL"); + + if(buffers.size() == buffers.max_size()) + throw Internal_Error("Output_Buffers::add: No more room in container"); + + buffers.push_back(queue); + } + +/* +* Retire old output queues +*/ +void Output_Buffers::retire() + { + while(buffers.size()) + { + if(buffers[0] == 0 || buffers[0]->size() == 0) + { + delete buffers[0]; + buffers.pop_front(); + offset = offset + Pipe::message_id(1); + } + else + break; + } + } + +/* +* Get a particular output queue +*/ +SecureQueue* Output_Buffers::get(Pipe::message_id msg) const + { + if(msg < offset) + return 0; + if(msg > message_count()) + throw Internal_Error("Output_Buffers::get: msg > size"); + + return buffers[msg-offset]; + } + +/* +* Return the total number of messages +*/ +Pipe::message_id Output_Buffers::message_count() const + { + return (offset + buffers.size()); + } + +/* +* Output_Buffers Constructor +*/ +Output_Buffers::Output_Buffers() + { + offset = 0; + } + +/* +* Output_Buffers Destructor +*/ +Output_Buffers::~Output_Buffers() + { + for(u32bit j = 0; j != buffers.size(); ++j) + delete buffers[j]; + } + +} diff --git a/botan/src/filters/out_buf.h b/botan/src/filters/out_buf.h new file mode 100644 index 0000000..0baacda --- /dev/null +++ b/botan/src/filters/out_buf.h @@ -0,0 +1,43 @@ +/* +* Output Buffer +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_OUTPUT_BUFFER_H__ +#define BOTAN_OUTPUT_BUFFER_H__ + +#include <botan/types.h> +#include <botan/pipe.h> +#include <deque> + +namespace Botan { + +/* +* Container of output buffers for Pipe +*/ +class BOTAN_DLL Output_Buffers + { + public: + u32bit read(byte[], u32bit, Pipe::message_id); + u32bit peek(byte[], u32bit, u32bit, Pipe::message_id) const; + u32bit remaining(Pipe::message_id) const; + + void add(class SecureQueue*); + void retire(); + + Pipe::message_id message_count() const; + + Output_Buffers(); + ~Output_Buffers(); + private: + class SecureQueue* get(Pipe::message_id) const; + + std::deque<SecureQueue*> buffers; + Pipe::message_id offset; + }; + +} + +#endif diff --git a/botan/src/filters/pbe.h b/botan/src/filters/pbe.h new file mode 100644 index 0000000..f06d593 --- /dev/null +++ b/botan/src/filters/pbe.h @@ -0,0 +1,56 @@ +/* +* PBE +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PBE_BASE_H__ +#define BOTAN_PBE_BASE_H__ + +#include <botan/asn1_oid.h> +#include <botan/data_src.h> +#include <botan/filter.h> +#include <botan/rng.h> + +namespace Botan { + +/** +* Password Based Encryption (PBE) Filter. +*/ +class BOTAN_DLL PBE : public Filter + { + public: + /** + * Set this filter's key. + * @param pw the password to be used for the encryption + */ + virtual void set_key(const std::string&) = 0; + + /** + * Create a new random salt value and set the default iterations value. + */ + virtual void new_params(RandomNumberGenerator& rng) = 0; + + /** + * DER encode the params (the number of iterations and the salt value) + * @return the encoded params + */ + virtual MemoryVector<byte> encode_params() const = 0; + + /** + * Decode params and use them inside this Filter. + * @param src a data source to read the encoded params from + */ + virtual void decode_params(DataSource&) = 0; + + /** + * Get this PBE's OID. + * @return the OID + */ + virtual OID get_oid() const = 0; + }; + +} + +#endif diff --git a/botan/src/filters/pipe.cpp b/botan/src/filters/pipe.cpp new file mode 100644 index 0000000..33824be --- /dev/null +++ b/botan/src/filters/pipe.cpp @@ -0,0 +1,306 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pipe.h> +#include <botan/out_buf.h> +#include <botan/secqueue.h> +#include <botan/parsing.h> + +namespace Botan { + +/* +* Constructor for Invalid_Message_Number +*/ +Pipe::Invalid_Message_Number::Invalid_Message_Number(const std::string& where, + message_id msg) + { + set_msg("Pipe::" + where + ": Invalid message number " + + to_string(msg)); + } + +namespace { + +/* +* A Filter that does nothing +*/ +class Null_Filter : public Filter + { + public: + void write(const byte input[], u32bit length) + { send(input, length); } + }; + +} + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* f1, Filter* f2, Filter* f3, Filter* f4) + { + init(); + append(f1); + append(f2); + append(f3); + append(f4); + } + +/* +* Pipe Constructor +*/ +Pipe::Pipe(Filter* filter_array[], u32bit count) + { + init(); + for(u32bit j = 0; j != count; ++j) + append(filter_array[j]); + } + +/* +* Pipe Destructor +*/ +Pipe::~Pipe() + { + destruct(pipe); + delete outputs; + } + +/* +* Initialize the Pipe +*/ +void Pipe::init() + { + outputs = new Output_Buffers; + pipe = 0; + default_read = 0; + inside_msg = false; + } + +/* +* Reset the Pipe +*/ +void Pipe::reset() + { + if(inside_msg) + throw Invalid_State("Pipe cannot be reset while it is processing"); + destruct(pipe); + pipe = 0; + inside_msg = false; + } + +/* +* Destroy the Pipe +*/ +void Pipe::destruct(Filter* to_kill) + { + if(!to_kill || dynamic_cast<SecureQueue*>(to_kill)) + return; + for(u32bit j = 0; j != to_kill->total_ports(); ++j) + destruct(to_kill->next[j]); + delete to_kill; + } + +/* +* Test if the Pipe has any data in it +*/ +bool Pipe::end_of_data() const + { + return (remaining() == 0); + } + +/* +* Set the default read message +*/ +void Pipe::set_default_msg(message_id msg) + { + if(msg >= message_count()) + throw Invalid_Argument("Pipe::set_default_msg: msg number is too high"); + default_read = msg; + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const byte input[], u32bit length) + { + start_msg(); + write(input, length); + end_msg(); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const MemoryRegion<byte>& input) + { + process_msg(input.begin(), input.size()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(const std::string& input) + { + process_msg(reinterpret_cast<const byte*>(input.data()), input.length()); + } + +/* +* Process a full message at once +*/ +void Pipe::process_msg(DataSource& input) + { + start_msg(); + write(input); + end_msg(); + } + +/* +* Start a new message +*/ +void Pipe::start_msg() + { + if(inside_msg) + throw Invalid_State("Pipe::start_msg: Message was already started"); + if(pipe == 0) + pipe = new Null_Filter; + find_endpoints(pipe); + pipe->new_msg(); + inside_msg = true; + } + +/* +* End the current message +*/ +void Pipe::end_msg() + { + if(!inside_msg) + throw Invalid_State("Pipe::end_msg: Message was already ended"); + pipe->finish_msg(); + clear_endpoints(pipe); + if(dynamic_cast<Null_Filter*>(pipe)) + { + delete pipe; + pipe = 0; + } + inside_msg = false; + + outputs->retire(); + } + +/* +* Find the endpoints of the Pipe +*/ +void Pipe::find_endpoints(Filter* f) + { + for(u32bit j = 0; j != f->total_ports(); ++j) + if(f->next[j] && !dynamic_cast<SecureQueue*>(f->next[j])) + find_endpoints(f->next[j]); + else + { + SecureQueue* q = new SecureQueue; + f->next[j] = q; + outputs->add(q); + } + } + +/* +* Remove the SecureQueues attached to the Filter +*/ +void Pipe::clear_endpoints(Filter* f) + { + if(!f) return; + for(u32bit j = 0; j != f->total_ports(); ++j) + { + if(f->next[j] && dynamic_cast<SecureQueue*>(f->next[j])) + f->next[j] = 0; + clear_endpoints(f->next[j]); + } + } + +/* +* Append a Filter to the Pipe +*/ +void Pipe::append(Filter* filter) + { + if(inside_msg) + throw Invalid_State("Cannot append to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast<SecureQueue*>(filter)) + throw Invalid_Argument("Pipe::append: SecureQueue cannot be used"); + if(filter->owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->owned = true; + + if(!pipe) pipe = filter; + else pipe->attach(filter); + } + +/* +* Prepend a Filter to the Pipe +*/ +void Pipe::prepend(Filter* filter) + { + if(inside_msg) + throw Invalid_State("Cannot prepend to a Pipe while it is processing"); + if(!filter) + return; + if(dynamic_cast<SecureQueue*>(filter)) + throw Invalid_Argument("Pipe::prepend: SecureQueue cannot be used"); + if(filter->owned) + throw Invalid_Argument("Filters cannot be shared among multiple Pipes"); + + filter->owned = true; + + if(pipe) filter->attach(pipe); + pipe = filter; + } + +/* +* Pop a Filter off the Pipe +*/ +void Pipe::pop() + { + if(inside_msg) + throw Invalid_State("Cannot pop off a Pipe while it is processing"); + + if(!pipe) + return; + + if(pipe->total_ports() > 1) + throw Invalid_State("Cannot pop off a Filter with multiple ports"); + + Filter* f = pipe; + u32bit owns = f->owns(); + pipe = pipe->next[0]; + delete f; + + while(owns--) + { + f = pipe; + pipe = pipe->next[0]; + delete f; + } + } + +/* +* Return the number of messages in this Pipe +*/ +Pipe::message_id Pipe::message_count() const + { + return outputs->message_count(); + } + +/* +* Static Member Variables +*/ +const Pipe::message_id Pipe::LAST_MESSAGE = + static_cast<Pipe::message_id>(-2); + +const Pipe::message_id Pipe::DEFAULT_MESSAGE = + static_cast<Pipe::message_id>(-1); + +} diff --git a/botan/src/filters/pipe.h b/botan/src/filters/pipe.h new file mode 100644 index 0000000..120f2fb --- /dev/null +++ b/botan/src/filters/pipe.h @@ -0,0 +1,275 @@ +/* +* Pipe +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_PIPE_H__ +#define BOTAN_PIPE_H__ + +#include <botan/data_src.h> +#include <botan/filter.h> +#include <botan/exceptn.h> +#include <iosfwd> + +namespace Botan { + +/** +* This class represents pipe objects. +* A set of filters can be placed into a pipe, and information flows +* through the pipe until it reaches the end, where the output is +* collected for retrieval. If you're familiar with the Unix shell +* environment, this design will sound quite familiar. +*/ + +class BOTAN_DLL Pipe : public DataSource + { + public: + typedef u32bit message_id; + + class Invalid_Message_Number : public Invalid_Argument + { + public: + Invalid_Message_Number(const std::string&, message_id); + }; + + static const message_id LAST_MESSAGE; + static const message_id DEFAULT_MESSAGE; + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the byte array to write + * @param length the length of the byte array in + */ + void write(const byte in[], u32bit length); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the MemoryRegion containing the data to write + */ + void write(const MemoryRegion<byte>& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the string containing the data to write + */ + void write(const std::string& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in the DataSource to read the data from + */ + void write(DataSource& in); + + /** + * Write input to the pipe, i.e. to its first filter. + * @param in a single byte to be written + */ + void write(byte in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the byte array containing the data to write + * @param length the length of the byte array to write + */ + void process_msg(const byte in[], u32bit length); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the MemoryRegion containing the data to write + */ + void process_msg(const MemoryRegion<byte>& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the string containing the data to write + */ + void process_msg(const std::string& in); + + /** + * Perform start_msg(), write() and end_msg() sequentially. + * @param in the DataSource providing the data to write + */ + void process_msg(DataSource& in); + + /** + * Find out how many bytes are ready to read. + * @param msg the number identifying the message + * for which the information is desired + * @return the number of bytes that can still be read + */ + u32bit remaining(message_id msg = DEFAULT_MESSAGE) const; + + /** + * Read the default message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @return the number of bytes actually read into output + */ + u32bit read(byte output[], u32bit length); + + /** + * Read a specified message from the pipe. Moves the internal + * offset so that every call to read will return a new portion of + * the message. + * @param output the byte array to write the read bytes to + * @param length the length of the byte array output + * @param msg the number identifying the message to read from + * @return the number of bytes actually read into output + */ + u32bit read(byte output[], u32bit length, message_id msg); + + /** + * Read a single byte from the pipe. Moves the internal offset so that + * every call to read will return a new portion of the message. + * @param output the byte to write the result to + * @return the number of bytes actually read into output + */ + u32bit read(byte& output, message_id msg = DEFAULT_MESSAGE); + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return a SecureVector holding the contents of the pipe + */ + SecureVector<byte> read_all(message_id msg = DEFAULT_MESSAGE); + + /** + * Read the full contents of the pipe. + * @param msg the number identifying the message to read from + * @return a string holding the contents of the pipe + */ + std::string read_all_as_string(message_id = DEFAULT_MESSAGE); + + /** Read from the default message but do not modify the internal + * offset. Consecutive calls to peek() will return portions of + * the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @return the number of bytes actually peeked and written into output + */ + u32bit peek(byte output[], u32bit length, u32bit offset) const; + + /** Read from the specified message but do not modify the + * internal offset. Consecutive calls to peek() will return + * portions of the message starting at the same position. + * @param output the byte array to write the peeked message part to + * @param length the length of the byte array output + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return the number of bytes actually peeked and written into output + */ + u32bit peek(byte output[], u32bit length, + u32bit offset, message_id msg) const; + + /** Read a single byte from the specified message but do not + * modify the internal offset. Consecutive calls to peek() will + * return portions of the message starting at the same position. + * @param output the byte to write the peeked message byte to + * @param offset the offset from the current position in message + * @param msg the number identifying the message to peek from + * @return the number of bytes actually peeked and written into output + */ + u32bit peek(byte& output, u32bit offset, + message_id msg = DEFAULT_MESSAGE) const; + + u32bit default_msg() const { return default_read; } + + /** + * Set the default message + * @param msg the number identifying the message which is going to + * be the new default message + */ + void set_default_msg(message_id msg); + + /** + * Get the number of messages the are in this pipe. + * @return the number of messages the are in this pipe + */ + message_id message_count() const; + + /** + * Test whether this pipe has any data that can be read from. + * @return true if there is more data to read, false otherwise + */ + bool end_of_data() const; + + /** + * Start a new message in the pipe. A potential other message in this pipe + * must be closed with end_msg() before this function may be called. + */ + void start_msg(); + + /** + * End the current message. + */ + void end_msg(); + + /** + * Insert a new filter at the front of the pipe + * @param filt the new filter to insert + */ + void prepend(Filter* filt); + + /** + * Insert a new filter at the back of the pipe + * @param filt the new filter to insert + */ + void append(Filter* filt); + + /** + * Remove the first filter at the front of the pipe. + */ + void pop(); + + /** + * Reset this pipe to an empty pipe. + */ + void reset(); + + /** + * Construct a Pipe of up to four filters. The filters are set up + * in the same order as the arguments. + */ + Pipe(Filter* = 0, Filter* = 0, Filter* = 0, Filter* = 0); + + /** + * Construct a Pipe from range of filters passed as an array + * @param filters the set of filters to use + * @param count the number of elements in filters + */ + Pipe(Filter* filters[], u32bit count); + ~Pipe(); + private: + Pipe(const Pipe&) : DataSource() {} + Pipe& operator=(const Pipe&) { return (*this); } + void init(); + void destruct(Filter*); + void find_endpoints(Filter*); + void clear_endpoints(Filter*); + + message_id get_message_no(const std::string&, message_id) const; + + Filter* pipe; + class Output_Buffers* outputs; + message_id default_read; + bool inside_msg; + }; + +/* +* I/O Operators for Pipe +*/ +BOTAN_DLL std::ostream& operator<<(std::ostream&, Pipe&); +BOTAN_DLL std::istream& operator>>(std::istream&, Pipe&); + +} + +#endif + +#if defined(BOTAN_HAS_PIPE_UNIXFD_IO) + #include <botan/fd_unix.h> +#endif diff --git a/botan/src/filters/pipe_io.cpp b/botan/src/filters/pipe_io.cpp new file mode 100644 index 0000000..c57be6d --- /dev/null +++ b/botan/src/filters/pipe_io.cpp @@ -0,0 +1,45 @@ +/* +* Pipe I/O +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pipe.h> +#include <iostream> + +namespace Botan { + +/* +* Write data from a pipe into an ostream +*/ +std::ostream& operator<<(std::ostream& stream, Pipe& pipe) + { + SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); + while(stream.good() && pipe.remaining()) + { + u32bit got = pipe.read(buffer, buffer.size()); + stream.write(reinterpret_cast<const char*>(buffer.begin()), got); + } + if(!stream.good()) + throw Stream_IO_Error("Pipe output operator (iostream) has failed"); + return stream; + } + +/* +* Read data from an istream into a pipe +*/ +std::istream& operator>>(std::istream& stream, Pipe& pipe) + { + SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); + while(stream.good()) + { + stream.read(reinterpret_cast<char*>(buffer.begin()), buffer.size()); + pipe.write(buffer, stream.gcount()); + } + if(stream.bad() || (stream.fail() && !stream.eof())) + throw Stream_IO_Error("Pipe input operator (iostream) has failed"); + return stream; + } + +} diff --git a/botan/src/filters/pipe_rw.cpp b/botan/src/filters/pipe_rw.cpp new file mode 100644 index 0000000..41b57a7 --- /dev/null +++ b/botan/src/filters/pipe_rw.cpp @@ -0,0 +1,167 @@ +/* +* Pipe Reading/Writing +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/pipe.h> +#include <botan/out_buf.h> +#include <botan/secqueue.h> + +namespace Botan { + +/* +* Look up the canonical ID for a queue +*/ +Pipe::message_id Pipe::get_message_no(const std::string& func_name, + message_id msg) const + { + if(msg == DEFAULT_MESSAGE) + msg = default_msg(); + else if(msg == LAST_MESSAGE) + msg = message_count() - 1; + + if(msg >= message_count()) + throw Invalid_Message_Number(func_name, msg); + + return msg; + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const byte input[], u32bit length) + { + if(!inside_msg) + throw Exception("Cannot write to a Pipe while it is not processing"); + pipe->write(input, length); + } + +/* +* Write into a Pipe +*/ +void Pipe::write(const MemoryRegion<byte>& input) + { + write(input.begin(), input.size()); + } + +/* +* Write a string into a Pipe +*/ +void Pipe::write(const std::string& str) + { + write(reinterpret_cast<const byte*>(str.data()), str.size()); + } + +/* +* Write a single byte into a Pipe +*/ +void Pipe::write(byte input) + { + write(&input, 1); + } + +/* +* Write the contents of a DataSource into a Pipe +*/ +void Pipe::write(DataSource& source) + { + SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); + while(!source.end_of_data()) + { + u32bit got = source.read(buffer, buffer.size()); + write(buffer, got); + } + } + +/* +* Read some data from the pipe +*/ +u32bit Pipe::read(byte output[], u32bit length, message_id msg) + { + return outputs->read(output, length, get_message_no("read", msg)); + } + +/* +* Read some data from the pipe +*/ +u32bit Pipe::read(byte output[], u32bit length) + { + return read(output, length, DEFAULT_MESSAGE); + } + +/* +* Read a single byte from the pipe +*/ +u32bit Pipe::read(byte& out, message_id msg) + { + return read(&out, 1, msg); + } + +/* +* Return all data in the pipe +*/ +SecureVector<byte> Pipe::read_all(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + SecureVector<byte> buffer(remaining(msg)); + read(buffer, buffer.size(), msg); + return buffer; + } + +/* +* Return all data in the pipe as a string +*/ +std::string Pipe::read_all_as_string(message_id msg) + { + msg = ((msg != DEFAULT_MESSAGE) ? msg : default_msg()); + SecureVector<byte> buffer(DEFAULT_BUFFERSIZE); + std::string str; + str.reserve(remaining(msg)); + + while(true) + { + u32bit got = read(buffer, buffer.size(), msg); + if(got == 0) + break; + str.append(reinterpret_cast<const char*>(buffer.begin()), got); + } + + return str; + } + +/* +* Find out how many bytes are ready to read +*/ +u32bit Pipe::remaining(message_id msg) const + { + return outputs->remaining(get_message_no("remaining", msg)); + } + +/* +* Peek at some data in the pipe +*/ +u32bit Pipe::peek(byte output[], u32bit length, + u32bit offset, message_id msg) const + { + return outputs->peek(output, length, offset, get_message_no("peek", msg)); + } + +/* +* Peek at some data in the pipe +*/ +u32bit Pipe::peek(byte output[], u32bit length, u32bit offset) const + { + return peek(output, length, offset, DEFAULT_MESSAGE); + } + +/* +* Peek at a byte in the pipe +*/ +u32bit Pipe::peek(byte& out, u32bit offset, message_id msg) const + { + return peek(&out, 1, offset, msg); + } + +} diff --git a/botan/src/filters/secqueue.cpp b/botan/src/filters/secqueue.cpp new file mode 100644 index 0000000..f63ef89 --- /dev/null +++ b/botan/src/filters/secqueue.cpp @@ -0,0 +1,205 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#include <botan/secqueue.h> +#include <algorithm> + +namespace Botan { + +/* +* SecureQueueNode +*/ +class SecureQueueNode + { + public: + u32bit write(const byte input[], u32bit length) + { + u32bit copied = std::min(length, buffer.size() - end); + copy_mem(buffer + end, input, copied); + end += copied; + return copied; + } + u32bit read(byte output[], u32bit length) + { + u32bit copied = std::min(length, end - start); + copy_mem(output, buffer + start, copied); + start += copied; + return copied; + } + u32bit peek(byte output[], u32bit length, u32bit offset = 0) + { + const u32bit left = end - start; + if(offset >= left) return 0; + u32bit copied = std::min(length, left - offset); + copy_mem(output, buffer + start + offset, copied); + return copied; + } + u32bit size() const { return (end - start); } + SecureQueueNode() { next = 0; start = end = 0; } + ~SecureQueueNode() { next = 0; start = end = 0; } + private: + friend class SecureQueue; + SecureQueueNode* next; + SecureBuffer<byte, DEFAULT_BUFFERSIZE> buffer; + u32bit start, end; + }; + +/* +* Create a SecureQueue +*/ +SecureQueue::SecureQueue() + { + set_next(0, 0); + head = tail = new SecureQueueNode; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue::SecureQueue(const SecureQueue& input) : + Fanout_Filter(), DataSource() + { + set_next(0, 0); + + head = tail = new SecureQueueNode; + SecureQueueNode* temp = input.head; + while(temp) + { + write(temp->buffer + temp->start, temp->end - temp->start); + temp = temp->next; + } + } + +/* +* Destroy this SecureQueue +*/ +void SecureQueue::destroy() + { + SecureQueueNode* temp = head; + while(temp) + { + SecureQueueNode* holder = temp->next; + delete temp; + temp = holder; + } + head = tail = 0; + } + +/* +* Copy a SecureQueue +*/ +SecureQueue& SecureQueue::operator=(const SecureQueue& input) + { + destroy(); + head = tail = new SecureQueueNode; + SecureQueueNode* temp = input.head; + while(temp) + { + write(temp->buffer + temp->start, temp->end - temp->start); + temp = temp->next; + } + return (*this); + } + +/* +* Add some bytes to the queue +*/ +void SecureQueue::write(const byte input[], u32bit length) + { + if(!head) + head = tail = new SecureQueueNode; + while(length) + { + const u32bit n = tail->write(input, length); + input += n; + length -= n; + if(length) + { + tail->next = new SecureQueueNode; + tail = tail->next; + } + } + } + +/* +* Read some bytes from the queue +*/ +u32bit SecureQueue::read(byte output[], u32bit length) + { + u32bit got = 0; + while(length && head) + { + const u32bit n = head->read(output, length); + output += n; + got += n; + length -= n; + if(head->size() == 0) + { + SecureQueueNode* holder = head->next; + delete head; + head = holder; + } + } + return got; + } + +/* +* Read data, but do not remove it from queue +*/ +u32bit SecureQueue::peek(byte output[], u32bit length, u32bit offset) const + { + SecureQueueNode* current = head; + + while(offset && current) + { + if(offset >= current->size()) + { + offset -= current->size(); + current = current->next; + } + else + break; + } + + u32bit got = 0; + while(length && current) + { + const u32bit n = current->peek(output, length, offset); + offset = 0; + output += n; + got += n; + length -= n; + current = current->next; + } + return got; + } + +/* +* Return how many bytes the queue holds +*/ +u32bit SecureQueue::size() const + { + SecureQueueNode* current = head; + u32bit count = 0; + + while(current) + { + count += current->size(); + current = current->next; + } + return count; + } + +/* +* Test if the queue has any data in it +*/ +bool SecureQueue::end_of_data() const + { + return (size() == 0); + } + +} diff --git a/botan/src/filters/secqueue.h b/botan/src/filters/secqueue.h new file mode 100644 index 0000000..fc1fc21 --- /dev/null +++ b/botan/src/filters/secqueue.h @@ -0,0 +1,43 @@ +/* +* SecureQueue +* (C) 1999-2007 Jack Lloyd +* +* Distributed under the terms of the Botan license +*/ + +#ifndef BOTAN_SECURE_QUEUE_H__ +#define BOTAN_SECURE_QUEUE_H__ + +#include <botan/data_src.h> +#include <botan/filter.h> + +namespace Botan { + +/* +* SecureQueue +*/ +class BOTAN_DLL SecureQueue : public Fanout_Filter, public DataSource + { + public: + void write(const byte[], u32bit); + + u32bit read(byte[], u32bit); + u32bit peek(byte[], u32bit, u32bit = 0) const; + + bool end_of_data() const; + u32bit size() const; + bool attachable() { return false; } + + SecureQueue& operator=(const SecureQueue&); + SecureQueue(); + SecureQueue(const SecureQueue&); + ~SecureQueue() { destroy(); } + private: + void destroy(); + class SecureQueueNode* head; + class SecureQueueNode* tail; + }; + +} + +#endif |