Browse Source

merged branches/trac256 for trac #256: various base32/hex bug fixes.

git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@2549 e5f2f494-b856-4b98-b285-d166d9295462
JINMEI Tatuya 14 years ago
parent
commit
17c6525363

+ 3 - 3
src/lib/datasrc/data_source.cc

@@ -28,14 +28,14 @@
 #include <datasrc/data_source.h>
 #include <datasrc/query.h>
 
-#include <dns/base32.h>
+#include <dns/util/base32hex.h>
 #include <dns/buffer.h>
 #include <dns/message.h>
 #include <dns/name.h>
 #include <dns/rdataclass.h>
 #include <dns/rrset.h>
 #include <dns/rrsetlist.h>
-#include <dns/sha1.h>
+#include <dns/util/sha1.h>
 
 #include <cc/data.h>
 
@@ -1234,7 +1234,7 @@ Nsec3Param::getHash(const Name& name) const {
         inlength = SHA1_HASHSIZE;
     } while (n++ < iterations_);
 
-    return (encodeBase32(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
+    return (encodeBase32Hex(vector<uint8_t>(digest, digest + SHA1_HASHSIZE)));
 }
 
 //

+ 7 - 8
src/lib/dns/Makefile.am

@@ -57,12 +57,14 @@ BUILT_SOURCES = rrclass.h rrtype.h rrparamregistry.cc
 
 lib_LTLIBRARIES = libdns++.la
 
-libdns___la_SOURCES = base32.h base32.cc
-libdns___la_SOURCES += base64.h base64.cc
+libdns___la_SOURCES = util/base32hex.h util/base64.h util/base_n.cc
+libdns___la_SOURCES += util/base32hex_from_binary.h
+libdns___la_SOURCES += util/binary_from_base32hex.h
+libdns___la_SOURCES += util/base16_from_binary.h util/binary_from_base16.h
 libdns___la_SOURCES += buffer.h
 libdns___la_SOURCES += dnssectime.h dnssectime.cc
 libdns___la_SOURCES += exceptions.h exceptions.cc
-libdns___la_SOURCES += hex.h hex.cc
+libdns___la_SOURCES += util/hex.h
 libdns___la_SOURCES += message.h message.cc
 libdns___la_SOURCES += messagerenderer.h messagerenderer.cc
 libdns___la_SOURCES += name.h name.cc
@@ -74,7 +76,7 @@ libdns___la_SOURCES += rrsetlist.h rrsetlist.cc
 libdns___la_SOURCES += rrttl.h rrttl.cc
 libdns___la_SOURCES += rrtype.cc
 libdns___la_SOURCES += question.h question.cc
-libdns___la_SOURCES += sha1.h sha1.cc
+libdns___la_SOURCES += util/sha1.h util/sha1.cc
 libdns___la_SOURCES += tsig.h tsig.cc
 
 nodist_libdns___la_SOURCES = rdataclass.cc rrclass.h rrtype.h
@@ -105,9 +107,6 @@ libdns++_include_HEADERS = \
 	rrtype.h \
 	tsig.h
 # Purposely not installing these headers:
-# base32.h # used only internally, and not actually DNS specific
-# base64.h # used only internally, and not actually DNS specific
-# hex.h # used only internally, and not actually DNS specific
-# sha1.h # used only internally, and not actually DNS specific
+# util/*.h: used only internally, and not actually DNS specific
 # rrclass-placeholder.h
 # rrtype-placeholder.h

+ 0 - 198
src/lib/dns/base32.cc

@@ -1,198 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id$
-
-#include <cassert>
-#include <iterator>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-
-#include <exceptions/exceptions.h>
-
-#include <ctype.h>
-#include <stdint.h>
-#include <string.h>
-
-#include <dns/base32.h>
-
-using namespace std;
-
-namespace isc {
-namespace dns {
-
-static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
-
-string
-encodeBase32(const vector<uint8_t>& binary) {
-    ostringstream base32;
-    size_t len = binary.size();
-    size_t pos = 0;
-    while (len > 0) {
-        char buf[9];
-        memset(buf, '=', 8);
-        buf[8] = '\0';
-
-        uint8_t digit = (binary.at(pos) >> 3) & 0x1f;
-        buf[0] = base32hex[digit];
-
-        if (len == 1) {
-            digit = (binary.at(pos) << 2) & 0x1c;
-            buf[1] = base32hex[digit];
-            base32 << buf;
-            break;
-        }
-
-        digit = ((binary.at(pos) << 2) & 0x1c) |
-                ((binary.at(pos + 1) >> 6) & 0x03);
-        buf[1] = base32hex[digit];
-
-        digit = (binary.at(pos + 1) >> 1) & 0x1f;
-        buf[2] = base32hex[digit];
-
-        if (len == 2) {
-            digit = (binary.at(pos + 1) << 4) & 0x10;
-            buf[3] = base32hex[digit];
-            base32 << buf;
-            break;
-        }
-
-        digit = ((binary.at(pos + 1) << 4) & 0x10) |
-                ((binary.at(pos + 2) >> 4) & 0x0f);
-        buf[3] = base32hex[digit];
-        if (len == 3) {
-            digit = (binary.at(pos + 2) << 1) & 0x1e;
-            buf[4] = base32hex[digit];
-            base32 << buf;
-            break;
-        }
-
-        digit = ((binary.at(pos + 2) << 1) & 0x1e) |
-                ((binary.at(pos + 3) >> 7) & 0x01);
-        buf[4] = base32hex[digit];
-
-        digit = (binary.at(pos + 3) >> 2) & 0x1f;
-        buf[5] = base32hex[digit];
-
-        if (len == 4) {
-            digit = (binary.at(pos + 3) << 3) & 0x18;
-            buf[6] = base32hex[digit];
-            base32 << buf;
-            break;
-        }
-
-        digit = ((binary.at(pos + 3) << 3) & 0x18) |
-                ((binary.at(pos + 4) >> 5) & 0x07);
-        buf[6] = base32hex[digit];
-
-        digit = binary.at(pos + 4) & 0x1f;
-        buf[7] = base32hex[digit];
-
-        len -= 5;
-        pos += 5;
-
-        base32 << buf;
-    }
-
-    return (base32.str());
-}
-
-void
-decodeBase32(const string& base32, vector<uint8_t>& result) {
-    ostringstream comp;
-
-    // compress input by removing whitespace
-    const size_t len = base32.length();
-    for (int i = 0; i < len; ++i) {
-        const char c = base32[i];
-        if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
-            continue;
-        }
-        comp << c;
-    }
-
-    // base32 text should be a multiple of 8 bytes long
-    if (comp.str().length() % 8 != 0) {
-        isc_throw(BadBase32String, "Invalid length: " << comp.str().length());
-    }
-
-    istringstream iss(comp.str());
-    result.clear();
-    bool seenpad = false;
-    while (!iss.eof()) {
-        string group;
-
-        iss >> setw(8) >> group;
-        if (iss.bad() || iss.fail()) {
-            isc_throw(BadBase32String,
-                      "Could not parse base32 input: " << base32);
-        }
-
-        uint8_t octet = 0;
-        for (int i = 0; i < 8; ++i) {
-            char c = toupper(group.at(i));
-            int value;
-
-            if (c != '=' && seenpad) {
-                isc_throw(BadBase32String, "Invalid base32 input: " << base32);
-            } else 
-
-            if (c == '=' && !seenpad) {
-                value = 0;
-                seenpad = true;
-            } else {
-                const char* pos = strchr(base32hex, c);
-                if (!pos) {
-                    isc_throw(BadBase32String,
-                              "Invalid base32 input: " << base32);
-                }
-                value = pos - base32hex;
-                assert (value < 32);
-            }
-
-            switch (i) {
-            case 0: octet |= value << 3;
-                    break;
-            case 1: octet |= value >> 2;
-                    result.push_back(octet);
-                    octet = (value & 0x03) << 6;
-                    break;
-            case 2: octet |= value << 1;
-                    break;
-            case 3: octet |= value >> 4;
-                    result.push_back(octet);
-                    octet = (value & 0x0f) << 4;
-                    break;
-            case 4: octet |= value >> 1;
-                    result.push_back(octet);
-                    octet = (value & 0x01) << 7;
-                    break;
-            case 5: octet |= value << 2;
-                    break;
-            case 6: octet |= value >> 3;
-                    result.push_back(octet);
-                    octet = (value & 0x07) << 5;
-                    break;
-            case 7: octet |= value;
-                    result.push_back(octet);
-            }
-        }
-    }
-}
-
-}
-}

+ 0 - 54
src/lib/dns/base32.h

