From 8530b58eddbed272803c731d6d208ff2a04a1e25 Mon Sep 17 00:00:00 2001 From: Jeffrey Walton Date: Tue, 28 Nov 2017 04:22:19 -0500 Subject: [PATCH] Add Base32 extended hex encoder and decoder (GH #534) I'm not sure if this is what the fellow in the issue wanted, but we are missing it. Also see https://stackoverflow.com/q/47325517/608639 --- base32.cpp | 50 ++++++++++++++++++++++++++++++++--- base32.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 118 insertions(+), 8 deletions(-) diff --git a/base32.cpp b/base32.cpp index c3d32526..2f0c4c7f 100644 --- a/base32.cpp +++ b/base32.cpp @@ -1,4 +1,5 @@ // base32.cpp - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai +// extended hex alphabet added by JW in November, 2017. #include "pch.h" #include "base32.h" @@ -6,8 +7,11 @@ NAMESPACE_BEGIN(CryptoPP) ANONYMOUS_NAMESPACE_BEGIN -const byte s_vecUpper[] = "ABCDEFGHIJKMNPQRSTUVWXYZ23456789"; -const byte s_vecLower[] = "abcdefghijkmnpqrstuvwxyz23456789"; +const byte s_stdUpper[] = "ABCDEFGHIJKMNPQRSTUVWXYZ23456789"; +const byte s_stdLower[] = "abcdefghijkmnpqrstuvwxyz23456789"; +const byte s_hexUpper[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV"; +const byte s_hexLower[] = "0123456789abcdefghijklmnopqrstuv"; + const int s_array[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, @@ -27,6 +31,25 @@ const int s_array[256] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 }; +const int s_hexArray[256] = { + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 26, 27, 28, 29, 30, 31, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1 +}; + ANONYMOUS_NAMESPACE_END void Base32Encoder::IsolatedInitialize(const NameValuePairs ¶meters) @@ -34,7 +57,7 @@ void Base32Encoder::IsolatedInitialize(const NameValuePairs ¶meters) bool uppercase = parameters.GetValueWithDefault(Name::Uppercase(), true); m_filter->Initialize(CombinedNameValuePairs( parameters, - MakeParameters(Name::EncodingLookupArray(), uppercase ? &s_vecUpper[0] : &s_vecLower[0], false)(Name::Log2Base(), 5, true))); + MakeParameters(Name::EncodingLookupArray(), uppercase ? &s_stdUpper[0] : &s_stdLower[0], false)(Name::Log2Base(), 5, true))); } void Base32Decoder::IsolatedInitialize(const NameValuePairs ¶meters) @@ -50,4 +73,25 @@ const int *Base32Decoder::GetDefaultDecodingLookupArray() return s_array; } +void Base32HexEncoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + bool uppercase = parameters.GetValueWithDefault(Name::Uppercase(), true); + m_filter->Initialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::EncodingLookupArray(), uppercase ? &s_hexUpper[0] : &s_hexLower[0], false)(Name::Log2Base(), 5, true))); +} + +void Base32HexDecoder::IsolatedInitialize(const NameValuePairs ¶meters) +{ + BaseN_Decoder::IsolatedInitialize(CombinedNameValuePairs( + parameters, + MakeParameters(Name::DecodingLookupArray(), GetDefaultDecodingLookupArray(), false)(Name::Log2Base(), 5, true))); +} + +// Unrolled initialization, http://github.com/weidai11/cryptopp/issues/376 +const int *Base32HexDecoder::GetDefaultDecodingLookupArray() +{ + return s_hexArray; +} + NAMESPACE_END diff --git a/base32.h b/base32.h index b0f3094c..61ce3e85 100644 --- a/base32.h +++ b/base32.h @@ -1,7 +1,8 @@ // base32.h - written and placed in the public domain by Frank Palazzolo, based on hex.cpp by Wei Dai +// extended hex alphabet added by JW in November, 2017. -//! \file -//! \brief Classes for Base32Encoder and Base32Decoder +//! \file base32.h +//! \brief Classes for Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder #ifndef CRYPTOPP_BASE32_H #define CRYPTOPP_BASE32_H @@ -14,6 +15,7 @@ NAMESPACE_BEGIN(CryptoPP) //! \class Base32Encoder //! \brief Base32 encodes data //! \details Converts data to base32. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +//! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder class Base32Encoder : public SimpleProxyFilter { public: @@ -25,7 +27,7 @@ public: //! \param terminator the terminator appeand after processing //! \details Base32Encoder() constructs a default encoder. The constructor lacks fields for padding and //! line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. - //! \sa IsolatedInitialize() for an example of modifying a Base32Encoder after construction. + //! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder Base32Encoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) { @@ -51,13 +53,14 @@ public: //! encoder.IsolatedInitialize(params); //! \details If you change the encoding alphabet, then you will need to change the decoding alphabet \a and //! the decoder's lookup table. - //! \sa Base32Decoder::IsolatedInitialize() for an example of changing a Base32Decoder's lookup table. + //! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder void IsolatedInitialize(const NameValuePairs ¶meters); }; //! \class Base32Decoder //! \brief Base32 decodes data //! \details Decode base32 data. The default code is based on Differential Unicode Domain Encoding (DUDE) (draft-ietf-idn-dude-02.txt). +//! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder class Base32Decoder : public BaseN_Decoder { public: @@ -82,7 +85,70 @@ public: //! Base32Decoder decoder; //! AlgorithmParameters params = MakeParameters(Name::DecodingLookupArray(),(const int *)lookup); //! decoder.IsolatedInitialize(params); - //! \sa Base32Encoder::IsolatedInitialize() for an example of changing a Base32Encoder's alphabet. + //! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + void IsolatedInitialize(const NameValuePairs ¶meters); + +private: + //! \brief Provides the default decoding lookup table + //! \return default decoding lookup table + static const int * CRYPTOPP_API GetDefaultDecodingLookupArray(); +}; + +//! \class Base32HexEncoder +//! \brief Base32 encodes data using extended hex +//! \details Converts data to base32 using extended hex alphabet. The alphabet is different than Base32Encoder. +//! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +//! \since Crypto++ 6.0 +class Base32HexEncoder : public SimpleProxyFilter +{ +public: + //! \brief Construct a Base32HexEncoder + //! \param attachment a BufferedTrasformation to attach to this object + //! \param uppercase a flag indicating uppercase output + //! \param groupSize the size of the grouping + //! \param separator the separator to use between groups + //! \param terminator the terminator appeand after processing + //! \details Base32HexEncoder() constructs a default encoder. The constructor lacks fields for padding and + //! line breaks. You must use IsolatedInitialize() to change the default padding character or suppress it. + //! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexEncoder(BufferedTransformation *attachment = NULLPTR, bool uppercase = true, int groupSize = 0, const std::string &separator = ":", const std::string &terminator = "") + : SimpleProxyFilter(new BaseN_Encoder(new Grouper), attachment) + { + IsolatedInitialize(MakeParameters(Name::Uppercase(), uppercase)(Name::GroupSize(), groupSize)(Name::Separator(), ConstByteArrayParameter(separator))(Name::Terminator(), ConstByteArrayParameter(terminator))); + } + + //! \brief Initialize or reinitialize this object, without signal propagation + //! \param parameters a set of NameValuePairs used to initialize this object + //! \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + //! number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + //! transformations. If initialization should be propagated, then use the Initialize() function. + //! \details The following code modifies the padding and line break parameters for an encoder: + //!
+	//!     Base32HexEncoder encoder;
+	//!     AlgorithmParameters params = MakeParameters(Pad(), false)(InsertLineBreaks(), false);
+	//!     encoder.IsolatedInitialize(params);
+ void IsolatedInitialize(const NameValuePairs ¶meters); +}; + +//! \class Base32HexDecoder +//! \brief Base32 extended hex decodes data +//! \brief Base32 decodes data using extended hex alphabet. The alphabet is different than Base32Decoder. +//! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder, RFC 4648, Base 32 Encoding with Extended Hex Alphabet. +//! \since Crypto++ 6.0 +class Base32HexDecoder : public BaseN_Decoder +{ +public: + //! \brief Construct a Base32HexDecoder + //! \param attachment a BufferedTrasformation to attach to this object + //! \sa Base32Encoder, Base32Decoder, Base32HexEncoder and Base32HexDecoder + Base32HexDecoder(BufferedTransformation *attachment = NULLPTR) + : BaseN_Decoder(GetDefaultDecodingLookupArray(), 5, attachment) {} + + //! \brief Initialize or reinitialize this object, without signal propagation + //! \param parameters a set of NameValuePairs used to initialize this object + //! \details IsolatedInitialize() is used to initialize or reinitialize an object using a variable + //! number of arbitrarily typed arguments. IsolatedInitialize() does not call Initialize() on attached + //! transformations. If initialization should be propagated, then use the Initialize() function. void IsolatedInitialize(const NameValuePairs ¶meters); private: