aboutsummaryrefslogtreecommitdiff
path: root/src/sha1.cpp
diff options
context:
space:
mode:
authorMike Buland <eichlan@xagasoft.com>2009-02-19 23:44:57 +0000
committerMike Buland <eichlan@xagasoft.com>2009-02-19 23:44:57 +0000
commit4309066dff46f52690998bbd1f60ec8b1631f142 (patch)
tree07b6092622c909351f20590e7ee96d07f5b2d010 /src/sha1.cpp
parent3f958097632256329cdbaf2219e2ba15325e9c52 (diff)
downloadlibbu++-4309066dff46f52690998bbd1f60ec8b1631f142.tar.gz
libbu++-4309066dff46f52690998bbd1f60ec8b1631f142.tar.bz2
libbu++-4309066dff46f52690998bbd1f60ec8b1631f142.tar.xz
libbu++-4309066dff46f52690998bbd1f60ec8b1631f142.zip
We have the new Bu::CryptoHash base class and Bu::Md5 is here and ready
to rock. sha1 is still only a shell, I dunno if/when I'm going to implement that one. So far Bu::Md5 is 100% compatible with md5sum in all tests performed so far, in fact the test program's output is compatible with md5sum in every way (and it's so cute and little too!) Oh, minor update for stdstream and the formatter, they can handle more handy types now.
Diffstat (limited to 'src/sha1.cpp')
-rw-r--r--src/sha1.cpp161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/sha1.cpp b/src/sha1.cpp
new file mode 100644
index 0000000..8270c3b
--- /dev/null
+++ b/src/sha1.cpp
@@ -0,0 +1,161 @@
1#include <stdio.h>
2#include <string.h>
3#include <stdlib.h>
4
5#include "sha1.h"
6
7Sha1::Sha1() :
8 H0( 0x67452301 ),
9 H1( 0xefcdab89 ),
10 H2( 0x98badcfe ),
11 H3( 0x10325476 ),
12 H4( 0xc3d2e1f0 ),
13 unprocessedBytes( 0 ),
14 size( 0 )
15{
16}
17
18Sha1::~Sha1()
19{
20}
21
22void Sha1::process()
23{
24 int t;
25 uint32_t a, b, c, d, e, K, f, W[80];
26
27 // starting values
28 a = H0;
29 b = H1;
30 c = H2;
31 d = H3;
32 e = H4;
33
34 // copy and expand the message block
35 for( t = 0; t < 16; t++ ) W[t] = (bytes[t*4] << 24)
36 +(bytes[t*4 + 1] << 16)
37 +(bytes[t*4 + 2] << 8)
38 + bytes[t*4 + 3];
39 for(; t< 80; t++ ) W[t] = lrot( W[t-3]^W[t-8]^W[t-14]^W[t-16], 1 );
40
41 /* main loop */
42 uint32_t temp;
43 for( t = 0; t < 80; t++ )
44 {
45 if( t < 20 ) {
46 K = 0x5a827999;
47 f = (b & c) | ((~b) & d);
48 } else if( t < 40 ) {
49 K = 0x6ed9eba1;
50 f = b ^ c ^ d;
51 } else if( t < 60 ) {
52 K = 0x8f1bbcdc;
53 f = (b & c) | (b & d) | (c & d);
54 } else {
55 K = 0xca62c1d6;
56 f = b ^ c ^ d;
57 }
58 temp = lrot(a,5) + f + e + W[t] + K;
59 e = d;
60 d = c;
61 c = lrot(b,30);
62 b = a;
63 a = temp;
64 //printf( "t=%d %08x %08x %08x %08x %08x\n",t,a,b,c,d,e );
65 }
66
67 /* add variables */
68 H0 += a;
69 H1 += b;
70 H2 += c;
71 H3 += d;
72 H4 += e;
73
74 //printf( "Current: %08x %08x %08x %08x %08x\n",H0,H1,H2,H3,H4 );
75 /* all bytes have been processed */
76 unprocessedBytes = 0;
77}
78
79void Sha1::update( const char* data, int num )
80{
81 // add these bytes to the running total
82 size += num;
83
84 // repeat until all data is processed
85 while( num > 0 )
86 {
87 // number of bytes required to complete block
88 int needed = 64 - unprocessedBytes;
89
90 // number of bytes to copy (use smaller of two)
91 int toCopy = (num < needed) ? num : needed;
92
93 // Copy the bytes
94 memcpy( bytes + unprocessedBytes, data, toCopy );
95
96 // Bytes have been copied
97 num -= toCopy;
98 data += toCopy;
99 unprocessedBytes += toCopy;
100
101 // there is a full block
102 if( unprocessedBytes == 64 ) process();
103 }
104}
105
106unsigned char* Sha1::getDigest()
107{
108 // save the message size
109 uint32_t totalBitsL = size << 3;
110 uint32_t totalBitsH = size >> 29;
111
112 // add 0x80 to the message
113 update( "\x80", 1 );
114
115 unsigned char footer[64] = {
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
117 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
119 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
120
121 // block has no room for 8-byte filesize, so finish it
122 if( unprocessedBytes > 56 )
123 update( (char*)footer, 64 - unprocessedBytes);
124
125 // how many zeros do we need
126 int neededZeros = 56 - unprocessedBytes;
127
128 // store file size (in bits) in big-endian format
129 toBigEndian( totalBitsH, footer + neededZeros );
130 toBigEndian( totalBitsL, footer + neededZeros + 4 );
131
132 // finish the final block
133 update( (char*)footer, neededZeros + 8 );
134
135 // allocate memory for the digest bytes
136 unsigned char* digest = new unsigned char[20];
137
138 // copy the digest bytes
139 toBigEndian( H0, digest );
140 toBigEndian( H1, digest + 4 );
141 toBigEndian( H2, digest + 8 );
142 toBigEndian( H3, digest + 12 );
143 toBigEndian( H4, digest + 16 );
144
145 // return the digest
146 return digest;
147}
148
149uint32_t Sha1::lrot( uint32_t x, int bits )
150{
151 return (x<<bits) | (x>>(32 - bits));
152};
153
154void Sha1::toBigEndian( uint32_t num, unsigned char* byte )
155{
156 byte[0] = (unsigned char)(num>>24);
157 byte[1] = (unsigned char)(num>>16);
158 byte[2] = (unsigned char)(num>>8);
159 byte[3] = (unsigned char)num;
160}
161