@@ -1,54 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id$
-
-#ifndef __BASE32_H
-#define __BASE32_H 1
-
-#include <stdint.h>
-#include <string>
-#include <vector>
-
-#include <exceptions/exceptions.h>
-
-//
-// Note: this helper module isn't specific to the DNS protocol per se.
-// We should probably move this to somewhere else, possibly in some common
-// utility area.
-//
-
-namespace isc {
-namespace dns {
-
-///
-/// \brief A standard DNS (or ISC) module exception that is thrown if a
-/// base32 decoder encounters an invalid input.
-///
-class BadBase32String : public Exception {
-public:
-    BadBase32String(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-std::string encodeBase32(const std::vector<uint8_t>& binary);
-void decodeBase32(const std::string& hex, std::vector<uint8_t>& result);
-}
-}
-
-#endif  // __BASE32_H
-
-// Local Variables: 
-// mode: c++
-// End: 

+ 0 - 189
src/lib/dns/base64.cc

@@ -1,189 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id$
-
-#include <stdint.h>
-#include <cassert>
-#include <iterator>
-#include <string>
-#include <vector>
-
-#include <boost/archive/iterators/base64_from_binary.hpp>
-#include <boost/archive/iterators/binary_from_base64.hpp>
-#include <boost/archive/iterators/transform_width.hpp>
-
-#include <exceptions/exceptions.h>
-
-#include <dns/base64.h>
-
-using namespace std;
-using namespace boost::archive::iterators;
-
-namespace isc {
-namespace dns {
-
-namespace {
-const char BASE64_PADDING_CHAR = '=';
-const uint8_t BINARY_ZERO_CODE = 0;
-  
-class BinaryNormalizer : public iterator<input_iterator_tag, uint8_t> {
-public:
-    BinaryNormalizer(const vector<uint8_t>::const_iterator& base,
-                     const vector<uint8_t>::const_iterator& base_end) :
-        base_(base), base_end_(base_end), in_pad_(false)
-    {}
-    BinaryNormalizer& operator++()
-    {
-        if (!in_pad_) {
-            ++base_;
-        }
-        if (base_ == base_end_) {
-            in_pad_ = true;
-        }
-        return (*this);
-    }
-    const uint8_t& operator*() const {
-        if (in_pad_) {
-            return (BINARY_ZERO_CODE);
-        } else {
-            return (*base_);
-        }
-    }
-    bool operator==(const BinaryNormalizer& other) const
-    {
-        return (base_ == other.base_);
-    }
-private:
-    vector<uint8_t>::const_iterator base_;
-    const vector<uint8_t>::const_iterator base_end_;
-    bool in_pad_;
-};
-
-typedef
-base64_from_binary<transform_width<BinaryNormalizer, 6, 8> > base64_encoder;
-} // end of anonymous namespace
-
-string
-encodeBase64(const vector<uint8_t>& binary)
-{
-    // calculate the resulting length.  it's the smallest multiple of 4
-    // equal to or larger than 4/3 * original data length.
-    size_t len = ((binary.size() * 4 / 3) + 3) & ~3;
-
-    string base64;
-    base64.reserve(len);
-    base64.assign(base64_encoder(BinaryNormalizer(binary.begin(),
-                                                  binary.end())),
-                  base64_encoder(BinaryNormalizer(binary.end(), binary.end())));
-    assert(len >= base64.length());
-    base64.append(len - base64.length(), BASE64_PADDING_CHAR);
-    return (base64);
-}
-
-namespace {
-const size_t BASE64_MAX_PADDING_CHARS = 2;
-const char BASE64_ZERO_CODE = 'A'; // correspond to 000000(2)
-
-class Base64Normalizer : public iterator<input_iterator_tag, char> {
-public:
-    Base64Normalizer(const string::const_iterator& base,
-                     const string::const_iterator& base_beginpad,
-                     const string::const_iterator& base_end) :
-        base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
-        in_pad_(false)
-    {}
-    Base64Normalizer& operator++()
-    {
-        ++base_;
-        while (base_ != base_end_ && isspace(*base_)) {
-            ++base_;
-        }
-        if (base_ == base_beginpad_) {
-            in_pad_ = true;
-        }
-        return (*this);
-    }
-    const char& operator*() const {
-        if (in_pad_ && *base_ == BASE64_PADDING_CHAR) {
-            return (BASE64_ZERO_CODE);
-        } else {
-            return (*base_);
-        }
-    }
-    bool operator==(const Base64Normalizer& other) const
-    {
-        return (base_ == other.base_);
-    }
-private:
-    string::const_iterator base_;
-    const string::const_iterator base_beginpad_;
-    const string::const_iterator base_end_;
-    bool in_pad_;
-};
-
-typedef
-transform_width<binary_from_base64<Base64Normalizer, char>, 8, 6, char>
-base64_decoder;
-} // end of anonymous namespace
-
-void
-decodeBase64(const string& base64, vector<uint8_t>& result)
-{
-    // enumerate the number of trailing padding characters (=), ignoring
-    // white spaces.  since base64_from_binary doesn't accept padding,
-    // we handle it explicitly.
-    size_t padlen = 0;
-    string::const_reverse_iterator srit = base64.rbegin();
-    string::const_reverse_iterator srit_end = base64.rend();
-    while (srit != srit_end) {
-        char ch = *srit;
-        if (ch == BASE64_PADDING_CHAR) {
-            if (++padlen > BASE64_MAX_PADDING_CHARS) {
-                isc_throw(BadBase64String,
-                          "Too many Base64 padding characters");
-            }
-        } else if (!isspace(ch)) {
-            break;
-        }
-        ++srit;
-    }
-
-    try {
-        result.assign(base64_decoder(Base64Normalizer(base64.begin(),
-                                                      srit.base(),
-                                                      base64.end())),
-                      base64_decoder(Base64Normalizer(base64.end(),
-                                                      base64.end(),
-                                                      base64.end())));
-    } catch (dataflow_exception& ex) {
-        isc_throw(BadBase64String, ex.what());
-    }
-
-    // Confirm the original base64 text is the canonical encoding of the
-    // data.
-    assert(result.size() >= padlen);
-    vector<uint8_t>::const_reverse_iterator rit = result.rbegin();
-    for (int i = 0; i < padlen; ++i, ++rit) {
-        if (*rit != 0) {
-            isc_throw(BadBase64String, "Non 0 bits included in padding");
-        }
-    }
-
-    // strip the padded zero-bit fields
-    result.resize(result.size() - padlen);
-}
-
-}
-}

+ 0 - 108
src/lib/dns/hex.cc

@@ -1,108 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id$
-
-#include <cassert>
-#include <iterator>
-#include <iomanip>
-#include <iostream>
-#include <sstream>
-#include <string>
-#include <vector>
-
-
-#include <exceptions/exceptions.h>
-#include <boost/foreach.hpp>
-#include <ctype.h>
-#include <stdint.h>
-
-#include <dns/hex.h>
-
-using namespace std;
-
-namespace isc {
-namespace dns {
-
-namespace {
-const char hexdigits[] = "0123456789ABCDEF";
-}
-
-std::string
-encodeHex(const std::vector<uint8_t>& binary) {
-    // calculate the resulting length.  it should be twice the
-    // original data length
-    const size_t len = (binary.size() * 2);
-    std::ostringstream hex;
-
-    BOOST_FOREACH(uint8_t octet, binary) {
-        hex << hexdigits[octet >> 4] << hexdigits[octet & 0xf];
-    }
-    assert(len >= hex.str().length());
-    return (hex.str());
-}
-
-void
-decodeHex(const std::string& hex, std::vector<uint8_t>& result) {
-    ostringstream comp;
-
-    // compress input by removing whitespace
-    const size_t len = hex.length();
-    for (int i = 0; i < len; ++i) {
-        char c = hex.at(i);
-        if (c == ' ' || c == '\t' || c == '\r' || c == '\n') {
-            continue;
-        }
-        comp << c;
-    }
-
-    istringstream iss(comp.str());
-    result.clear();
-    char c1, c2;
-
-    iss.width(1);
-    if ((comp.str().length() % 2) == 1) {
-        c2 = '0';
-        iss >> c2;
-
-        const char* pos = strchr(hexdigits, toupper(c2));
-        if (pos == NULL) {
-            isc_throw(BadHexString, "Invalid hex digit");
-        }
-
-        if (!iss.eof() && !iss.bad() && !iss.fail()) {
-            result.push_back(pos - hexdigits);
-        }
-    }
-    while (!iss.eof()) {
-        c1 = c2 = '0';
-        iss >> c1 >> c2;;
-
-        if (iss.eof() || iss.fail() || iss.bad()) {
-            break;
-        }
-
-        const char* pos1 = strchr(hexdigits, toupper(c1));
-        const char* pos2 = strchr(hexdigits, toupper(c2));
-        if (!pos1 || !pos2) {
-            isc_throw(BadHexString, "Invalid hex digit");
-        }
-
-        const uint8_t n = ((pos1 - hexdigits) << 4) | (pos2 - hexdigits);
-        result.push_back(n);
-    }
-}
-
-}
-}

+ 1 - 1
src/lib/dns/rdata/generic/dnskey_48.cc

@@ -22,7 +22,7 @@
 #include <boost/lexical_cast.hpp>
 #include <boost/foreach.hpp>
 
-#include <dns/base64.h>
+#include <dns/util/base64.h>
 #include <dns/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>

+ 1 - 1
src/lib/dns/rdata/generic/ds_43.cc

@@ -22,7 +22,7 @@
 #include <boost/lexical_cast.hpp>
 
 #include <dns/buffer.h>
-#include <dns/hex.h>
+#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>

+ 4 - 4
src/lib/dns/rdata/generic/nsec3_50.cc

@@ -22,10 +22,10 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/base32.h>
+#include <dns/util/base32hex.h>
 #include <dns/buffer.h>
 #include <dns/exceptions.h>
-#include <dns/hex.h>
+#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rrtype.h>
@@ -88,7 +88,7 @@ NSEC3::NSEC3(const string& nsec3_str) :
     if (iss.bad() || iss.fail()) {
         isc_throw(InvalidRdataText, "Invalid NSEC3 hash algorithm");
     }
-    decodeBase32(nextstr, next);
+    decodeBase32Hex(nextstr, next);
 
     uint8_t bitmap[8 * 1024];       // 64k bits
     vector<uint8_t> typebits;
@@ -237,7 +237,7 @@ NSEC3::toText() const
         " " + lexical_cast<string>(static_cast<int>(impl_->flags_)) +
         " " + lexical_cast<string>(static_cast<int>(impl_->iterations_)) +
         " " + encodeHex(impl_->salt_) +
-        " " + encodeBase32(impl_->next_) + s.str());
+        " " + encodeBase32Hex(impl_->next_) + s.str());
 }
 
 void

