📄 api.tex
字号:
``KDF1(hash)'' or ``KDF2(hash)'' where ``hash'' is any string you happen tolike (hopefully you like strings like ``SHA-1'' or ``RIPEMD-160'').How key agreement generally works is that you trade public values with someother party, and then each of you runs a computation with the other's value andyour key (this should return the same result to both parties). This computationcan be called by using \function{derive\_key} with either a byte array/lengthpair, or a \type{SecureVector<byte>} than holds the public value of the otherparty. The last argument to either call is a number that specifies how long akey you want.Depending on the key derivation function you're using, you many not\emph{actually} get back a key of that size. In particular, ``Raw'' will returna number about the size of the Diffie-Hellman modulus, and KDF1 can only returna key which is the same size as the output of the hash. KDF2, on the otherhand, will always give you a key exactly as long as you request, regardless ofthe underlying hash used with it. The key returned is a \type{SymmetricKey},ready to pass to a block cipher, MAC, or other symmetric algorithm.The public value which should be used can be obtained by calling\function{public\_data}, which exists for any key that is associated with akey agreement algorithm. It returns a \type{SecureVector<byte>}.KDF2 is by far the preferred algorithm for key derivation in new algorithms.\pagebreak\section{Filters}\subsection{Basic Filter Usage}Up until this point, using Botan would be very tedious; to do anything youwould have to bother with putting data into arrays, doing whatever you wantwith it, and then sending it someplace. The filter metaphor (defining a seriesof operations which take some amount of input, process it, then send it alongto the next filter) works very well in this situation. If you've ever used aUnix system, the usage of filters in Botan should be very intuitive (and evenif you haven't, don't worry, it's pretty easy). For instance, here is how youencrypt a file with Blowfish in CBC mode with PKCS\#7 padding, then encode itwith Base64 and send it to standard output (we assume that \verb|file| is anopen \type{istream}):\begin{verbatim}SymmetricKey key(16);BlockCipherModeIV iv(8); // or use: block_size_of(``Blowfish'')Pipe encryptor(new CBC_Encryption(``Blowfish'', ``PKCS7'', key, iv), new Base64_Encoder);encryptor.start_msg();file >> encryptor;encryptor.end_msg(); // flush buffers, complete computationscout << encryptor;\end{verbatim}\type{Pipe} works in conjunction with the \type{Filter} class (for example, the\type{CBC\_Encryption} and \type{Base64\_Encoder} types used above are\type{Filter}s), but you never have to deal with them directly; Pipe handlesall the required housekeeping.A useful ability of Pipe is to split up the work up into what are called``messages''. Messages are blocks of data that are processed in an identicalfashion (ie, with the same sequence of \type{Filter}s). Messages are delimitedby the \function{start\_msg} and \function{end\_msg} functions, as shownabove. There are two different ways to make use of messages. One is to sendseveral messages through a Pipe without changing the Pipe's configuration, soyou end up with a sequence of messages; one use of this would be to send asequence of identically encrypted UDP packets, for example (note that the\emph{data} need not be identical; it is just that each is encrypted, encoded,signed, etc in an identical fashion). Another is to change the filters that areused in the Pipe between each message, by adding or removing Pipes; functionsthat let you do this are documented a bit later in this section.Besides the istream input operator \texttt{>>} used in the example above, thereare input operators for \type{FILE} objects and also Unix file descriptors (ifthe \texttt{pipe\_unixfd} module was compiled into Botan). All of these pullall available data out of the file and put it into the Pipe in one bigshot. Alternately, you can put data in a bit at a time with three functions,all called \function{write}. One takes a \type{std::string}, another a single\type{byte}, and the last an array of \type{byte}s and a length parameter.There are a fairly large number of ways to pull processed data out of a Pipe.One can use file output operators similar to the input operators describedabove, as well as a wide variety of \function{read} calls (these functions maynot always return the full amount requested; they will always return a\type{u32bit} telling how many bytes were written into the buffer). These aresplit into two main flavors: ones that take a message number, and those that donot. If a read call does not take a message number, it will read from whatevermessage has been designated as the ``default read message'', using the\function{set\_default\_msg} function (\function{default\_msg} returns thisvalue). This is also important to do for using the file output operators, sincethese operators will always read from the default read message. The function\function{read\_all\_as\_string} returns the entire message as a\type{std::string}, and \function{read\_all} returns the same, as a\type{SecureVector<byte>}.Additionally, you can query the exact number of bytes in a message using\function{remaining}. There are also a pair of functions called \function{peek}which allow you to look at the contents of a message without removing it fromthe Pipe.You can reuse a \type{Pipe} by calling it's \function{reset} function, whichrestores a pipe to it's initial state of no filters (writing into the\type{Pipe} and then reading will give you back your data unchanged). Thisusually isn't too useful, so you can use the functions \function{append} and\function{prepend} to add filters to the Pipe again. The \function{pop}function will pop the first \type{Filter} off of the pipe. You can call\function{append} and \function{prepend} as many times as you like; each filteradded will be attached to the end or beginning (respectively) of the currentset of filters (note that you can use these functions even if you haven'tcalled \function{reset}). You can only use these stack-like functions while thePipe is ``unlocked'', that is, not in the middle of processing a message.Pipe's full interface definition can be found in \filename{pipe.h}\subsection{Fork}It's fairly common that you might receive some data and want to perform morethan one operation on it (ie, encrypt it with DES and calculate the MD5 hash ofthe plaintext at the same time). That's where \type{Fork} comes in. \type{Fork}is a filter that takes it's input and passes it on to \emph{one or more}\type{Filter}s which are attached to it. \type{Fork} changes the nature of thepipe system completely. Instead of being a linked list, it becomes a tree.Before messages were added to Botan, using Fork was significantly morecomplicated, requiring you to keep pointers to Fork objects you allocated andsending control information to them when you wanted to read your output. Now,however, things are much simpler. Each Filter in the fork is given it's ownoutput buffer, and thus it's own message. For example, if you have previouslywritten two messages into a Pipe, then you start a new one with a Fork whichhas three paths of Filter's inside it, you add three new messages to the Pipe.The data you put into the Pipe is duplicated and sent into each set of Filters,and the eventual output is placed into a dedicated message slot in the Pipe.The \texttt{hasher} and \texttt{hasher2} examples show two different ways ofusing Pipe and Fork.There is a very useful (and previously undocumented) trick that you can do with\type{Fork}. Let's say you had some data that had been encrypted with a blockcipher, and then hex encoded. In addition, a hex encoded MAC of the plaintexthad been calculated and included with the message. You not only want to decryptthe data, you want to verify the MAC. So the first two filters in the pipe willdecode the hex, and decrypt the raw ciphertext. But now, how are you going toboth a) get the plaintext, and b) calculate the MAC of the plaintext? This isactually very simple, if a bit obscure.What you have to do is, after the filters that do the initial decoding, createa \type{Fork}. For the first argument, pass a null pointer. The fork objectwill understand that this means that you don't want to do any more processingon that line of the fork; you just want the data that was placed in. And thenin the second argument you would pass in a \type{MAC\_Filter} so you couldcompute a MAC of the plaintext.For an example of this technique, look at the \texttt{rsa\_dec} example in\filename{doc/examples/}.Any \type{Filter}s which are attached to the \type{Pipe} after the \type{Fork}are implicitly attached onto the first branch created by the fork. For example,let's say you created this \type{Pipe}:\begin{verbatim}Pipe pipe(new Fork(new Hash_Filter(``MD5''), new Hash_Filter(``SHA-1'')), new Hex_Encoder);\end{verbatim}And then called \function{start\_msg}, inserted some data, then\function{end\_msg}. Then \arg{pipe} would contain two messages. The first one(message number 0) would contain the MD5 sum of the input in hex encoded form,and the other would contain the SHA-1 sum of the input in raw binary.\subsection{Chain}\type{Chain} is about as simple as it gets. \type{Chain} creates a chain of\type{Filter}s and encapsulates them inside a single filter (itself). This isprimarily useful for passing a sequence of filters into something which isexpecting only a single \type{Filter} (most notably, \type{Fork}). You can call\type{Chain}'s constructor with up to 4 \type{Filter*}s (they will be added inorder), or with an array of \type{Filter*}s and a \type{u32bit} which tells\type{Chain} how many \type{Filter*}s are in the array (again, they will beattached in order).See the next section for an example of using \type{Chain}.\pagebreak\subsection{A Filter Example}Here is some code which takes one or more filenames as it's arguments andcalculates the result of several hash functions for each file. The completeprogram can be found as \filename{hasher.cpp} in the Botan distribution. Forbrevity, most error checking has been removed.\begin{verbatim} string name[3] = { "MD5", "SHA-1", "RIPEMD-160" }; Botan::Filter* hash[3] = { new Botan::Chain(new Botan::Hash_Filter(name[0]), new Botan::Hex_Encoder), new Botan::Chain(new Botan::Hash_Filter(name[1]), new Botan::Hex_Encoder), new Botan::Chain(new Botan::Hash_Filter(name[2]), new Botan::Hex_Encoder) }; Botan::Pipe pipe(new Botan::Fork(hash, COUNT)); for(u32bit j = 1; argv[j] != 0; j++) { ifstream file(argv[j]); pipe.start_msg(); file >> pipe; pipe.end_msg(); file.close(); for(u32bit k = 0; k != 3; k++) { pipe.set_default_msg(k); cout << name[k] << "(" << argv[j] << ") = " << pipe << endl; } }\end{verbatim}\pagebreak\subsection{Rolling Your Own}Well, now that you know how filters work in Botan, you might want to writeyour own. Lucky for you, all of the hard work is done by the \type{Filter} baseclass, leaving you to handle the details of what your filter is supposed todo. Remember that if you get confused about any of this, you can always look atthe implementation of Botan's filters to see exactly how everything works.There are basically only four functions that a filter need worry about:\noindent\type{void} \function{write}(\type{byte} \arg{input}[], \type{u32bit}\arg{length}):The \function{write} function is what is called when a filter receives inputfor it to process. The filter is \emph{not} required to process it right away;many filters buffer their input before producing any output. A filter willusually have \function{write} called many times during it's lifetime.\noindent\type{void} \function{send}(\type{byte} \arg{output}[], \type{u32bit}\arg{length}):Eventually, a filter will want to produce some output to send along to the nextfilter in the pipeline. It does so by calling \function{send} with whatever itwants to send along to the next filter. There is also a version of\function{send} taking a single byte argument, as a convenience.\noindent\type{void} \function{start\_msg()}:This function is optional. Implement it if your Filter would like to do someprocessing or setup at the start of each message (for an example, see the Zlibcompression module).\noindent\type{void} \function{end\_msg()}:Implementing the \function{end\_msg} function is optional. It is called when ithas been requested that filters finish up their computations. Note that theymust \emph{not} deallocate their resources; this should be done by theirdestructor. They should simply finish up with whatever computation they havebeen working on (for example, a compressing filter would flush the compressorand \function{send} the final block), and empty any buffers in preparation forprocessing a fresh new set of input. It is essentially the inverse of\function{start\_msg}.Additionally, if necessary, filters can define a constructor that takes anyneeded arguments, and a destructor to deal with deallocating memory, closingfiles, etc.There is also a \type{BufferingFilter} class (in \filename{buf\_filt.h}) whichwill take a message and split it up into an initial block which can be of anysize (including zero), a sequence of fixed sized blocks of any non-zero size,and last (possibly zero-sized) final block. This might make a useful base classfor your filters, depending on what you have in mind.\pagebreak\subsection{Filter Catalog}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -