aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/sha1.cpp161
-rw-r--r--src/sha1.h42
-rw-r--r--src/tests/sha1.cpp44
3 files changed, 247 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
diff --git a/src/sha1.h b/src/sha1.h
new file mode 100644
index 0000000..ab6081d
--- /dev/null
+++ b/src/sha1.h
@@ -0,0 +1,42 @@
1/* sha1.h
2
3Copyright (c) 2005 Michael D. Leonhard
4
5http://tamale.net/
6
7This file is licensed under the terms described in the
8accompanying LICENSE file.
9*/
10
11#ifndef SHA1_H
12#define SHA1_H
13
14#include <stdint.h>
15
16/**
17 * Calculates SHA-1 sums. This is based strongly on code from Michael D.
18 * Leonhard who released his code under the terms of the MIT license, thank you!
19 */
20class Sha1
21{
22public:
23 Sha1();
24 ~Sha1();
25
26 void update( const char* data, int num );
27 unsigned char* getDigest();
28
29 // utility methods
30 static uint32_t lrot( uint32_t x, int bits );
31 static void toBigEndian( uint32_t in, unsigned char* out );
32
33private:
34 // fields
35 uint32_t H0, H1, H2, H3, H4;
36 unsigned char bytes[64];
37 int unprocessedBytes;
38 uint32_t size;
39 void process();
40};
41
42#endif
diff --git a/src/tests/sha1.cpp b/src/tests/sha1.cpp
new file mode 100644
index 0000000..51c5104
--- /dev/null
+++ b/src/tests/sha1.cpp
@@ -0,0 +1,44 @@
1#include "sha1.h"
2#include "file.h"
3
4#define BS 1024
5
6int main( int argc, char *argv[] )
7{
8 argc--; argv++;
9
10 if( argc == 0 )
11 {
12 printf("Provide a filename.\n");
13 return 0;
14 }
15
16 char buf[BS];
17
18 Sha1 s;
19 File fin( *argv, "rb" );
20 for(;;)
21 {
22 int nRead = fin.read( buf, BS );
23 if( nRead == 0 )
24 break;
25
26 s.update( buf, nRead );
27 if( nRead < BS )
28 break;
29 }
30
31 unsigned char *dig = s.getDigest();
32
33 char val[]={"0123456789ABCDEF"};
34
35 for( int j = 0; j < 20; j++ )
36 {
37 putchar( val[dig[j]>>4] );
38 putchar( val[dig[j]&0x0F] );
39 }
40 putchar('\n');
41
42 delete[] dig;
43}
44