- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

gmd5_native.cpp
Go to the documentation of this file.
1 //
2 // Copyright (C) 2001-2013 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 // gmd5_native.cpp
19 //
20
21 #include "gdef.h"
22 #include "gmd5.h"
23 #include "gstr.h"
24 #include "gstrings.h"
25 #include "gassert.h"
26 #include "md5.h"
27 #include <sstream>
28
29 namespace
30 {
31 typedef md5::big_t big_t ;
32 typedef md5::digest_stream md5_state_t ;
33 typedef md5::digest::state_type state_type ;
34 typedef md5::format format ;
35
36 void init( md5_state_t & )
37 {
38 }
39 void update( md5_state_t & context , const std::string & input )
40 {
41 context.add( input ) ;
42 }
43 std::string final( md5_state_t & context )
44 {
45 context.close() ;
46 return format::raw( context.state().d ) ;
47 }
48 std::string writeOut( const md5_state_t & context )
49 {
50 G_ASSERT( context.state().s.length() == 0U ) ;
51 G_ASSERT( context.state().n == 64U ) ; // ie. magic number below
52 std::ostringstream ss ;
53 ss <<
54 context.state().d.a << "." <<
55 context.state().d.b << "." <<
56 context.state().d.c << "." <<
57 context.state().d.d ;
58 return ss.str() ;
59 }
60 big_t toUnsigned( const std::string & s , bool limited = true )
61 {
62 // big_t can be bigger than unsigned long but long long might not
63 // be supported by the compiler, so do it oldschool
64 if( s.empty() ) throw G::Md5::Error( s ) ;
65 big_t result = 0U ;
66 for( std::string::const_iterator p = s.begin() ; p != s.end() ; ++p )
67 {
68 result *= 10U ;
69 unsigned int n =
70 ( *p == '0' ) ? 0U : (
71 ( *p == '1' ) ? 1U : (
72 ( *p == '2' ) ? 2U : (
73 ( *p == '3' ) ? 3U : (
74 ( *p == '4' ) ? 4U : (
75 ( *p == '5' ) ? 5U : (
76 ( *p == '6' ) ? 6U : (
77 ( *p == '7' ) ? 7U : (
78 ( *p == '8' ) ? 8U : (
79 ( *p == '9' ) ? 9U : 10U ))))))))) ;
80 if( n == 10U ) throw G::Md5::Error( s ) ;
81 if( limited && (result+n) < result ) throw G::Md5::Error( s ) ;
82 result += n ;
83 }
84 return result ;
85 }
86 void readIn( md5_state_t & context , G::Strings & s )
87 {
88 big_t a = toUnsigned( s.front() ) ; s.pop_front() ;
89 big_t b = toUnsigned( s.front() ) ; s.pop_front() ;
90 big_t c = toUnsigned( s.front() ) ; s.pop_front() ;
91 big_t d = toUnsigned( s.front() ) ; s.pop_front() ;
92 state_type state = { a , b , c , d } ;
93 md5::small_t magic_number = 64U ;
94 context = md5_state_t( state , magic_number ) ;
95 }
96 }
97
98 std::string G::Md5::xor_( const std::string & s1 , const std::string & s2 )
99 {
100 G_ASSERT( s1.length() == s2.length() ) ;
101 std::string::const_iterator p1 = s1.begin() ;
102 std::string::const_iterator p2 = s2.begin() ;
103 std::string result ;
104 for( ; p1 != s1.end() ; ++p1 , ++p2 )
105 {
106 unsigned char c1 = static_cast<unsigned char>(*p1) ;
107 unsigned char c2 = static_cast<unsigned char>(*p2) ;
108 unsigned char c = static_cast<unsigned char>( c1 ^ c2 ) ;
109 result.append( 1U , static_cast<char>(c) ) ;
110 }
111 return result ;
112 }
113
114 std::string G::Md5::key64( std::string k )
115 {
116 const size_t B = 64U ;
117 if( k.length() > B )
118 k = digest(k) ;
119 if( k.length() < B )
120 k.append( std::string(B-k.length(),'\0') ) ;
121 G_ASSERT( k.length() == B ) ;
122 return k ;
123 }
124
125 std::string G::Md5::ipad()
126 {
127 const size_t B = 64U ;
128 return std::string( B , '\066' ) ; // 00110110 = 00,110,110
129 }
130
131 std::string G::Md5::opad()
132 {
133 const size_t B = 64U ;
134 return std::string( B , '\134' ) ; // 01011100 = 01,011,100
135 }
136
137 std::string G::Md5::mask( const std::string & k )
138 {
139 std::string k64 = key64( k ) ;
140 return mask( k64 , ipad() ) + "." + mask( k64 , opad() ) ;
141 }
142
143 std::string G::Md5::mask( const std::string & k64 , const std::string & pad )
144 {
145 md5_state_t context ;
146 init( context ) ;
147 update( context , xor_(k64,pad) ) ;
148 return writeOut( context ) ;
149 }
150
151 std::string G::Md5::hmac( const std::string & masked_key , const std::string & input , Masked )
152 {
153 G::Strings part_list ;
154 G::Str::splitIntoTokens( masked_key , part_list , "." ) ;
155 if( part_list.size() != 8U )
156 throw InvalidMaskedKey( masked_key ) ;
157
158 md5_state_t inner_context ;
159 md5_state_t outer_context ;
160 readIn( inner_context , part_list ) ;
161 readIn( outer_context , part_list ) ;
162 update( inner_context , input ) ;
163 update( outer_context , final(inner_context) ) ;
164 return final( outer_context ) ;
165 }
166
167 std::string G::Md5::hmac( const std::string & k , const std::string & input )
168 {
169 std::string k64 = key64( k ) ;
170 return digest( xor_(k64,opad()) , digest(xor_(k64,ipad()),input) ) ;
171 }
172
173 std::string G::Md5::digest( const std::string & input )
174 {
175 return digest( input , NULL ) ;
176 }
177
178 std::string G::Md5::digest( const std::string & input_1 , const std::string & input_2 )
179 {
180 return digest( input_1 , &input_2 ) ;
181 }
182
183 std::string G::Md5::digest( const std::string & input_1 , const std::string * input_2 )
184 {
185 md5_state_t context ;
186 init( context ) ;
187 update( context , input_1 ) ;
188 if( input_2 != NULL )
189 update( context , *input_2 ) ;
190 return final( context ) ;
191 }
192
193 std::string G::Md5::printable( const std::string & input )
194 {
195 G_ASSERT( input.length() == 16U ) ;
196
197 std::string result ;
198 const char * hex = "0123456789abcdef" ;
199 const size_t n = input.length() ;
200 for( size_t i = 0U ; i < n ; i++ )
201 {
202 unsigned char c = static_cast<unsigned char>(input.at(i)) ;
203 result.append( 1U , hex[(c>>4U)&0x0F] ) ;
204 result.append( 1U , hex[(c>>0U)&0x0F] ) ;
205 }
206
207 return result ;
208 }
209
md5::digest_stream
A class that calculates an md5 digest from a data stream using the algorithm described by RFC 1321...
Definition: md5.h:238
G::Md5::Masked
An overload discriminator for G::Md5::hmac()
Definition: gmd5.h:43
md5::big_t
size_type big_t
To hold at least 32 bits, maybe more. Try unsigned long on small systems.
Definition: md5.h:44
gstrings.h
md5::small_t
size_type small_t
To hold at least a size_t. Must fit in a big_t.
Definition: md5.h:45
gmd5.h
G::Strings
std::list< std::string > Strings
A std::list of std::strings.
Definition: gstrings.h:39
G::Str::splitIntoTokens
static void splitIntoTokens(const std::string &in, Strings &out, const std::string &ws)
Splits the string into 'ws'-delimited tokens.
Definition: gstr.cpp:714
G::Md5::hmac
static std::string hmac(const std::string &key, const std::string &input)
Computes a Hashed Message Authentication Code using MD5 as the hash function.
Definition: gmd5_native.cpp:167
G_ASSERT
#define G_ASSERT(test)
Definition: gassert.h:30
gstr.h
gassert.h
md5::digest::state_type
Holds the md5 algorithm state. Used by md5::digest.
Definition: md5.h:80
md5::format
A static string-formatting class for the output of md5::digest.
Definition: md5.h:141
G::Md5::mask
static std::string mask(const std::string &key)
Masks an HMAC key so that it can be stored more safely.
Definition: gmd5_native.cpp:137
G::Md5::digest
static std::string digest(const std::string &input)
Creates an MD5 digest.
Definition: gmd5_native.cpp:173
md5.h
G::Md5::printable
static std::string printable(const std::string &input)
Converts a binary string into a printable form, using a lowercase hexadecimal encoding.
Definition: gmd5_native.cpp:193