Skip to content

Commit

Permalink
Add a built-in SHA256/SHA512 implementation.
Browse files Browse the repository at this point in the history
This also moves the HMAC-SHA512 implementation to sha2.cpp.
  • Loading branch information
sipa committed Jun 21, 2014
1 parent 540ce6a commit 977cdad
Show file tree
Hide file tree
Showing 8 changed files with 536 additions and 76 deletions.
2 changes: 2 additions & 0 deletions src/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ BITCOIN_CORE_H = \
rpcserver.h \
script.h \
serialize.h \
sha2.h \
sync.h \
threadsafety.h \
tinyformat.h \
Expand Down Expand Up @@ -152,6 +153,7 @@ libbitcoin_common_a_SOURCES = \
protocol.cpp \
rpcprotocol.cpp \
script.cpp \
sha2.cpp \
sync.cpp \
util.cpp \
version.cpp \
Expand Down
2 changes: 2 additions & 0 deletions src/Makefile.test.include
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ BITCOIN_TESTS =\
test/compress_tests.cpp \
test/DoS_tests.cpp \
test/getarg_tests.cpp \
test/hash_tests.cpp \
test/key_tests.cpp \
test/main_tests.cpp \
test/miner_tests.cpp \
Expand All @@ -44,6 +45,7 @@ BITCOIN_TESTS =\
test/script_P2SH_tests.cpp \
test/script_tests.cpp \
test/serialize_tests.cpp \
test/sha2_tests.cpp \
test/sigopcount_tests.cpp \
test/test_bitcoin.cpp \
test/transaction_tests.cpp \
Expand Down
41 changes: 0 additions & 41 deletions src/hash.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,44 +56,3 @@ unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char

return h1;
}

int HMAC_SHA512_Init(HMAC_SHA512_CTX *pctx, const void *pkey, size_t len)
{
unsigned char key[128];
if (len <= 128)
{
memcpy(key, pkey, len);
memset(key + len, 0, 128-len);
}
else
{
SHA512_CTX ctxKey;
SHA512_Init(&ctxKey);
SHA512_Update(&ctxKey, pkey, len);
SHA512_Final(key, &ctxKey);
memset(key + 64, 0, 64);
}

for (int n=0; n<128; n++)
key[n] ^= 0x5c;
SHA512_Init(&pctx->ctxOuter);
SHA512_Update(&pctx->ctxOuter, key, 128);

for (int n=0; n<128; n++)
key[n] ^= 0x5c ^ 0x36;
SHA512_Init(&pctx->ctxInner);
return SHA512_Update(&pctx->ctxInner, key, 128);
}

int HMAC_SHA512_Update(HMAC_SHA512_CTX *pctx, const void *pdata, size_t len)
{
return SHA512_Update(&pctx->ctxInner, pdata, len);
}

int HMAC_SHA512_Final(unsigned char *pmd, HMAC_SHA512_CTX *pctx)
{
unsigned char buf[64];
SHA512_Final(buf, &pctx->ctxInner);
SHA512_Update(&pctx->ctxOuter, buf, 64);
return SHA512_Final(pmd, &pctx->ctxOuter);
}
10 changes: 0 additions & 10 deletions src/hash.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,14 +126,4 @@ inline uint160 Hash160(const std::vector<unsigned char>& vch)

unsigned int MurmurHash3(unsigned int nHashSeed, const std::vector<unsigned char>& vDataToHash);

typedef struct
{
SHA512_CTX ctxInner;
SHA512_CTX ctxOuter;
} HMAC_SHA512_CTX;

int HMAC_SHA512_Init(HMAC_SHA512_CTX *pctx, const void *pkey, size_t len);
int HMAC_SHA512_Update(HMAC_SHA512_CTX *pctx, const void *pdata, size_t len);
int HMAC_SHA512_Final(unsigned char *pmd, HMAC_SHA512_CTX *pctx);