+ 1 - 1
src/lib/dns/rdata/generic/nsec3param_51.cc

@@ -22,7 +22,7 @@
 #include <boost/lexical_cast.hpp>
 
 #include <dns/buffer.h>
-#include <dns/hex.h>
+#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/name.h>
 #include <dns/rdata.h>

+ 1 - 1
src/lib/dns/rdata/generic/nsec_47.cc

@@ -19,7 +19,7 @@
 #include <sstream>
 #include <vector>
 
-#include <dns/base64.h>
+#include <dns/util/base64.h>
 #include <dns/buffer.h>
 #include <dns/exceptions.h>
 #include <dns/messagerenderer.h>

+ 1 - 1
src/lib/dns/rdata/generic/rrsig_46.cc

@@ -22,7 +22,7 @@
 
 #include <boost/lexical_cast.hpp>
 
-#include <dns/base64.h>
+#include <dns/util/base64.h>
 #include <dns/buffer.h>
 #include <dns/dnssectime.h>
 #include <dns/messagerenderer.h>

+ 1 - 1
src/lib/dns/tests/Makefile.am

@@ -31,7 +31,7 @@ run_unittests_SOURCES += rrset_unittest.cc rrsetlist_unittest.cc
 run_unittests_SOURCES += question_unittest.cc
 run_unittests_SOURCES += rrparamregistry_unittest.cc
 run_unittests_SOURCES += message_unittest.cc
-run_unittests_SOURCES += base32_unittest.cc
+run_unittests_SOURCES += base32hex_unittest.cc
 run_unittests_SOURCES += base64_unittest.cc
 run_unittests_SOURCES += hex_unittest.cc
 run_unittests_SOURCES += sha1_unittest.cc

+ 0 - 107
src/lib/dns/tests/base32_unittest.cc

