E-MailRelay
ghash.h
Go to the documentation of this file.
1//
2// Copyright (C) 2001-2024 Graeme Walker <graeme_walker@users.sourceforge.net>
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program. If not, see <http://www.gnu.org/licenses/>.
16// ===
17///
18/// \file ghash.h
19///
20
21#ifndef G_HASH_H
22#define G_HASH_H
23
24#include "gdef.h"
25#include "gexception.h"
26#include <string>
27
28namespace G
29{
30 class Hash ;
31}
32
33//| \class G::Hash
34/// A class for creating HMACs using an arbitrary cryptographic hash function
35/// as per RFC-2104.
36///
38{
39public:
40 struct Masked /// An overload discriminator for G::Hash::hmac()
41 {} ;
42
43 template <typename Fn2> static std::string hmac( Fn2 digest , std::size_t blocksize , const std::string & key ,
44 const std::string & input ) ;
45 ///< Computes a Hashed Message Authentication Code using the given hash
46 ///< function. This is typically for challenge-response authentication
47 ///< where the plaintext input is an arbitrary challenge string from the
48 ///< server that the client needs to hmac() using their shared private key.
49 ///<
50 ///< See also RFC-2104 [HMAC-MD5].
51 ///<
52 ///< For hash function H with block size B (64) using shared key SK:
53 ///<
54 ///< \code
55 ///< K = large(SK) ? H(SK) : SK
56 ///< ipad = 0x36 repeated B times
57 ///< opad = 0x5C repeated B times
58 ///< HMAC = H( K XOR opad , H( K XOR ipad , plaintext ) )
59 ///< \endcode
60 ///<
61 ///< The H() function processes a stream of blocks; the first parameter above
62 ///< represents the first block, and the second parameter is the rest of the
63 ///< stream (zero-padded up to a block boundary).
64 ///<
65 ///< The shared key can be up to B bytes, or if more than B bytes then K is
66 ///< the L-byte result of hashing the shared-key. K is zero-padded up to
67 ///< B bytes for XOR-ing.
68
69 template <typename Fn2> static std::string hmac( Fn2 postdigest , const std::string & masked_key ,
70 const std::string & input , Masked ) ;
71 ///< An hmac() overload using a masked key. The postdigest function should
72 ///< behave like G::Md5::postdigest() and it must throw an exception if the
73 ///< masked key is invalid.
74
75 template <typename Fn1, typename Fn2> static std::string mask( Fn1 predigest , Fn2 digest ,
76 std::size_t blocksize , const std::string & shared_key ) ;
77 ///< Computes a masked key from the given shared key, returning a non-printable
78 ///< string. This can be passed to the 'masked' overload of hmac() once the
79 ///< message is known.
80 ///<
81 ///< The predigest and digest functions must behave like G::Md5::predigest()
82 ///< and G::Md5::digest2().
83 ///<
84 ///< A masked key (MK) is the result of doing the initial, plaintext-independent
85 ///< parts of HMAC computation, taking the intermediate state of both the
86 ///< inner and outer hash functions.
87 ///<
88 ///< \code
89 ///< K = large(SK) ? H(SK) : SK
90 ///< HKipad = H( K XOR ipad , )
91 ///< HKopad = H( K XOR opad , )
92 ///< MK := ( HKipad , HKopad )
93 ///< \endcode
94
95 static std::string printable( const std::string & input ) ;
96 ///< Converts a binary string into a printable form, using a
97 ///< lowercase hexadecimal encoding.
98
99public:
100 Hash() = delete ;
101
102private:
103 template <typename Fn2> static std::string keyx( Fn2 , std::size_t blocksize , std::string k ) ;
104 static std::string xor_( const std::string & s1 , const std::string & s2 ) ;
105 static std::string ipad( std::size_t blocksize ) ;
106 static std::string opad( std::size_t blocksize ) ;
107} ;
108
109template <typename Fn2>
110std::string G::Hash::keyx( Fn2 fn , std::size_t blocksize , std::string k )
111{
112 if( k.length() > blocksize )
113 k = fn( k , std::string() ) ;
114 if( k.length() < blocksize )
115 k.append( blocksize-k.length() , '\0' ) ;
116 return k ;
117}
118
119template <typename Fn2>
120std::string G::Hash::hmac( Fn2 fn , std::size_t blocksize , const std::string & k , const std::string & input )
121{
122 const std::string kx = keyx( fn , blocksize , k ) ;
123 return fn( xor_(kx,opad(blocksize)) , fn(xor_(kx,ipad(blocksize)),input) ) ;
124}
125
126template <typename Fn, typename Fn2>
127std::string G::Hash::mask( Fn predigest_fn , Fn2 digest_fn , std::size_t blocksize , const std::string & k )
128{
129 std::string kx = keyx( digest_fn , blocksize , k ) ;
130 std::string ki_state = predigest_fn( xor_(kx,ipad(blocksize)) ) ;
131 std::string ko_state = predigest_fn( xor_(kx,opad(blocksize)) ) ;
132 return ki_state + ko_state ;
133}
134
135template <typename Fn2>
136std::string G::Hash::hmac( Fn2 postdigest_fn , const std::string & masked_key , const std::string & input , Masked )
137{
138 return postdigest_fn( masked_key , input ) ;
139}
140
141#endif
A class for creating HMACs using an arbitrary cryptographic hash function as per RFC-2104.
Definition: ghash.h:38
static std::string hmac(Fn2 digest, std::size_t blocksize, const std::string &key, const std::string &input)
Computes a Hashed Message Authentication Code using the given hash function.
Definition: ghash.h:120
static std::string mask(Fn1 predigest, Fn2 digest, std::size_t blocksize, const std::string &shared_key)
Computes a masked key from the given shared key, returning a non-printable string.
static std::string printable(const std::string &input)
Converts a binary string into a printable form, using a lowercase hexadecimal encoding.
Definition: ghash.cpp:53
Low-level classes.
Definition: garg.h:36
An overload discriminator for G::Hash::hmac()
Definition: ghash.h:41