#endif
19 changes: 8 additions & 11 deletions src/key.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

#include "key.h"

#include "sha2.h"

#include <openssl/bn.h>
#include <openssl/ecdsa.h>
#include <openssl/obj_mac.h>
Expand Down Expand Up @@ -510,12 +512,10 @@ void static BIP32Hash(const unsigned char chainCode[32], unsigned int nChild, un
num[1] = (nChild >> 16) & 0xFF;
num[2] = (nChild >> 8) & 0xFF;
num[3] = (nChild >> 0) & 0xFF;
HMAC_SHA512_CTX ctx;
HMAC_SHA512_Init(&ctx, chainCode, 32);
HMAC_SHA512_Update(&ctx, &header, 1);
HMAC_SHA512_Update(&ctx, data, 32);
HMAC_SHA512_Update(&ctx, num, 4);
HMAC_SHA512_Final(output, &ctx);
CHMAC_SHA512(chainCode, 32).Write(&header, 1)
.Write(data, 32)
.Write(num, 4)
.Finalize(output);
}

bool CKey::Derive(CKey& keyChild, unsigned char ccChild[32], unsigned int nChild, const unsigned char cc[32]) const {
Expand Down Expand Up @@ -562,13 +562,10 @@ bool CExtKey::Derive(CExtKey &out, unsigned int nChild) const {
}

void CExtKey::SetMaster(const unsigned char *seed, unsigned int nSeedLen) {
static const char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
HMAC_SHA512_CTX ctx;
HMAC_SHA512_Init(&ctx, hashkey, sizeof(hashkey));
HMAC_SHA512_Update(&ctx, seed, nSeedLen);
static const unsigned char hashkey[] = {'B','i','t','c','o','i','n',' ','s','e','e','d'};
unsigned char out[64];
LockObject(out);
HMAC_SHA512_Final(out, &ctx);
CHMAC_SHA512(hashkey, sizeof(hashkey)).Write(seed, nSeedLen).Finalize(out);
key.Set(&out[0], &out[32], true);
memcpy(vchChainCode, &out[32], 32);
UnlockObject(out);
Expand Down
428 changes: 428 additions & 0 deletions src/sha2.cpp

Large diffs are not rendered by default.

54 changes: 54 additions & 0 deletions src/sha2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright (c) 2014 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#ifndef BITCOIN_SHA2_H
#define BITCOIN_SHA2_H

#include <stdint.h>
#include <stdlib.h>

/** A hasher class for SHA-256. */
class CSHA256 {
private:
uint32_t s[8];
unsigned char buf[64];
size_t bytes;

public:
CSHA256();
CSHA256& Write(const unsigned char *data, size_t len);
void Finalize(unsigned char *hash);
CSHA256& Reset();
};

/** A hasher class for SHA-512. */
class CSHA512 {
private:
uint64_t s[8];
unsigned char buf[128];
size_t bytes;

public:
CSHA512();
CSHA512& Write(const unsigned char *data, size_t len);
void Finalize(unsigned char *hash);
CSHA512& Reset();
};

/** A hasher class for HMAC-SHA-512. */
class CHMAC_SHA512 {
private:
CSHA512 outer;
CSHA512 inner;

public:
CHMAC_SHA512(const unsigned char *key, size_t keylen);
CHMAC_SHA512& Write(const unsigned char *data, size_t len) {
inner.Write(data, len);
return *this;
}
void Finalize(unsigned char *hash);
};

#endif
56 changes: 42 additions & 14 deletions src/test/hmac_tests.cpp → src/test/sha2_tests.cpp
Original file line number Diff line number Diff line change
@@ -1,15 +1,49 @@
// Copyright (c) 2013 The Bitcoin Core developers
// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "hash.h"
#include "sha2.h"
#include "util.h"

#include <vector>

#include <boost/test/unit_test.hpp>

using namespace std;
BOOST_AUTO_TEST_SUITE(sha2_tests)

void SHA256TestVector(const std::string &in, const std::string &out) {
std::vector<unsigned char> hash;
hash.resize(32);
CSHA256().Write((unsigned char*)&in[0], in.size()).Finalize(&hash[0]);
BOOST_CHECK_EQUAL(HexStr(hash), out);
}

void SHA512TestVector(const std::string &in, const std::string &out) {
std::vector<unsigned char> hash;
hash.resize(64);
CSHA512().Write((unsigned char*)&in[0], in.size()).Finalize(&hash[0]);
BOOST_CHECK_EQUAL(HexStr(hash), out);
}

BOOST_AUTO_TEST_SUITE(hmac_tests)
BOOST_AUTO_TEST_CASE(sha256_testvectors) {
SHA256TestVector("", "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855");
SHA256TestVector("abc", "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
SHA256TestVector("message digest", "f7846f55cf23e14eebeab5b4e1550cad5b509e3348fbc4efa3a1413d393cb650");
SHA256TestVector("secure hash algorithm", "f30ceb2bb2829e79e4ca9753d35a8ecc00262d164cc077080295381cbd643f0d");
SHA256TestVector("SHA256 is considered to be safe", "6819d915c73f4d1e77e4e1b52d1fa0f9cf9beaead3939f15874bd988e2a23630");
SHA256TestVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
SHA256TestVector("For this sample, this 63-byte string will be used as input data", "f08a78cbbaee082b052ae0708f32fa1e50c5c421aa772ba5dbb406a2ea6be342");
SHA256TestVector("This is exactly 64 bytes long, not counting the terminating byte", "ab64eff7e88e2e46165e29f2bce41826bd4c7b3552f6b382a9e7d3af47c245f8");
SHA256TestVector("As Bitcoin relies on 80 byte header hashes, we want to have an example for that.", "7406e8de7d6e4fffc573daef05aefb8806e7790f55eab5576f31349743cca743");
}

BOOST_AUTO_TEST_CASE(sha512_testvectors) {
SHA512TestVector("abc", "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f");
SHA512TestVector("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "204a8fc6dda82f0a0ced7beb8e08a41657c16ef468b228a8279be331a703c33596fd15c13b1b07f9aa1d3bea57789ca031ad85c7a71dd70354ec631238ca3445");
SHA512TestVector("abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909");
SHA512TestVector(std::string(1000000, 'a'), "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973ebde0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
SHA512TestVector("", "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e");
}

typedef struct {
const char *pszKey;
Expand Down Expand Up @@ -111,18 +145,12 @@ BOOST_AUTO_TEST_CASE(hmacsha512_testvectors)
{
for (unsigned int n=0; n<sizeof(vtest)/sizeof(vtest[0]); n++)
{
vector<unsigned char> vchKey = ParseHex(vtest[n].pszKey);
vector<unsigned char> vchData = ParseHex(vtest[n].pszData);
vector<unsigned char> vchMAC = ParseHex(vtest[n].pszMAC);
std::vector<unsigned char> vchKey = ParseHex(vtest[n].pszKey);
std::vector<unsigned char> vchData = ParseHex(vtest[n].pszData);
std::vector<unsigned char> vchMAC = ParseHex(vtest[n].pszMAC);
unsigned char vchTemp[64];

HMAC_SHA512_CTX ctx;
HMAC_SHA512_Init(&ctx, &vchKey[0], vchKey.size());
HMAC_SHA512_Update(&ctx, &vchData[0], vchData.size());
HMAC_SHA512_Final(&vchTemp[0], &ctx);

CHMAC_SHA512(&vchKey[0], vchKey.size()).Write(&vchData[0], vchData.size()).Finalize(&vchTemp[0]);
BOOST_CHECK(memcmp(&vchTemp[0], &vchMAC[0], 64) == 0);

}
}

Expand Down

0 comments on commit 977cdad

Please sign in to comment.