@@ -1,107 +0,0 @@
-// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
-// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-// $Id$
-
-#include <stdint.h>
-#include <string>
-#include <utility>
-#include <vector>
-
-#include <dns/base32.h>
-
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc::dns;
-
-namespace {
-
-typedef pair<string, string> StringPair;
-
-class Base32Test : public ::testing::Test {
-protected:
-    Base32Test() {
-        // test vectors from RFC4648
-#if 0   // the current implementation doesn't seem to handle '=' correctly
-        test_sequence.push_back(StringPair("", ""));
-        test_sequence.push_back(StringPair("f", "CO======"));
-        test_sequence.push_back(StringPair("fo", "CPNG===="));
-        test_sequence.push_back(StringPair("foo", "CPNMU==="));
-        test_sequence.push_back(StringPair("foob", "CPNMUOG="));
-#endif
-        test_sequence.push_back(StringPair("fooba", "CPNMUOJ1"));
-#if 0                           // this fails
-        test_sequence.push_back(StringPair("foobar", "CPNMUOJ1E8======"));
-#endif
-    }
-    vector<StringPair> test_sequence;
-    vector<uint8_t> decoded_data;
-};
-
-void
-decodeCheck(const string& input_string, vector<uint8_t>& output,
-            const string& expected)
-{
-    decodeBase32(input_string, output);
-    EXPECT_EQ(expected, string(&output[0], &output[0] + output.size()));
-}
-
-
-TEST_F(Base32Test, reversibility) {
-    vector<uint8_t> result;
-//    const string input("H9RSFB7FPF2L8HG35CMPC765TDK23RP6");
-    const string input("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
-    decodeBase32(input, result);
-    string output = encodeBase32(result);
-    EXPECT_EQ(input, output);
-}
-
-TEST_F(Base32Test, decode0) {
-    for (vector<StringPair>::const_iterator it = test_sequence.begin();
-         it != test_sequence.end();
-         ++it) {
-        decodeCheck((*it).second, decoded_data, (*it).first);
-    }
-}
-
-TEST_F(Base32Test, decode1) {
-    vector<uint8_t> result;
-    const std::string input("000G40O40K30E209185GO38E1S8124GJ");
-    decodeBase32(input, result);
-    EXPECT_EQ(20, result.size());
-    for (uint8_t i = 0; i < 20; i++) {
-        EXPECT_EQ((int) i, (int) result[i]);
-    }
-}
-
-TEST_F(Base32Test, encode0) {
-    for (vector<StringPair>::const_iterator it = test_sequence.begin();
-         it != test_sequence.end();
-         ++it) {
-        decoded_data.assign((*it).first.begin(), (*it).first.end());
-        EXPECT_EQ((*it).second, encodeBase32(decoded_data));
-    }
-}
-
-TEST_F(Base32Test, encode1) {
-    const std::string expect("000G40O40K30E209185GO38E1S8124GJ");
-    vector<uint8_t> binary;
-    for (uint8_t i = 0; i < 20; i++) {
-        binary.push_back(i);
-    }
-    string base32 = encodeBase32(binary);
-    EXPECT_EQ(expect, base32);
-}
-}

+ 161 - 0
src/lib/dns/tests/base32hex_unittest.cc

@@ -0,0 +1,161 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdint.h>
+
+#include <cctype>
+#include <string>
+#include <utility>
+#include <vector>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/util/base32hex.h>
+
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dns;
+
+namespace {
+
+typedef pair<string, string> StringPair;
+
+class Base32HexTest : public ::testing::Test {
+protected:
+    Base32HexTest() : encoding_chars("0123456789ABCDEFGHIJKLMNOPQRSTUV=") {
+        // test vectors from RFC4648
+        test_sequence.push_back(StringPair("", ""));
+        test_sequence.push_back(StringPair("f", "CO======"));
+        test_sequence.push_back(StringPair("fo", "CPNG===="));
+        test_sequence.push_back(StringPair("foo", "CPNMU==="));
+        test_sequence.push_back(StringPair("foob", "CPNMUOG="));
+        test_sequence.push_back(StringPair("fooba", "CPNMUOJ1"));
+        test_sequence.push_back(StringPair("foobar", "CPNMUOJ1E8======"));
+
+        // the same data, encoded using lower case chars (testable only
+        // for the decode side)
+        test_sequence_lower.push_back(StringPair("f", "co======"));
+        test_sequence_lower.push_back(StringPair("fo", "cpng===="));
+        test_sequence_lower.push_back(StringPair("foo", "cpnmu==="));
+        test_sequence_lower.push_back(StringPair("foob", "cpnmuog="));
+        test_sequence_lower.push_back(StringPair("fooba", "cpnmuoj1"));
+        test_sequence_lower.push_back(StringPair("foobar",
+                                                 "cpnmuoj1e8======"));
+    }
+    vector<StringPair> test_sequence;
+    vector<StringPair> test_sequence_lower;
+    vector<uint8_t> decoded_data;
+    const string encoding_chars;
+};
+
+void
+decodeCheck(const string& input_string, vector<uint8_t>& output,
+            const string& expected)
+{
+    decodeBase32Hex(input_string, output);
+    EXPECT_EQ(expected, string(&output[0], &output[0] + output.size()));
+}
+
+TEST_F(Base32HexTest, decode) {
+    for (vector<StringPair>::const_iterator it = test_sequence.begin();
+         it != test_sequence.end();
+         ++it) {
+        decodeCheck((*it).second, decoded_data, (*it).first);
+    }
+
+    // whitespace should be allowed
+    decodeCheck("CP NM\tUOG=", decoded_data, "foob");
+    decodeCheck("CPNMU===\n", decoded_data, "foo");
+
+    // invalid number of padding characters
+    EXPECT_THROW(decodeBase32Hex("CPNMU0==", decoded_data), BadValue);
+    EXPECT_THROW(decodeBase32Hex("CO0=====", decoded_data), BadValue);
+    EXPECT_THROW(decodeBase32Hex("CO=======", decoded_data), // too many ='s
+                 BadValue);
+
+    // intermediate padding isn't allowed
+    EXPECT_THROW(decodeBase32Hex("CPNMUOG=CPNMUOG=", decoded_data), BadValue);
+
+    // Non canonical form isn't allowed.
+    // P => 25(11001), so the padding byte would be 01000000
+    EXPECT_THROW(decodeBase32Hex("0P======", decoded_data), BadValue);
+}
+
+TEST_F(Base32HexTest, decodeLower) {
+    for (vector<StringPair>::const_iterator it = test_sequence_lower.begin();
+         it != test_sequence_lower.end();
+         ++it) {
+        decodeCheck((*it).second, decoded_data, (*it).first);
+    }
+}
+
+TEST_F(Base32HexTest, encode) {
+    for (vector<StringPair>::const_iterator it = test_sequence.begin();
+         it != test_sequence.end();
+         ++it) {
+        decoded_data.assign((*it).first.begin(), (*it).first.end());
+        EXPECT_EQ((*it).second, encodeBase32Hex(decoded_data));
+    }
+}
+
+// For Base32Hex we use handmade mappings, so it's prudent to test the
+// entire mapping table explicitly.
+TEST_F(Base32HexTest, decodeMap) {
+    string input(8, '0');       // input placeholder
+
+    // We're going to populate an input string with only the last character
+    // not equal to the zero character ('0') for each valid base32hex encoding
+    // character.  Decoding that input should result in a data stream with
+    // the last byte equal to the numeric value represented by the that
+    // character.  For example, we'll generate and confirm the following:
+    // "00000000" => should be 0 (as a 40bit integer)
+    // "00000001" => should be 1 (as a 40bit integer)
+    // ...
+    // "0000000V" => should be 31 (as a 40bit integer)
+    // We also check the use of an invalid character for the last character
+    // surely fails. '=' should be accepted as a valid padding in this
+    // context; space characters shouldn't be allowed in this context.
+
+    for (int i = 0; i < 256; ++i) {
+        input[7] = i;
+
+        const char ch = toupper(i);
+        const size_t pos = encoding_chars.find(ch);
+        if (pos == string::npos) {
+            EXPECT_THROW(decodeBase32Hex(input, decoded_data), BadValue);
+        } else {
+            decodeBase32Hex(input, decoded_data);
+            if (ch == '=') {
+                EXPECT_EQ(4, decoded_data.size());
+            } else {
+                EXPECT_EQ(5, decoded_data.size());
+                EXPECT_EQ(pos, decoded_data[4]);
+            }
+        }
+    }
+}
+
+TEST_F(Base32HexTest, encodeMap) {
+    for (int i = 0; i < 32; ++i) {
+        decoded_data.assign(4, 0);
+        decoded_data.push_back(i);
+        EXPECT_EQ(encoding_chars[i], encodeBase32Hex(decoded_data)[7]);
+    }
+}
+
+}

+ 9 - 6
src/lib/dns/tests/base64_unittest.cc

@@ -18,11 +18,14 @@
 #include <utility>
 #include <vector>
 
-#include <dns/base64.h>
+#include <exceptions/exceptions.h>
+
+#include <dns/util/base64.h>
 
 #include <gtest/gtest.h>
 
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 
 namespace {
@@ -67,18 +70,18 @@ TEST_F(Base64Test, decode) {
     decodeCheck("Zm9vYmE=\n", decoded_data, "fooba");
 
     // only up to 2 padding characters are allowed
-    EXPECT_THROW(decodeBase64("A===", decoded_data), BadBase64String);
-    EXPECT_THROW(decodeBase64("A= ==", decoded_data), BadBase64String);
+    EXPECT_THROW(decodeBase64("A===", decoded_data), BadValue);
+    EXPECT_THROW(decodeBase64("A= ==", decoded_data), BadValue);
 
     // intermediate padding isn't allowed
-    EXPECT_THROW(decodeBase64("YmE=YmE=", decoded_data), BadBase64String);
+    EXPECT_THROW(decodeBase64("YmE=YmE=", decoded_data), BadValue);
 
     // Non canonical form isn't allowed.
     // Z => 25(011001), m => 38(100110), 9 => 60(111101), so the padding
     // byte would be 0100 0000.
-    EXPECT_THROW(decodeBase64("Zm9=", decoded_data), BadBase64String);
+    EXPECT_THROW(decodeBase64("Zm9=", decoded_data), BadValue);
     // Same for the 1st padding byte.  This would make it 01100000.
-    EXPECT_THROW(decodeBase64("Zm==", decoded_data), BadBase64String);
+    EXPECT_THROW(decodeBase64("Zm==", decoded_data), BadValue);
 }
 
 TEST_F(Base64Test, encode) {

+ 46 - 12
src/lib/dns/tests/hex_unittest.cc

@@ -19,26 +19,28 @@
 #include <vector>
 #include <string>
 
-#include <dns/hex.h>
+#include <exceptions/exceptions.h>
 
-#include <gtest/gtest.h>
+#include <dns/util/hex.h>
 
-#include <dns/tests/unittest_util.h>
+#include <gtest/gtest.h>
 
-using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 
 namespace {
+const string hex_txt("DEADBEEFDECADE");
+const string hex_txt_space("DEAD BEEF DECADE");
+const string hex_txt_lower("deadbeefdecade");
+
 class HexTest : public ::testing::Test {
 protected:
-    HexTest() {}
+    HexTest() : encoding_chars("0123456789ABCDEF") {}
+    vector<uint8_t> decoded_data;
+    const string encoding_chars;
 };
 
-const std::string hex_txt("DEADBEEFDECADE");
-const std::string hex_txt_space("DEAD BEEF DECADE");
-const std::string hex_txt_lower("deadbeefdecade");
-
 TEST_F(HexTest, encodeHex) {
     std::vector<uint8_t> data;
 
@@ -53,8 +55,7 @@ TEST_F(HexTest, encodeHex) {
 }
 
 void
-compareData(const std::vector<uint8_t>& data)
-{
+compareData(const std::vector<uint8_t>& data) {
     EXPECT_EQ(0xde, data[0]);
     EXPECT_EQ(0xad, data[1]);
     EXPECT_EQ(0xbe, data[2]);
@@ -82,7 +83,40 @@ TEST_F(HexTest, decodeHex) {
 
     // Bogus input: should fail
     result.clear();
-    EXPECT_THROW(decodeHex("1x", result), BadHexString);
+    EXPECT_THROW(decodeHex("1x", result), BadValue);
+
+    // Bogus input: encoded string must have an even number of characters.
+    result.clear();
+    EXPECT_THROW(decodeHex("dea", result), BadValue);
+}
+
+// For Hex encode/decode we use handmade mappings, so it's prudent to test the
+// entire mapping table explicitly.
+TEST_F(HexTest, decodeMap) {
+    string input("00");       // input placeholder
+
+    // See Base32HexTest.decodeMap for details of the following tests.
+    for (int i = 0; i < 256; ++i) {
+        input[1] = i;
+
+        const char ch = toupper(i);
+        const size_t pos = encoding_chars.find(ch);
+        if (pos == string::npos) {
+            EXPECT_THROW(decodeHex(input, decoded_data), BadValue);
+        } else {
+            decodeHex(input, decoded_data);
+            EXPECT_EQ(1, decoded_data.size());
+            EXPECT_EQ(pos, decoded_data[0]);
+        }
+    }
+}
+
+TEST_F(HexTest, encodeMap) {
+    for (int i = 0; i < 16; ++i) {
+        decoded_data.clear();
+        decoded_data.push_back(i);
+        EXPECT_EQ(encoding_chars[i], encodeHex(decoded_data)[1]);
+    }
 }
 
 }

+ 4 - 3
src/lib/dns/tests/rdata_dnskey_unittest.cc

@@ -16,7 +16,8 @@
 
 #include <string>
 
-#include <dns/base64.h>
+#include <exceptions/exceptions.h>
+
 #include <dns/buffer.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
@@ -31,6 +32,7 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 
@@ -68,8 +70,7 @@ TEST_F(Rdata_DNSKEY_Test, badText) {
                  InvalidRdataText);
     EXPECT_THROW(generic::DNSKEY("257 3 500 BAAAAAAAAAAAD"),
                  InvalidRdataText);
-    EXPECT_THROW(generic::DNSKEY("257 3 5 BAAAAAAAAAAAD"),
-                 BadBase64String);
+    EXPECT_THROW(generic::DNSKEY("257 3 5 BAAAAAAAAAAAD"), BadValue);
 }
 
 TEST_F(Rdata_DNSKEY_Test, DISABLED_badText) {

+ 19 - 12
src/lib/dns/tests/rdata_nsec3_unittest.cc

@@ -16,10 +16,11 @@
 
 #include <string>
 
-#include <dns/base32.h>
+#include <exceptions/exceptions.h>
+
 #include <dns/buffer.h>
 #include <dns/exceptions.h>
-#include <dns/hex.h>
+#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -33,16 +34,19 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 
 namespace {
 class Rdata_NSEC3_Test : public RdataTest {
     // there's nothing to specialize
+public:
+    Rdata_NSEC3_Test() :
+        nsec3_txt("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
+                  "NS SOA RRSIG DNSKEY NSEC3PARAM") {}
+    string nsec3_txt;
 };
-string nsec3_txt("1 1 1 D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
-                 "NS SOA RRSIG DNSKEY NSEC3PARAM");
-
 
 TEST_F(Rdata_NSEC3_Test, toText) {
     const generic::NSEC3 rdata_nsec3(nsec3_txt);
@@ -50,30 +54,33 @@ TEST_F(Rdata_NSEC3_Test, toText) {
 }
 
 TEST_F(Rdata_NSEC3_Test, badText) {
-    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEE "
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEEE "
                                             "0123456789ABCDEFGHIJKLMNOPQRSTUV "
                                             "BIFF POW SPOON"),
                  InvalidRdataText);
     EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEE "
                                             "WXYZWXYZWXYZ=WXYZWXYZ==WXYZWXYZW "
                                             "A NS SOA"),
-                 BadBase32String);
-    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1000000 1 1 ADDAFEE "
+                 BadValue);     // bad hex
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1 ADDAFEEE "
+                                            "WXYZWXYZWXYZ=WXYZWXYZ==WXYZWXYZW "
+                                            "A NS SOA"),
+                 BadValue);     // bad base32hex
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1000000 1 1 ADDAFEEE "
                                             "0123456789ABCDEFGHIJKLMNOPQRSTUV "
                                             "A NS SOA"),
                  InvalidRdataText);
