gloox  1.1-svn
sha.cpp
1 /*
2  Copyright (c) 2006-2009 by Jakob Schroeter <js@camaya.net>
3  This file is part of the gloox library. http://camaya.net/gloox
4 
5  This software is distributed under a license. The full license
6  agreement can be found in the file LICENSE in this distribution.
7  This software may not be copied, modified, sold or distributed
8  other than expressed in the named license agreement.
9 
10  This software is distributed without any warranty.
11 */
12 
13 #include "config.h"
14 
15 #include "sha.h"
16 #include "gloox.h"
17 
18 #include <cstdio>
19 
20 namespace gloox
21 {
22 
23  const std::string SHA::sha1( const std::string& data )
24  {
25  SHA sha;
26  sha.feed( data );
27  return sha.hex();
28  }
29 
31  {
32  init();
33  }
34 
36  {
37  }
38 
39  void SHA::init()
40  {
41  Length_Low = 0;
42  Length_High = 0;
43  Message_Block_Index = 0;
44 
45  H[0] = 0x67452301;
46  H[1] = 0xEFCDAB89;
47  H[2] = 0x98BADCFE;
48  H[3] = 0x10325476;
49  H[4] = 0xC3D2E1F0;
50 
51  m_finished = false;
52  m_corrupted = false;
53  }
54 
55  void SHA::reset()
56  {
57  init();
58  }
59 
60  const std::string SHA::hex()
61  {
62  if( m_corrupted )
63  return EmptyString;
64 
65  finalize();
66 
67  char buf[41];
68  for( int i = 0; i < 20; ++i )
69  sprintf( buf + i * 2, "%02x", (unsigned char)( H[i >> 2] >> ( ( 3 - ( i & 3 ) ) << 3 ) ) );
70 
71  return std::string( buf, 40 );
72  }
73 
74  const std::string SHA::binary()
75  {
76  if( !m_finished )
77  finalize();
78 
79  unsigned char digest[20];
80  for( int i = 0; i < 20; ++i )
81  digest[i] = (unsigned char)( H[i >> 2] >> ( ( 3 - ( i & 3 ) ) << 3 ) );
82 
83  return std::string( (char*)digest, 20 );
84  }
85 
87  {
88  if( !m_finished )
89  {
90  pad();
91  m_finished = true;
92  }
93  }
94 
95  void SHA::feed( const unsigned char* data, unsigned length )
96  {
97  if( !length )
98  return;
99 
100  if( m_finished || m_corrupted )
101  {
102  m_corrupted = true;
103  return;
104  }
105 
106  while( length-- && !m_corrupted )
107  {
108  Message_Block[Message_Block_Index++] = ( *data & 0xFF );
109 
110  Length_Low += 8;
111  Length_Low &= 0xFFFFFFFF;
112  if( Length_Low == 0 )
113  {
114  Length_High++;
115  Length_High &= 0xFFFFFFFF;
116  if( Length_High == 0 )
117  {
118  m_corrupted = true;
119  }
120  }
121 
122  if( Message_Block_Index == 64 )
123  {
124  process();
125  }
126 
127  ++data;
128  }
129  }
130 
131  void SHA::feed( const std::string& data )
132  {
133  feed( (const unsigned char*)data.c_str(), (int)data.length() );
134  }
135 
136  void SHA::process()
137  {
138  const unsigned K[] = { 0x5A827999,
139  0x6ED9EBA1,
140  0x8F1BBCDC,
141  0xCA62C1D6
142  };
143  int t;
144  unsigned temp;
145  unsigned W[80];
146  unsigned A, B, C, D, E;
147 
148  for( t = 0; t < 16; t++ )
149  {
150  W[t] = ((unsigned) Message_Block[t * 4]) << 24;
151  W[t] |= ((unsigned) Message_Block[t * 4 + 1]) << 16;
152  W[t] |= ((unsigned) Message_Block[t * 4 + 2]) << 8;
153  W[t] |= ((unsigned) Message_Block[t * 4 + 3]);
154  }
155 
156  for( t = 16; t < 80; ++t )
157  {
158  W[t] = shift( 1, W[t-3] ^ W[t-8] ^ W[t-14] ^ W[t-16] );
159  }
160 
161  A = H[0];
162  B = H[1];
163  C = H[2];
164  D = H[3];
165  E = H[4];
166 
167  for( t = 0; t < 20; ++t )
168  {
169  temp = shift( 5, A ) + ( ( B & C ) | ( ( ~B ) & D ) ) + E + W[t] + K[0];
170  temp &= 0xFFFFFFFF;
171  E = D;
172  D = C;
173  C = shift( 30, B );
174  B = A;
175  A = temp;
176  }
177 
178  for( t = 20; t < 40; ++t )
179  {
180  temp = shift( 5, A ) + ( B ^ C ^ D ) + E + W[t] + K[1];
181  temp &= 0xFFFFFFFF;
182  E = D;
183  D = C;
184  C = shift( 30, B );
185  B = A;
186  A = temp;
187  }
188 
189  for( t = 40; t < 60; ++t )
190  {
191  temp = shift( 5, A ) + ( ( B & C ) | ( B & D ) | ( C & D ) ) + E + W[t] + K[2];
192  temp &= 0xFFFFFFFF;
193  E = D;
194  D = C;
195  C = shift( 30, B );
196  B = A;
197  A = temp;
198  }
199 
200  for( t = 60; t < 80; ++t )
201  {
202  temp = shift( 5, A ) + ( B ^ C ^ D ) + E + W[t] + K[3];
203  temp &= 0xFFFFFFFF;
204  E = D;
205  D = C;
206  C = shift( 30, B );
207  B = A;
208  A = temp;
209  }
210 
211  H[0] = ( H[0] + A ) & 0xFFFFFFFF;
212  H[1] = ( H[1] + B ) & 0xFFFFFFFF;
213  H[2] = ( H[2] + C ) & 0xFFFFFFFF;
214  H[3] = ( H[3] + D ) & 0xFFFFFFFF;
215  H[4] = ( H[4] + E ) & 0xFFFFFFFF;
216 
217  Message_Block_Index = 0;
218  }
219 
220  void SHA::pad()
221  {
222  Message_Block[Message_Block_Index++] = 0x80;
223 
224  if( Message_Block_Index > 56 )
225  {
226  while( Message_Block_Index < 64 )
227  {
228  Message_Block[Message_Block_Index++] = 0;
229  }
230 
231  process();
232  }
233 
234  while( Message_Block_Index < 56 )
235  {
236  Message_Block[Message_Block_Index++] = 0;
237  }
238 
239  Message_Block[56] = static_cast<unsigned char>( ( Length_High >> 24 ) & 0xFF );
240  Message_Block[57] = static_cast<unsigned char>( ( Length_High >> 16 ) & 0xFF );
241  Message_Block[58] = static_cast<unsigned char>( ( Length_High >> 8 ) & 0xFF );
242  Message_Block[59] = static_cast<unsigned char>( ( Length_High ) & 0xFF );
243  Message_Block[60] = static_cast<unsigned char>( ( Length_Low >> 24 ) & 0xFF );
244  Message_Block[61] = static_cast<unsigned char>( ( Length_Low >> 16 ) & 0xFF );
245  Message_Block[62] = static_cast<unsigned char>( ( Length_Low >> 8 ) & 0xFF );
246  Message_Block[63] = static_cast<unsigned char>( ( Length_Low ) & 0xFF );
247 
248  process();
249  }
250 
251 
252  unsigned SHA::shift( int bits, unsigned word )
253  {
254  return ( ( word << bits ) & 0xFFFFFFFF) | ( ( word & 0xFFFFFFFF ) >> ( 32-bits ) );
255  }
256 
257 }