Skip to content

Commit a142dfa

Browse files
committed
version 6
1 parent f04b05b commit a142dfa

File tree

16 files changed

+566
-134
lines changed

16 files changed

+566
-134
lines changed

crc32.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// //////////////////////////////////////////////////////////
22
// crc32.cpp
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

@@ -379,7 +379,7 @@ void CRC32::add(const void* data, size_t numBytes)
379379
}
380380

381381

382-
/// return latest hash as 16 hex characters
382+
/// return latest hash as 8 hex characters
383383
std::string CRC32::getHash()
384384
{
385385
// convert hash to string
@@ -395,7 +395,6 @@ std::string CRC32::getHash()
395395
hashBuffer[5] = dec2hex[(m_hash >> 8) & 15];
396396
hashBuffer[6] = dec2hex[(m_hash >> 4) & 15];
397397
hashBuffer[7] = dec2hex[ m_hash & 15];
398-
399398
// zero-terminated string
400399
hashBuffer[8] = 0;
401400

@@ -404,6 +403,16 @@ std::string CRC32::getHash()
404403
}
405404

406405

406+
/// return latest hash as bytes
407+
void CRC32::getHash(unsigned char buffer[CRC32::HashBytes])
408+
{
409+
buffer[0] = (m_hash >> 24) & 0xFF;
410+
buffer[1] = (m_hash >> 16) & 0xFF;
411+
buffer[2] = (m_hash >> 8) & 0xFF;
412+
buffer[3] = m_hash & 0xFF;
413+
}
414+
415+
407416
/// compute CRC32 of a memory block
408417
std::string CRC32::operator()(const void* data, size_t numBytes)
409418
{

crc32.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// //////////////////////////////////////////////////////////
22
// crc32.h
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

@@ -32,10 +32,18 @@ typedef unsigned __int32 uint32_t;
3232
while (more data available)
3333
crc32.add(pointer to fresh data, number of new bytes);
3434
std::string myHash3 = crc32.getHash();
35+
36+
Note:
37+
You can find code for the faster Slicing-by-16 algorithm on my website, too:
38+
http://create.stephan-brumme.com/crc32/
39+
Its unrolled version is about twice as fast but its look-up table doubled in size as well.
3540
*/
3641
class CRC32 //: public Hash
3742
{
3843
public:
44+
/// hash is 4 bytes long
45+
enum { HashBytes = 4 };
46+
3947
/// same as reset()
4048
CRC32();
4149

@@ -47,8 +55,10 @@ class CRC32 //: public Hash
4755
/// add arbitrary number of bytes
4856
void add(const void* data, size_t numBytes);
4957

50-
/// return latest hash as 16 hex characters
58+
/// return latest hash as 8 hex characters
5159
std::string getHash();
60+
/// return latest hash as bytes
61+
void getHash(unsigned char buffer[HashBytes]);
5262

5363
/// restart
5464
void reset();

digest.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
// //////////////////////////////////////////////////////////
22
// digest.cpp
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

7+
// g++ -O3 digest.cpp crc32.cpp md5.cpp sha1.cpp sha256.cpp keccak.cpp sha3.cpp -o digest
8+
79
#include "crc32.h"
810
#include "md5.h"
911
#include "sha1.h"
@@ -14,12 +16,13 @@
1416
#include <iostream>
1517
#include <fstream>
1618

19+
1720
int main(int argc, char** argv)
1821
{
1922
// syntax check
2023
if (argc < 2 || argc > 3)
2124
{
22-
std::cout << "./digest filename [--md5|--sha1|--sha256|--crc|--keccak|--sha3]" << std::endl;
25+
std::cout << "./digest filename [--crc|--md5|--sha1|--sha256|--keccak|--sha3]" << std::endl;
2326
return 1;
2427
}
2528

hash.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// //////////////////////////////////////////////////////////
22
// hash.h
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

@@ -20,7 +20,7 @@ class Hash
2020
/// add arbitrary number of bytes
2121
virtual void add(const void* data, size_t numBytes) = 0;
2222

23-
/// return latest hash as 16 hex characters
23+
/// return latest hash as hex characters
2424
virtual std::string getHash() = 0;
2525

2626
/// restart

hmac.h

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// //////////////////////////////////////////////////////////
2+
// hmac.h
3+
// Copyright (c) 2015 Stephan Brumme. All rights reserved.
4+
// see http://create.stephan-brumme.com/disclaimer.html
5+
//
6+
7+
#pragma once
8+
9+
// based on http://tools.ietf.org/html/rfc2104
10+
// see also http://en.wikipedia.org/wiki/Hash-based_message_authentication_code
11+
12+
/** Usage:
13+
std::string msg = "The quick brown fox jumps over the lazy dog";
14+
std::string key = "key";
15+
std::string md5hmac = hmac< MD5 >(msg, key);
16+
std::string sha1hmac = hmac< SHA1 >(msg, key);
17+
std::string sha2hmac = hmac<SHA256>(msg, key);
18+
19+
Note:
20+
To keep my code simple, HMAC computation currently needs the whole message at once.
21+
This is in contrast to the hashes MD5, SHA1, etc. where an add() method is available
22+
for incremental computation.
23+
You can use any hash for HMAC as long as it provides:
24+
- constant HashMethod::BlockSize (typically 64)
25+
- constant HashMethod::HashBytes (length of hash in bytes, e.g. 20 for SHA1)
26+
- HashMethod::add(buffer, bufferSize)
27+
- HashMethod::getHash(unsigned char buffer[HashMethod::BlockSize])
28+
*/
29+
30+
#include <string>
31+
#include <cstring> // memcpy
32+
33+
/// compute HMAC hash of data and key using MD5, SHA1 or SHA256
34+
template <typename HashMethod>
35+
std::string hmac(const void* data, size_t numDataBytes, const void* key, size_t numKeyBytes)
36+
{
37+
// initialize key with zeros
38+
unsigned char usedKey[HashMethod::BlockSize] = {0};
39+
40+
// adjust length of key: must contain exactly blockSize bytes
41+
if (numKeyBytes <= HashMethod::BlockSize)
42+
{
43+
// copy key
44+
memcpy(usedKey, key, numKeyBytes);
45+
}
46+
else
47+
{
48+
// shorten key: usedKey = hashed(key)
49+
HashMethod keyHasher;
50+
keyHasher.add(key, numKeyBytes);
51+
keyHasher.getHash(usedKey);
52+
}
53+
54+
// create initial XOR padding
55+
for (size_t i = 0; i < HashMethod::BlockSize; i++)
56+
usedKey[i] ^= 0x36;
57+
58+
// inside = hash((usedKey ^ 0x36) + data)
59+
unsigned char inside[HashMethod::HashBytes];
60+
HashMethod insideHasher;
61+
insideHasher.add(usedKey, HashMethod::BlockSize);
62+
insideHasher.add(data, numDataBytes);
63+
insideHasher.getHash(inside);
64+
65+
// undo usedKey's previous 0x36 XORing and apply a XOR by 0x5C
66+
for (size_t i = 0; i < HashMethod::BlockSize; i++)
67+
usedKey[i] ^= 0x5C ^ 0x36;
68+
69+
// hash((usedKey ^ 0x5C) + hash((usedKey ^ 0x36) + data))
70+
HashMethod finalHasher;
71+
finalHasher.add(usedKey, HashMethod::BlockSize);
72+
finalHasher.add(inside, HashMethod::HashBytes);
73+
74+
return finalHasher.getHash();
75+
}
76+
77+
78+
/// convenience function for std::string
79+
template <typename HashMethod>
80+
std::string hmac(const std::string& data, const std::string& key)
81+
{
82+
return hmac<HashMethod>(data.c_str(), data.size(), key.c_str(), key.size());
83+
}

keccak.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// //////////////////////////////////////////////////////////
22
// keccak.cpp
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

@@ -222,11 +222,11 @@ void Keccak::processBuffer()
222222
// add a "1" byte
223223
m_buffer[offset++] = 1;
224224
// fill with zeros
225-
while (offset < blockSize - 1)
225+
while (offset < blockSize)
226226
m_buffer[offset++] = 0;
227227

228228
// and add a single set bit
229-
m_buffer[blockSize - 1] = 0x80;
229+
m_buffer[blockSize - 1] |= 0x80;
230230

231231
processBlock(m_buffer);
232232
}

keccak.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// //////////////////////////////////////////////////////////
22
// keccak.h
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

md5.cpp

Lines changed: 36 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// //////////////////////////////////////////////////////////
22
// md5.cpp
3-
// Copyright (c) 2014 Stephan Brumme. All rights reserved.
3+
// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
44
// see http://create.stephan-brumme.com/disclaimer.html
55
//
66

@@ -316,72 +316,49 @@ void MD5::processBuffer()
316316
}
317317

318318

319-
/// return latest hash as 16 hex characters
319+
/// return latest hash as 32 hex characters
320320
std::string MD5::getHash()
321321
{
322-
// convert hash to string
323-
static const char dec2hex[16+1] = "0123456789abcdef";
322+
// compute hash (as raw bytes)
323+
unsigned char rawHash[HashBytes];
324+
getHash(rawHash);
325+
326+
// convert to hex string
327+
std::string result;
328+
result.reserve(2 * HashBytes);
329+
for (int i = 0; i < HashBytes; i++)
330+
{
331+
static const char dec2hex[16+1] = "0123456789abcdef";
332+
result += dec2hex[(rawHash[i] >> 4) & 15];
333+
result += dec2hex[ rawHash[i] & 15];
334+
}
335+
336+
return result;
337+
}
338+
324339

340+
/// return latest hash as bytes
341+
void MD5::getHash(unsigned char buffer[MD5::HashBytes])
342+
{
325343
// save old hash if buffer is partially filled
326-
uint32_t oldHash[4];
327-
oldHash[0] = m_hash[0];
328-
oldHash[1] = m_hash[1];
329-
oldHash[2] = m_hash[2];
330-
oldHash[3] = m_hash[3];
344+
uint32_t oldHash[HashValues];
345+
for (int i = 0; i < HashValues; i++)
346+
oldHash[i] = m_hash[i];
331347

332348
// process remaining bytes
333349
processBuffer();
334350

335-
// create hash string
336-
char hashBuffer[4*8+1];
337-
338-
hashBuffer[ 0] = dec2hex[(m_hash[0] >> 4) & 15];
339-
hashBuffer[ 1] = dec2hex[ m_hash[0] & 15];
340-
hashBuffer[ 2] = dec2hex[(m_hash[0] >> 12) & 15];
341-
hashBuffer[ 3] = dec2hex[(m_hash[0] >> 8) & 15];
342-
hashBuffer[ 4] = dec2hex[(m_hash[0] >> 20) & 15];
343-
hashBuffer[ 5] = dec2hex[(m_hash[0] >> 16) & 15];
344-
hashBuffer[ 6] = dec2hex[ m_hash[0] >> 28 ];
345-
hashBuffer[ 7] = dec2hex[(m_hash[0] >> 24) & 15];
346-
347-
hashBuffer[ 8] = dec2hex[(m_hash[1] >> 4) & 15];
348-
hashBuffer[ 9] = dec2hex[ m_hash[1] & 15];
349-
hashBuffer[10] = dec2hex[(m_hash[1] >> 12) & 15];
350-
hashBuffer[11] = dec2hex[(m_hash[1] >> 8) & 15];
351-
hashBuffer[12] = dec2hex[(m_hash[1] >> 20) & 15];
352-
hashBuffer[13] = dec2hex[(m_hash[1] >> 16) & 15];
353-
hashBuffer[14] = dec2hex[ m_hash[1] >> 28 ];
354-
hashBuffer[15] = dec2hex[(m_hash[1] >> 24) & 15];
355-
356-
hashBuffer[16] = dec2hex[(m_hash[2] >> 4) & 15];
357-
hashBuffer[17] = dec2hex[ m_hash[2] & 15];
358-
hashBuffer[18] = dec2hex[(m_hash[2] >> 12) & 15];
359-
hashBuffer[19] = dec2hex[(m_hash[2] >> 8) & 15];
360-
hashBuffer[20] = dec2hex[(m_hash[2] >> 20) & 15];
361-
hashBuffer[21] = dec2hex[(m_hash[2] >> 16) & 15];
362-
hashBuffer[22] = dec2hex[ m_hash[2] >> 28 ];
363-
hashBuffer[23] = dec2hex[(m_hash[2] >> 24) & 15];
364-
365-
hashBuffer[24] = dec2hex[(m_hash[3] >> 4) & 15];
366-
hashBuffer[25] = dec2hex[ m_hash[3] & 15];
367-
hashBuffer[26] = dec2hex[(m_hash[3] >> 12) & 15];
368-
hashBuffer[27] = dec2hex[(m_hash[3] >> 8) & 15];
369-
hashBuffer[28] = dec2hex[(m_hash[3] >> 20) & 15];
370-
hashBuffer[29] = dec2hex[(m_hash[3] >> 16) & 15];
371-
hashBuffer[30] = dec2hex[ m_hash[3] >> 28 ];
372-
hashBuffer[31] = dec2hex[(m_hash[3] >> 24) & 15];
373-
374-
// zero-terminated string
375-
hashBuffer[32] = 0;
376-
377-
// restore old hash
378-
m_hash[0] = oldHash[0];
379-
m_hash[1] = oldHash[1];
380-
m_hash[2] = oldHash[2];
381-
m_hash[3] = oldHash[3];
382-
383-
// convert to std::string
384-
return hashBuffer;
351+
unsigned char* current = buffer;
352+
for (int i = 0; i < HashValues; i++)
353+
{
354+
*current++ = m_hash[i] & 0xFF;
355+
*current++ = (m_hash[i] >> 8) & 0xFF;
356+
*current++ = (m_hash[i] >> 16) & 0xFF;
357+
*current++ = (m_hash[i] >> 24) & 0xFF;
358+
359+
// restore old hash
360+
m_hash[i] = oldHash[i];
361+
}
385362
}
386363

387364

md5.h

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ typedef unsigned __int64 uint64_t;
3737
class MD5 //: public Hash
3838
{
3939
public:
40+
/// split into 64 byte blocks (=> 512 bits), hash is 16 bytes long
41+
enum { BlockSize = 512 / 8, HashBytes = 16 };
42+
4043
/// same as reset()
4144
MD5();
4245

@@ -48,8 +51,10 @@ class MD5 //: public Hash
4851
/// add arbitrary number of bytes
4952
void add(const void* data, size_t numBytes);
5053

51-
/// return latest hash as 16 hex characters
54+
/// return latest hash as 32 hex characters
5255
std::string getHash();
56+
/// return latest hash as bytes
57+
void getHash(unsigned char buffer[HashBytes]);
5358

5459
/// restart
5560
void reset();
@@ -60,15 +65,14 @@ class MD5 //: public Hash
6065
/// process everything left in the internal buffer
6166
void processBuffer();
6267

63-
/// split into 64 byte blocks (=> 512 bits)
64-
enum { BlockSize = 512 / 8 };
65-
6668
/// size of processed data in bytes
6769
uint64_t m_numBytes;
6870
/// valid bytes in m_buffer
6971
size_t m_bufferSize;
7072
/// bytes not processed yet
7173
uint8_t m_buffer[BlockSize];
74+
75+
enum { HashValues = HashBytes / 4 };
7276
/// hash, stored as integers
73-
uint32_t m_hash[4];
77+
uint32_t m_hash[HashValues];
7478
};

0 commit comments

Comments
 (0)