-    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1000000 1 ADDAFEE "
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1000000 1 ADDAFEEE "
                                             "0123456789ABCDEFGHIJKLMNOPQRSTUV "
                                             "A NS SOA"),
                  InvalidRdataText);
-    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1000000 ADDAFEE "
+    EXPECT_THROW(generic::NSEC3 rdata_nsec3("1 1 1000000 ADDAFEEE "
                                             "0123456789ABCDEFGHIJKLMNOPQRSTUV "
                                             "A NS SOA"),
                  InvalidRdataText);
 }
 
-TEST_F(Rdata_NSEC3_Test, DISABLED_badText) {
-    // this currently fails
+TEST_F(Rdata_NSEC3_Test, DISABLED_badText) { // this currently fails
     EXPECT_THROW(generic::NSEC3(
                      "1 1 1D399EAAB H9RSFB7FPF2L8HG35CMPC765TDK23RP6 "
                      "NS SOA RRSIG DNSKEY NSEC3PARAM"), InvalidRdataText);

+ 6 - 3
src/lib/dns/tests/rdata_nsec3param_unittest.cc

@@ -16,9 +16,11 @@
 
 #include <string>
 
-#include <dns/base32.h>
+#include <exceptions/exceptions.h>
+
+#include <dns/util/base32hex.h>
 #include <dns/buffer.h>
-#include <dns/hex.h>
+#include <dns/util/hex.h>
 #include <dns/messagerenderer.h>
 #include <dns/rdata.h>
 #include <dns/rdataclass.h>
@@ -32,6 +34,7 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 
@@ -47,7 +50,7 @@ TEST_F(Rdata_NSEC3PARAM_Test, toText) {
 }
 
 TEST_F(Rdata_NSEC3PARAM_Test, badText) {
-    EXPECT_THROW(generic::NSEC3PARAM("1 1 1 SPORK"), BadHexString);
+    EXPECT_THROW(generic::NSEC3PARAM("1 1 1 SPORK"), BadValue); // bad hex
     EXPECT_THROW(generic::NSEC3PARAM("100000 1 1 ADDAFEE"), InvalidRdataText);
     EXPECT_THROW(generic::NSEC3PARAM("1 100000 1 ADDAFEE"), InvalidRdataText);
     EXPECT_THROW(generic::NSEC3PARAM("1 1 100000 ADDAFEE"), InvalidRdataText);

+ 6 - 3
src/lib/dns/tests/rdata_rrsig_unittest.cc

@@ -14,7 +14,8 @@
 
 // $Id$
 
-#include <dns/base64.h>
+#include <exceptions/exceptions.h>
+
 #include <dns/buffer.h>
 #include <dns/dnssectime.h>
 #include <dns/messagerenderer.h>
@@ -30,6 +31,7 @@
 
 using isc::UnitTestUtil;
 using namespace std;
+using namespace isc;
 using namespace isc::dns;
 using namespace isc::dns::rdata;
 
@@ -81,10 +83,11 @@ TEST_F(Rdata_RRSIG_Test, badText) {
                      "diGdLIrFabqr72af2rUq+UDBKMWXujwZTZUTws32sVldDPk/"
                      "NbuacJM25fQXfv5mO3Af7TOoow3AjMaVG9icjCW0V55WcWQU"
                      "f49t+sXKPzbipN9g+s1ZPiIyofc="), InvalidRdataText);
-    EXPECT_THROW(const generic::RRSIG sig("A 5 4 43200 "
+    EXPECT_THROW(const generic::RRSIG sig(
+                     "A 5 4 43200 "
                      "20100223214617 20100222214617 8496 isc.org. "
                      "EEeeeeeeEEEeeeeeeGaaahAAAAAAAAHHHHHHHHHHH!="),
-                     BadBase64String);
+                 BadValue);     // bad base64 input
 }
 
 TEST_F(Rdata_RRSIG_Test, DISABLED_badText) {

+ 1 - 1
src/lib/dns/tests/sha1_unittest.cc

@@ -17,7 +17,7 @@
 #include <stdint.h>
 #include <string>
 
-#include <dns/sha1.h>
+#include <dns/util/sha1.h>
 
 #include <gtest/gtest.h>
 

+ 31 - 0
src/lib/dns/util/README

@@ -0,0 +1,31 @@
+This "util" directory is provided for utility header files and
+implementations that are internally used in the DNS library
+(libdns++).
+
+The functionality provided in these tools is generally available in
+other external or perhaps system supplied libraries.  The basic
+development policy of BIND 10 is to avoid "reinventing wheels" unless
+they belong to the exact technology area that BIND 10 targets (e.g.,
+DNS).  However, libdns++ is a very core part of BIND 10, and is also
+intended to be used as a public library, so dependency from libdns++
+to external libraries should be minimized.  The utilities in this
+directory are provided balancing two policies and as a kind of
+compromise.
+
+The header files in this directory are therefore not intended to be
+installed.  Likewise, classes and public functions defined in this
+directory are not intended to be used outside libdns++, although we
+cannot prohibit it at the language level.
+
+They are not even expected to be used in other modules of BIND 10 than
+libdns++ based on the basic policy explained above.  Other modules
+should only rely on the DNS specific interface that may internally
+rely on these utility interfaces, or should use external libraries if
+the other module really needs to use the utility feature directly.
+There seem to be some violations as of this writing, but we should
+eventually fix it.  A notable example is the SHA1 interfaces.  They
+are defined here in the context of NSEC3 processing, but, in fact,
+they are not even used from any of the other libdns++ classes or
+functions.  The SHA1 related interfaces should be moved to the
+application that needs it or the application should only access it
+through DNS specific interfaces defined in libdns++.

+ 110 - 0
src/lib/dns/util/base16_from_binary.h

@@ -0,0 +1,110 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
+#define BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// base16_from_binary.h (derived from boost base64_from_binary.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+#include <cstddef> // size_t
+#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
+#if defined(BOOST_NO_STDC_NAMESPACE)
+namespace std{ 
+    using ::size_t; 
+} // namespace std
+#endif
+
+#include <boost/serialization/pfto.hpp>
+
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/archive/iterators/dataflow_exception.hpp>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert binary integers to base16 characters
+
+namespace detail {
+
+template<class CharType>
+struct from_4_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char * lookup_table = 
+            "0123456789"
+            "ABCDEF";
+        assert(t < 16);
+        return lookup_table[static_cast<size_t>(t)];
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_4_bit<CharType>,
+//      transform_width<Base, 4, sizeof(Base::value_type) * 8, CharType>
+//  > base16_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+//template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class base16_from_binary : 
+    public transform_iterator<
+        detail::from_4_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        BOOST_DEDUCED_TYPENAME detail::from_4_bit<CharType>,
+        Base
+    > super_t;
+
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    base16_from_binary(BOOST_PFTO_WRAPPER(T) start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))),
+            detail::from_4_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    base16_from_binary(const base16_from_binary & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::from_4_bit<CharType>()
+        )
+    {}
+//    base16_from_binary(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BASE16_FROM_BINARY_HPP

+ 26 - 17
src/lib/dns/base64.h

@@ -14,15 +14,13 @@
 
 // $Id$
 
-#ifndef __BASE64_H
-#define __BASE64_H 1
+#ifndef __BASE32HEX_H
+#define __BASE32HEX_H 1
 
 #include <stdint.h>
 #include <string>
 #include <vector>
 
-#include <exceptions/exceptions.h>
-
 //
 // Note: this helper module isn't specific to the DNS protocol per se.
 // We should probably move this to somewhere else, possibly in some common
@@ -32,23 +30,34 @@
 namespace isc {
 namespace dns {
 
+/// \brief Encode binary data in the base32hex format.
+///
+/// The underlying implementation is shared with \c encodeBase64, and all
+/// description except the format (base32hex) equally applies.
+///
+/// Note: the encoding format is base32hex, not base32.
+///
+/// \param binary A vector object storing the data to be encoded. 
+/// \return A newly created string that stores base32hex encoded value for
+/// binary.
+std::string encodeBase32Hex(const std::vector<uint8_t>& binary);
+
+/// \brief Decode a text encoded in the base32hex format into the
+/// original %data.
+///
+/// The underlying implementation is shared with \c decodeBase64, and all
+/// description except the format (base32hex) equally applies.
 ///
-/// \brief A standard DNS (or ISC) module exception that is thrown a Base64
-/// decoder encounters an invalid input.
+/// Note: the encoding format is base32hex, not base32.
 ///
-class BadBase64String : public Exception {
-public:
-    BadBase64String(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
-std::string encodeBase64(const std::vector<uint8_t>& binary);
-void decodeBase64(const std::string& base64, std::vector<uint8_t>& result);
+/// \param input A text encoded in the base32hex format.
+/// \param result A vector in which the decoded %data is to be stored.
+void decodeBase32Hex(const std::string& input, std::vector<uint8_t>& result);
 }
 }
 
-#endif  // __BASE64_H
+#endif  // __BASE32HEX_H
 
-// Local Variables: 
+// Local Variables:
 // mode: c++
-// End: 
+// End:

+ 110 - 0
src/lib/dns/util/base32hex_from_binary.h

@@ -0,0 +1,110 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
+#define BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// base32hex_from_binary.h (derived from boost base64_from_binary.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+#include <cstddef> // size_t
+#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
+#if defined(BOOST_NO_STDC_NAMESPACE)
+namespace std{ 
+    using ::size_t; 
+} // namespace std
+#endif
+
+#include <boost/serialization/pfto.hpp>
+
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/archive/iterators/dataflow_exception.hpp>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert binary integers to base32hex characters
+
+namespace detail {
+
+template<class CharType>
+struct from_5_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char * lookup_table = 
+            "0123456789"
+            "ABCDEFGHIJKLMNOPQRSTUV";
+        assert(t < 32);
+        return lookup_table[static_cast<size_t>(t)];
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_5_bit<CharType>,
+//      transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
+//  > base32hex_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+//template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class base32hex_from_binary : 
+    public transform_iterator<
+        detail::from_5_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        BOOST_DEDUCED_TYPENAME detail::from_5_bit<CharType>,
+        Base
+    > super_t;
+
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    base32hex_from_binary(BOOST_PFTO_WRAPPER(T) start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))),
+            detail::from_5_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    base32hex_from_binary(const base32hex_from_binary & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::from_5_bit<CharType>()
+        )
+    {}
+//    base32hex_from_binary(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BASE32HEX_FROM_BINARY_HPP

+ 78 - 0
src/lib/dns/util/base64.h

@@ -0,0 +1,78 @@
+// Copyright (C) 2009  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#ifndef __BASE64_H
+#define __BASE64_H 1
+
+#include <stdint.h>
+#include <string>
+#include <vector>
+
+//
+// Note: this helper module isn't specific to the DNS protocol per se.
+// We should probably move this to somewhere else, possibly in some common
+// utility area.
+//
+
+namespace isc {
+namespace dns {
+
+/// \brief Encode binary data in the base64 format.
+///
+/// This function returns a new \c std::string object that stores a text
+/// encoded in the base64 format for the given \c binary %data.
+/// The resulting string will be a valid, canonical form of base64
+/// representation as specified in RFC4648.
+///
+/// If memory allocation for the returned string fails, a corresponding
+/// standard exception will be thrown.  This function never throws exceptions
+/// otherwise.
+///
+/// \param binary A vector object storing the data to be encoded. 
+/// \return A newly created string that stores base64 encoded value for binary.
+std::string encodeBase64(const std::vector<uint8_t>& binary);
+
+/// \brief Decode a text encoded in the base64 format into the original %data.
+///
+/// The \c input argument must be a valid string represented in the base64
+/// format as specified in RFC4648.  Space characters (spaces, tabs, newlines)
+/// can be included in \c input and will be ignored.  Without spaces, the
+/// length of string must be a multiple of 4 bytes with necessary paddings.
+/// Also it must be encoded using the canonical encoding (see RFC4648).
+/// If any of these conditions is not met, an exception of class
+/// \c isc::BadValue will be thrown.
+///
+/// If \c result doesn't have sufficient capacity to store all decoded %data
+/// and memory allocation fails, a corresponding standard exception will be
+/// thrown.  If the caller knows the necessary length (which can in theory
+/// be calculated from the input string), this situation can be avoided by
+/// reserving sufficient space for \c result beforehand.
+///
+/// Any existing %data in \c result will be removed.  This is the case in some
+/// of the cases where an exception is thrown; that is, this function only
+/// provides the basic exception guarantee.
+///
+/// \param input A text encoded in the base64 format.
+/// \param result A vector in which the decoded %data is to be stored.
+void decodeBase64(const std::string& input, std::vector<uint8_t>& result);
+}
+}
+
+#endif  // __BASE64_H
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 400 - 0
src/lib/dns/util/base_n.cc

@@ -0,0 +1,400 @@
+// Copyright (C) 2010  Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+// $Id$
+
+#include <stdint.h>
+#include <cassert>
+#include <iterator>
+#include <string>
+#include <vector>
+
+#include <boost/archive/iterators/base64_from_binary.hpp>
+#include <boost/archive/iterators/binary_from_base64.hpp>
+#include <boost/archive/iterators/transform_width.hpp>
+#include <boost/math/common_factor.hpp>
+
+#include <dns/util/base32hex_from_binary.h>
+#include <dns/util/binary_from_base32hex.h>
+
+#include <dns/util/base16_from_binary.h>
+#include <dns/util/binary_from_base16.h>
+
+#include <exceptions/exceptions.h>
+
+#include <dns/util/base32hex.h>
+#include <dns/util/base64.h>
+
+using namespace std;
+using namespace boost::archive::iterators;
+
+namespace isc {
+namespace dns {
+
+// In the following anonymous namespace, we provide a generic framework
+// to encode/decode baseN format.  We use the following tools:
+// - boost base64_from_binary/binary_from_base64: provide mapping table for
+//   base64.
+//   These classes take another iterator (Base) as a template argument, and
+//   their dereference operator (operator*()) first retrieves an input value
+//   from Base via Base::operator* and converts the value using their mapping
+//   table.  The converted value is returned as their own operator*.
+// - base{32hex,16}_from_binary/binary_from_base{32hex,16}: provide mapping
+//   table for base32hex and base16.  A straightforward variation of their
+//   base64 counterparts.
+// - EncodeNormalizer/DecodeNormalizer: supplemental filter handling baseN
+//   padding characters (=)
+// - boost transform_width: an iterator framework for handling data stream
+//   per bit-group.  It takes another iterator (Base) and output/input bit
+//   numbers (BitsOut/BitsIn) template arguments.  A transform_width object
+//   internally maintains a bit stream, which can be retrieved per BitsOut
+//   bits via its dereference operator (operator*()).  It builds the stream
+//   by internally iterating over the Base object via Base::operator++ and
+//   Base::operator*, using the least BitsIn bits of the result of
+//   Base::operator*.  In our usage BitsIn for encoding and BitsOut for
+//   decoding are always 8 (# of bits for one byte).
+//
+// Its dereference operator
+//   retrieves BitsIn bits from the result of "*Base" (if necessary it
+//   internally calls ++Base) 
+//
+// A conceptual description of how the encoding and decoding work is as
+// follows:
+// Encoding:
+//   input binary data => Normalizer (append sufficient number of 0 bits)
+//                     => transform_width (extract bit groups from the original
+//                                         stream)
+//                     => baseXX_from_binary (convert each bit group to an
+//                                            encoded byte using the mapping)
+// Decoding:
+//   input baseXX text => Normalizer (convert '='s to the encoded characters
+//                                    corresponding to 0, e.g. 'A's in base64)
+//                     => binary_from_baseXX (convert each encoded byte into
+//                                            the original group bit)
+//                     => transform_width (build original byte stream by
+//                                         concatenating the decoded bit
+//                                         stream)
+//
+// Below, we define a set of templated classes to handle different parameters
+// for different encoding algorithms.
+namespace {
+// Common constants used for all baseN encoding.
+const char BASE_PADDING_CHAR = '=';
+const uint8_t BINARY_ZERO_CODE = 0;
+  
+// EncodeNormalizer is an input iterator intended to be used as a filter
+// between the binary stream and baseXX_from_binary translator (via
+// transform_width).  An EncodeNormalizer object is configured with two
+// iterators (base and base_end), specifying the head and end of the input
+// stream.  It internally iterators over the original stream, and return
+// each byte of the stream intact via its dereference operator until it
+// reaches the end of the stream.  After that the EncodeNormalizer object
+// will return 0 no matter how many times it is subsequently incremented.
+// This is necessary because the input binary stream may not contain
+// sufficient bits for a full encoded text while baseXX_from_binary expects
+// a sufficient length of input.
+// Note: this class is intended to be used within this implementation file,
+// and assumes "base < base_end" on construction without validating the
+// arguments.  The behavior is undefined if this assumption doesn't hold.
+class EncodeNormalizer : public iterator<input_iterator_tag, uint8_t> {
+public:
+    EncodeNormalizer(const vector<uint8_t>::const_iterator& base,
+                     const vector<uint8_t>::const_iterator& base_end) :
+        base_(base), base_end_(base_end), in_pad_(false)
+    {}
+    EncodeNormalizer& operator++() {
+        if (!in_pad_) {
+            ++base_;
+        }
+        if (base_ == base_end_) {
+            in_pad_ = true;
+        }
+        return (*this);
+    }
+    const uint8_t& operator*() const {
+        if (in_pad_) {
+            return (BINARY_ZERO_CODE);
+        } else {
+            return (*base_);
+        }
+    }
+    bool operator==(const EncodeNormalizer& other) const {
+        return (base_ == other.base_);
+    }
+private:
+    vector<uint8_t>::const_iterator base_;
+    const vector<uint8_t>::const_iterator base_end_;
+    bool in_pad_;
+};
+
+// DecodeNormalizer is an input iterator intended to be used as a filter
+// between the encoded baseX stream and binary_from_baseXX.
+// A DecodeNormalizer object is configured with three string iterators
+// (base, base_beinpad, and base_beginpad), specifying the head of the string,
+// the beginning position of baseX padding (when there's padding), and
+// end of the string, respectively.  It internally iterators over the original
+// stream, and return each character of the encoded string via its dereference
+// operator until it reaches base_beginpad.  After that the DecodeNormalizer
+// will return the encoding character corresponding to the all-0 value
+// (which is specified on construction via base_zero_code.  see also
+// BaseZeroCode below).  This translation is necessary because
+// binary_from_baseXX doesn't accept the padding character (i.e. '=').
+// Note: this class is intended to be used within this implementation file,
+// and for simplicity assumes "base < base_beginpad <= base_end" on
+// construction without validating the arguments.  The behavior is undefined
+// if this assumption doesn't hold.
+class DecodeNormalizer : public iterator<input_iterator_tag, char> {
+public:
+    DecodeNormalizer(const char base_zero_code,
+                     const string::const_iterator& base,
+                     const string::const_iterator& base_beginpad,
+                     const string::const_iterator& base_end) :
+        base_zero_code_(base_zero_code),
+        base_(base), base_beginpad_(base_beginpad), base_end_(base_end),
+        in_pad_(false)
+    {}
+    DecodeNormalizer& operator++() {
+        ++base_;
+        while (base_ != base_end_ && isspace(*base_)) {
+            ++base_;
+        }
+        if (base_ == base_beginpad_) {
+            in_pad_ = true;
+        }
+        return (*this);
+    }
+    const char& operator*() const {
+        if (in_pad_ && *base_ == BASE_PADDING_CHAR) {
+            return (base_zero_code_);
+        } else {
+            return (*base_);
+        }
+    }
+    bool operator==(const DecodeNormalizer& other) const {
+        return (base_ == other.base_);
+    }
+private:
+    const char base_zero_code_;
+    string::const_iterator base_;
+    const string::const_iterator base_beginpad_;
+    const string::const_iterator base_end_;
+    bool in_pad_;
+};
+
+// BitsPerChunk: number of bits to be converted using the baseN mapping table.
+//               e.g. 6 for base64.
+// BaseZeroCode: the byte character that represents a value of 0 in
+//               the corresponding encoding.  e.g. 'A' for base64.
+// Encoder: baseX_from_binary<transform_width<EncodeNormalizer,
+//                                            BitsPerChunk, 8> >
+// Decoder: transform_width<binary_from_baseX<DecodeNormalizer>,
+//                          8, BitsPerChunk>
+template <int BitsPerChunk, char BaseZeroCode,
+          typename Encoder, typename Decoder>
+struct BaseNTransformer {
+    static string encode(const vector<uint8_t>& binary);
+    static void decode(const char* algorithm,
+                       const string& base64, vector<uint8_t>& result);
+
+    // BITS_PER_GROUP is the number of bits for the smallest possible (non
+    // empty) bit string that can be converted to a valid baseN encoded text
+    // without padding.  It's the least common multiple of 8 and BitsPerChunk,
+    // e.g. 24 for base64.
+    static const int BITS_PER_GROUP =
+        boost::math::static_lcm<BitsPerChunk, 8>::value;
+
+    // MAX_PADDING_CHARS is the maximum number of padding characters
+    // that can appear in a valid baseN encoded text.
+    // It's group_len - chars_for_byte, where group_len is the number of
+    // encoded characters to represent BITS_PER_GROUP bits, and
+    // chars_for_byte is the number of encoded character that is needed to
+    // represent a single byte, which is ceil(8 / BitsPerChunk).
+    // For example, for base64 we need two encoded characters to represent a
+    // byte, and each group consists of 4 encoded characters, so
+    // MAX_PADDING_CHARS is 4 - 2 = 2.
+    static const int MAX_PADDING_CHARS =
+        BITS_PER_GROUP / BitsPerChunk -
+        (8 / BitsPerChunk + ((8 % BitsPerChunk) == 0 ? 0 : 1));
+}; 
+
+template <int BitsPerChunk, char BaseZeroCode,
+          typename Encoder, typename Decoder>
+string
+BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::encode(
+    const vector<uint8_t>& binary)
+{
+    // calculate the resulting length.
+    size_t bits = binary.size() * 8;
+    if (bits % BITS_PER_GROUP > 0) {
+        bits += (BITS_PER_GROUP - (bits % BITS_PER_GROUP));
+    }
+    const size_t len = bits / BitsPerChunk;
+
+    string result;
+    result.reserve(len);
+    result.assign(Encoder(EncodeNormalizer(binary.begin(), binary.end())),
+                  Encoder(EncodeNormalizer(binary.end(), binary.end())));
+    assert(len >= result.length());
+    result.append(len - result.length(), BASE_PADDING_CHAR);
+    return (result);
+}
+
+template <int BitsPerChunk, char BaseZeroCode,
+          typename Encoder, typename Decoder>
+void
+BaseNTransformer<BitsPerChunk, BaseZeroCode, Encoder, Decoder>::decode(
+    const char* const algorithm,
+    const string& input,
+    vector<uint8_t>& result)
+{
+    // enumerate the number of trailing padding characters (=), ignoring
+    // white spaces.  since baseN_from_binary doesn't accept padding,
+    // we handle it explicitly.
+    size_t padchars = 0;
+    string::const_reverse_iterator srit = input.rbegin();
+    string::const_reverse_iterator srit_end = input.rend();
+    while (srit != srit_end) {
+        char ch = *srit;
+        if (ch == BASE_PADDING_CHAR) {
+            if (++padchars > MAX_PADDING_CHARS) {
+                isc_throw(BadValue, "Too many " << algorithm
+                          << " padding characters: " << input);
+            }
+        } else if (!isspace(ch)) {
+            break;
+        }
+        ++srit;
+    }
+    // then calculate the number of padding bits corresponding to the padding
+    // characters.  In general, the padding bits consist of all-zero
+    // trailing bits of the last encoded character followed by zero bits
+    // represented by the padding characters:
+    // 1st pad  2nd pad  3rd pad...
+    // +++===== =======  ===...    (+: from encoded chars, =: from pad chars)
+    // 0000...0 0......0 000...
+    // 0      7 8     15 16.... (bits)
+    // The number of bits for the '==...' part is padchars * BitsPerChunk.
+    // So the total number of padding bits is the smallest multiple of 8 
+    // that is >= padchars * BitsPerChunk.
+    // (Below, note the common idiom of the bitwise AND with ~7.  It clears the
+    // lowest three bits, so has the effect of rounding the result down to the
+    // nearest multiple of 8)
+    const size_t padbits = (padchars * BitsPerChunk + 7) & ~7;
+
+    // In some encoding algorithm, it could happen that a padding byte would
+    // contain a full set of encoded bits, which is not allowed by definition
+    // of padding.  For example, if BitsPerChunk is 5, the following
+    // representation could happen:
+    // ++00000= (+: from encoded chars, 0: encoded char for '0', =: pad chars)
+    // 0      7 (bits)
+    // This must actually be encoded as follows:
+    // ++======
+    // 0      7 (bits)
+    // The following check rejects this type of invalid encoding.
+    if (padbits > BitsPerChunk * (padchars + 1)) {
+        isc_throw(BadValue, "Invalid " << algorithm << "padding: " << input);
+    }
+
+    // convert the number of bits in bytes for convenience.
+    const size_t padbytes = padbits / 8;
+
+    try {
+        result.assign(Decoder(DecodeNormalizer(BaseZeroCode, input.begin(),
+                                               srit.base(), input.end())),
+                      Decoder(DecodeNormalizer(BaseZeroCode, input.end(),
+                                               input.end(), input.end())));
+    } catch (const dataflow_exception& ex) {
+        // convert any boost exceptions into our local one.
+        isc_throw(BadValue, ex.what());
+    }
+
+    // Confirm the original BaseX text is the canonical encoding of the
+    // data, that is, that the first byte of padding is indeed 0.
+    // (DecodeNormalizer and binary_from_baseXX ensure that the rest of the
+    // padding is all zero).
+    assert(result.size() >= padbytes);
+    if (padbytes > 0 && *(result.end() - padbytes) != 0) {
+            isc_throw(BadValue, "Non 0 bits included in " << algorithm
+                      << " padding: " << input);
+    }
+
+    // strip the padded zero-bit fields
+    result.resize(result.size() - padbytes);
+}
+
+//
+// Instantiation for BASE-64
+//
+typedef
+base64_from_binary<transform_width<EncodeNormalizer, 6, 8> > base64_encoder;
+typedef
+transform_width<binary_from_base64<DecodeNormalizer>, 8, 6> base64_decoder;
+typedef BaseNTransformer<6, 'A', base64_encoder, base64_decoder>
+Base64Transformer;
+
+//
+// Instantiation for BASE-32HEX
+//
+typedef
+base32hex_from_binary<transform_width<EncodeNormalizer, 5, 8> >
+base32hex_encoder;
+typedef
+transform_width<binary_from_base32hex<DecodeNormalizer>, 8, 5>
+base32hex_decoder;
+typedef BaseNTransformer<5, '0', base32hex_encoder, base32hex_decoder>
+Base32HexTransformer;
+
+//
+// Instantiation for BASE-16 (HEX)
+//
+typedef
+base16_from_binary<transform_width<EncodeNormalizer, 4, 8> > base16_encoder;
+typedef
+transform_width<binary_from_base16<DecodeNormalizer>, 8, 4> base16_decoder;
+typedef BaseNTransformer<4, '0', base16_encoder, base16_decoder>
+Base16Transformer;
+}
+
+string
+encodeBase64(const vector<uint8_t>& binary) {
+    return (Base64Transformer::encode(binary));
+}
+
+void
+decodeBase64(const string& input, vector<uint8_t>& result) {
+    Base64Transformer::decode("base64", input, result);
+}
+
+string
+encodeBase32Hex(const vector<uint8_t>& binary) {
+    return (Base32HexTransformer::encode(binary));
+}
+
+void
+decodeBase32Hex(const string& input, vector<uint8_t>& result) {
+    Base32HexTransformer::decode("base32hex", input, result);
+}
+
+string
+encodeHex(const vector<uint8_t>& binary) {
+    return (Base16Transformer::encode(binary));
+}
+
+void
+decodeHex(const string& input, vector<uint8_t>& result) {
+    Base16Transformer::decode("base16", input, result);
+}
+
+}
+}

+ 125 - 0
src/lib/dns/util/binary_from_base16.h

@@ -0,0 +1,125 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
+#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// binary_from_base16.h (derived from boost binary_from_base64.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
+#include <boost/serialization/throw_exception.hpp>
+#include <boost/serialization/pfto.hpp>
+#include <boost/static_assert.hpp>
+
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/archive/iterators/dataflow_exception.hpp>
+
+#include <exceptions/exceptions.h>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert base16 characters to binary data
+
+namespace detail {
+
+template<class CharType>
+struct to_4_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char lookup_table[] = {
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 20-2f
+             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 30-3f
+            -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 40-4f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 50-5f
+            -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1  // 60-6f
+        };
+        // metrowerks trips this assertion - how come?
+        #if ! defined(__MWERKS__)
+        BOOST_STATIC_ASSERT(0x70 == sizeof(lookup_table));
+        #endif
+        signed char value = -1;
+        if((unsigned)t < sizeof(lookup_table))
+            value = lookup_table[(unsigned)t];
+        if(-1 == value) { 
+            isc_throw(isc::BadValue,
+                      "attempt to decode a value not in base16 char set");
+        }
+        return value;
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_4_bit<CharType>,
+//      transform_width<Base, 4, sizeof(Base::value_type) * 8, CharType>
+//  > base16_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class binary_from_base16 : public
+    transform_iterator<
+        detail::to_4_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        detail::to_4_bit<CharType>,
+        Base
+    > super_t;
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    binary_from_base16(BOOST_PFTO_WRAPPER(T)  start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))), 
+            detail::to_4_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    binary_from_base16(const binary_from_base16 & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::to_4_bit<CharType>()
+        )
+    {}
+//    binary_from_base16(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE16_HPP
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 126 - 0
src/lib/dns/util/binary_from_base32hex.h

@@ -0,0 +1,126 @@
+#ifndef BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
+#define BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
+
+// MS compatible compilers support #pragma once
+#if defined(_MSC_VER) && (_MSC_VER >= 1020)
+# pragma once
+#endif
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// binary_from_base32hex.h (derived from boost binary_from_base64.hpp)
+
+// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+//  See http://www.boost.org for updates, documentation, and revision history.
+
+#include <cassert>
+
+#include <boost/config.hpp> // for BOOST_DEDUCED_TYPENAME
+#include <boost/serialization/throw_exception.hpp>
+#include <boost/serialization/pfto.hpp>
+#include <boost/static_assert.hpp>
+
+#include <boost/iterator/transform_iterator.hpp>
+#include <boost/archive/iterators/dataflow_exception.hpp>
+
+#include <exceptions/exceptions.h>
+
+namespace boost { 
+namespace archive {
+namespace iterators {
+
+/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
+// convert base32hex characters to binary data
+
+namespace detail {
+
+template<class CharType>
+struct to_5_bit {
+    typedef CharType result_type;
+    CharType operator()(CharType t) const{
+        const char lookup_table[] = {
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 00-0f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 10-1f
+            -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 20-2f
+             0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, // 30-3f
+            -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // 40-4f
+            25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,-1, // 50-5f
+            -1,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24, // 60-6f
+            25,26,27,28,29,30,31,-1,-1,-1,-1,-1,-1,-1,-1,-1  // 70-7f
+        };
+        // metrowerks trips this assertion - how come?
+        #if ! defined(__MWERKS__)
+        BOOST_STATIC_ASSERT(0x80 == sizeof(lookup_table));
+        #endif
+        signed char value = -1;
+        if((unsigned)t < sizeof(lookup_table))
+            value = lookup_table[(unsigned)t];
+        if(-1 == value) { 
+            isc_throw(isc::BadValue,
+                      "attempt to decode a value not in base32hex char set");
+        }
+        return value;
+    }
+};
+
+} // namespace detail
+
+// note: what we would like to do is
+// template<class Base, class CharType = BOOST_DEDUCED_TYPENAME Base::value_type>
+//  typedef transform_iterator<
+//      from_5_bit<CharType>,
+//      transform_width<Base, 5, sizeof(Base::value_type) * 8, CharType>
+//  > base32hex_from_binary;
+// but C++ won't accept this.  Rather than using a "type generator" and
+// using a different syntax, make a derivation which should be equivalent.
+//
+// Another issue addressed here is that the transform_iterator doesn't have
+// a templated constructor.  This makes it incompatible with the dataflow
+// ideal.  This is also addressed here.
+
+template<
+    class Base, 
+    class CharType = BOOST_DEDUCED_TYPENAME boost::iterator_value<Base>::type
+>
+class binary_from_base32hex : public
+    transform_iterator<
+        detail::to_5_bit<CharType>,
+        Base
+    >
+{
+    friend class boost::iterator_core_access;
+    typedef transform_iterator<
+        detail::to_5_bit<CharType>,
+        Base
+    > super_t;
+public:
+    // make composible buy using templated constructor
+    template<class T>
+    binary_from_base32hex(BOOST_PFTO_WRAPPER(T)  start) :
+        super_t(
+            Base(BOOST_MAKE_PFTO_WRAPPER(static_cast<T>(start))), 
+            detail::to_5_bit<CharType>()
+        )
+    {}
+    // intel 7.1 doesn't like default copy constructor
+    binary_from_base32hex(const binary_from_base32hex & rhs) : 
+        super_t(
+            Base(rhs.base_reference()),
+            detail::to_5_bit<CharType>()
+        )
+    {}
+//    binary_from_base32hex(){};
+};
+
+} // namespace iterators
+} // namespace archive
+} // namespace boost
+
+#endif // BOOST_ARCHIVE_ITERATORS_BINARY_FROM_BASE32HEX_HPP
+
+// Local Variables: 
+// mode: c++
+// End: 

+ 23 - 12
src/lib/dns/hex.h

@@ -17,11 +17,10 @@
 #ifndef __HEX_H
 #define __HEX_H 1
 
+#include <stdint.h>
 #include <string>
 #include <vector>
 
-#include <exceptions/exceptions.h>
-
 //
 // Note: this helper module isn't specific to the DNS protocol per se.
 // We should probably move this to somewhere else, possibly in some common
@@ -30,19 +29,31 @@
 
 namespace isc {
 namespace dns {
-
+/// \brief Encode binary data in the base16 ('hex') format.
 ///
-/// \brief A standard DNS (or ISC) module exception that is thrown if a hex
-/// decoder encounters an invalid input.
+/// The underlying implementation is shared with \c encodeBase64, and most of
+/// the description except the format (base16) equally applies.
+/// Another notable exception is that the base16 encoding doesn't require
+/// padding, so padding related considerations and the notion of canonical
+/// encoding don't apply.
 ///
-class BadHexString : public Exception {
-public:
-    BadHexString(const char* file, size_t line, const char* what) :
-        isc::Exception(file, line, what) {}
-};
-
+/// \param binary A vector object storing the data to be encoded. 
+/// \return A newly created string that stores base16 encoded value for
+/// binary.
 std::string encodeHex(const std::vector<uint8_t>& binary);
-void decodeHex(const std::string& hex, std::vector<uint8_t>& result);
+
+/// \brief Decode a text encoded in the base16 ('hex') format into the
+/// original %data.
+///
+/// The underlying implementation is shared with \c decodeBase64, and most
+/// of the description except the format (base16) equally applies.
+/// Another notable exception is that the base16 encoding doesn't require
+/// padding, so padding related considerations and the notion of canonical
+/// encoding don't apply.
+///
+/// \param input A text encoded in the base16 format.
+/// \param result A vector in which the decoded %data is to be stored.
+void decodeHex(const std::string& input, std::vector<uint8_t>& result);
 }
 }
 

+ 1 - 1
src/lib/dns/sha1.cc

@@ -50,7 +50,7 @@
  *      without express or implied warranty of any kind.
  *      
  */
-#include <dns/sha1.h>
+#include <dns/util/sha1.h>
 
 /* Local Function Prototyptes */
 static void SHA1Finalize(SHA1Context *, uint8_t Pad_Byte);

src/lib/dns/sha1.h → src/lib/dns/util/sha1.h


+ 12 - 2
src/lib/exceptions/exceptions.h

@@ -104,7 +104,7 @@ private:
 };
 
 ///
-/// \brief A standard DNS module exception that is thrown if a parameter give
+/// \brief A generic exception that is thrown if a parameter given
 /// to a method would refer to or modify out-of-range data.
 ///
 class OutOfRange : public Exception {
@@ -114,7 +114,17 @@ public:
 };
 
 ///
-/// \brief A standard DNS module exception that is thrown when an unexpected
+/// \brief A generic exception that is thrown if a parameter given
+/// to a method is considered invalid in that context.
+///
+class BadValue : public Exception {
+public:
+    BadValue(const char* file, size_t line, const char* what) :
+        isc::Exception(file, line, what) {}
+};
+
+///
+/// \brief A generic exception that is thrown when an unexpected
 /// error condition occurs.
 ///
 class Unexpected : public Exception {