The primary purpose of this report is to clarify errors, identify vulnerabilities, determine the benefits versus the drawbacks of a particular coin and to help eliminate the threat of scam artists, liars and thieves.
The first thing I looked at is the crypto. Encryption is a good thing for privacy and security. Converting, or hashing, output strings, makes it a lot more difficult for outsiders to view or use the information. Higher levels of encryption add to the difficulty in manipulating the information.
Bitcoin uses the SHA256 library for crypto. A 256 bit encryption algorithm is a decent strength encryption. In this case however, it does not use a true 256 bit. It actually uses layers of 16 bit, 32 bit and 64 bit. The 16 bit layer actually hashes out to 20 bits. The total output for all layers is in the neighborhood of 256 bits, but total output (sum), is not the same as a true 256 bit output. It is dramatically easier to crack a single layer of 20, 32 and 64 bits compared to a single 256 bit string.
The use of open source crypto is good for debugging, teaching purposes, identifying common errors and etcetra. But being the double-edged sword, it also allows nefarious programmers to get the information they need to crack it. In the case of SHA256, the hasher works as it should. The conversion process adequately converts the output. But, the chunker, that divides up the output into chunks for converting, only actually chunks out to 30 and 60 bits. Leaving 2 and 4 bits respectively, to hang in limbo. These bits are potentially passed through the network unencrypted.
Some would argue that it's only the last 4 bits, and won't matter. Well, it's only the lottery, and you were given the last 4 numbers of the winning number for free. You only have to come up with a few more numbers to hit it big. Assuming that the last 2 and 4 bits left over from the chunker are included in the previous bit for conversion, then the last chunk becomes 3 and 5 bits, instead of the 1 bit at a time to be converted. It's possible that the last chunk is discarded for irregularities, thus remaining unencrypted. Or, it does get converted, but does not improve the encryption or reduce the chances of a successful crack. This is easily fixed by recoding the chunker to actually chunk out to the full 32 and 64 bits, as indicated in the output from source. There could also be minor adjustments for efficiency and less resource consumption, but these are not any kind of mandatory changes nor are required for this crypto to work properly.
Here is the source for the bitcoin header. As you can see, it clearly uses 16, 32 and 64 bit outputs.
// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or
http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CRYPTO_COMMON_H
#define BITCOIN_CRYPTO_COMMON_H
#if defined(HAVE_CONFIG_H)
#include "bitcoin-config.h"
#endif
#include
#include "compat/endian.h"
uint16_t static inline ReadLE16(const unsigned char* ptr)
{
return le16toh(*((uint16_t*)ptr));
}
uint32_t static inline ReadLE32(const unsigned char* ptr)
{
return le32toh(*((uint32_t*)ptr));
}
uint64_t static inline ReadLE64(const unsigned char* ptr)
{
return le64toh(*((uint64_t*)ptr));
}
void static inline WriteLE16(unsigned char* ptr, uint16_t x)
{
*((uint16_t*)ptr) = htole16(x);
}
void static inline WriteLE32(unsigned char* ptr, uint32_t x)
{
*((uint32_t*)ptr) = htole32(x);
}
void static inline WriteLE64(unsigned char* ptr, uint64_t x)
{
*((uint64_t*)ptr) = htole64(x);
}
uint32_t static inline ReadBE32(const unsigned char* ptr)
{
return be32toh(*((uint32_t*)ptr));
}
uint64_t static inline ReadBE64(const unsigned char* ptr)
{
return be64toh(*((uint64_t*)ptr));
}
void static inline WriteBE32(unsigned char* ptr, uint32_t x)
{
*((uint32_t*)ptr) = htobe32(x);
}
void static inline WriteBE64(unsigned char* ptr, uint64_t x)
{
*((uint64_t*)ptr) = htobe64(x);
}
#endif // BITCOIN_CRYPTO_COMMON_H
Another example, taken from source, is the output of one of the layers as 20 bits. Elsewhere in source it starts as a 16 bit layer, but actually outputs to 20. This is ok.
// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CRYPTO_SHA1_H
#define BITCOIN_CRYPTO_SHA1_H
#include
#include
/** A hasher class for SHA1. */
class CSHA1
{
private:
uint32_t s[5];
unsigned char buf[64];
size_t bytes;
public:
static const size_t OUTPUT_SIZE = 20;
CSHA1();
CSHA1& Write(const unsigned char* data, size_t len);
void Finalize(unsigned char hash[OUTPUT_SIZE]);
CSHA1& Reset();
};
#endif // BITCOIN_CRYPTO_SHA1_H
Here is the 32 bit output:
// Copyright (c) 2014 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
#ifndef BITCOIN_CRYPTO_SHA256_H
#define BITCOIN_CRYPTO_SHA256_H
#include
#include
/** A hasher class for SHA-256. */
class CSHA256
{
private:
uint32_t s[8];
unsigned char buf[64];
size_t bytes;
public:
static const size_t OUTPUT_SIZE = 32;
CSHA256();
CSHA256& Write(const unsigned char* data, size_t len);
void Finalize(unsigned char hash[OUTPUT_SIZE]);
CSHA256& Reset();
};
#endif // BITCOIN_CRYPTO_SHA256_H
The algorithm used works. The library used that the crypto is based on, works as it should. The names were made to be a bit misleading, but more than likely, that is to try and deter would-be crackers from trying to crack the encryption and get in. Because this deals with money, I would recommend that the crypto is written out to be a full 256 bit layer, or even use the 512 bit. The reality is, anything less than 256 bit can be cracked by a child with a brute forcer, and time.
All of this can be found on Github. Look here for the crypto source and see for yourself: https://github.com/bitcoin/bitcoin/tree/master/src/crypto