Fix big endianess support in InternalMessageDigest and PBKDF2

- Replace sha1/md5 implementation by ones from https://github.com/nmaier/crypto
- Add endianess functionality fro https://github.com/nmaier/crypto

Closes GH-239
pull/239/merge
Nils Maier 2014-06-10 13:09:08 +02:00
parent 60032bf0ab
commit 8587669995
11 changed files with 1402 additions and 611 deletions

View File

@ -35,81 +35,71 @@
#include "MessageDigestImpl.h"
#include "md5.h"
#include "sha1.h"
#include "crypto_hash.h"
namespace aria2 {
namespace {
using namespace aria2;
using namespace crypto;
template<size_t dlen,
typename ctx_t,
int (*init_fn)(ctx_t**),
void (*update_fn)(ctx_t*, const void*, size_t),
void (*final_fn)(ctx_t*, uint8_t*),
void (*free_fn)(ctx_t**)>
class MessageDigestBase : public MessageDigestImpl {
template<hash::Algorithms algo>
class MessageDigestBase : public MessageDigestImpl
{
public:
MessageDigestBase() : ctx_(nullptr) { reset(); }
virtual ~MessageDigestBase()
MessageDigestBase() : ctx_{hash::create(algo)} {}
virtual ~MessageDigestBase() {}
static size_t length()
{
free_fn(&ctx_);
auto ctx = hash::create(algo);
return ctx->length();
}
static size_t length()
{
return dlen;
}
virtual size_t getDigestLength() const CXX11_OVERRIDE
{
return dlen;
return ctx_->length();
}
virtual void reset() CXX11_OVERRIDE
{
free_fn(&ctx_);
init_fn(&ctx_);
ctx_->reset();
}
virtual void update(const void* data, size_t length) CXX11_OVERRIDE
virtual void update(const void *data, size_t length) CXX11_OVERRIDE
{
auto bytes = reinterpret_cast<const char*>(data);
while (length) {
size_t l = std::min(length, (size_t)std::numeric_limits<uint32_t>::max());
update_fn(ctx_, bytes, l);
length -= l;
bytes += l;
}
ctx_->update(data, length);
}
virtual void digest(unsigned char* md) CXX11_OVERRIDE
virtual void digest(unsigned char *md) CXX11_OVERRIDE
{
final_fn(ctx_, md);
auto rv = ctx_->finalize();
memcpy(md, rv.data(), rv.length());
}
private:
ctx_t* ctx_;
std::unique_ptr<hash::Algorithm> ctx_;
};
typedef MessageDigestBase<MD5_LENGTH,
struct MD5_CTX,
MD5_Init,
MD5_Update,
MD5_Final,
MD5_Free>
MessageDigestMD5;
typedef MessageDigestBase<SHA1_LENGTH,
SHA1_CTX,
SHA1_Init,
SHA1_Update,
SHA1_Final,
SHA1_Free>
MessageDigestSHA1;
typedef MessageDigestBase<hash::algoMD5> MessageDigestMD5;
typedef MessageDigestBase<hash::algoSHA1> MessageDigestSHA1;
typedef MessageDigestBase<hash::algoSHA224> MessageDigestSHA224;
typedef MessageDigestBase<hash::algoSHA256> MessageDigestSHA256;
typedef MessageDigestBase<hash::algoSHA384> MessageDigestSHA384;
typedef MessageDigestBase<hash::algoSHA512> MessageDigestSHA512;
} // namespace
std::unique_ptr<MessageDigestImpl> MessageDigestImpl::sha1()
{
namespace aria2 {
std::unique_ptr<MessageDigestImpl> MessageDigestImpl::sha1() {
return make_unique<MessageDigestSHA1>();
}
MessageDigestImpl::hashes_t MessageDigestImpl::hashes = {
{ "sha-1", make_hi<MessageDigestSHA1>() },
{ "sha-224", make_hi<MessageDigestSHA224>() },
{ "sha-256", make_hi<MessageDigestSHA256>() },
{ "sha-384", make_hi<MessageDigestSHA384>() },
{ "sha-512", make_hi<MessageDigestSHA512>() },
{ "md5", make_hi<MessageDigestMD5>() },
};

View File

@ -58,6 +58,7 @@ SRCS = \
CookieStorage.cc CookieStorage.h\
cookie_helper.cc cookie_helper.h\
CreateRequestCommand.cc CreateRequestCommand.h\
crypto_endian.h\
CUIDCounter.cc CUIDCounter.h\
DefaultAuthResolver.cc DefaultAuthResolver.h\
DefaultBtProgressInfoFile.cc DefaultBtProgressInfoFile.h\
@ -370,8 +371,7 @@ endif
if USE_INTERNAL_MD
SRCS += \
InternalMessageDigestImpl.cc\
md5.c md5.h\
sha1.c sha1.h
crypto_hash.cc crypto_hash.h
endif # USE_WINDOWS_MD
if HAVE_LIBGNUTLS

116
src/crypto_endian.h Normal file
View File

@ -0,0 +1,116 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Written in 2014 by Nils Maier
#ifndef CRYPTO_ENDIAN_H
#define CRYPTO_ENDIAN_H
#include <cstdint>
#include "config.h"
namespace crypto {
#if defined(__GNUG__)
#define forceinline __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define forceinline __forceinline
#else // ! _MSC_VER
#define forceinline inline
#endif // ! _MSC_VER
/* In order for this implementation to work your system (or you yourself) must
* define after including <sys/param.h>
* - LITTLE_ENDIAN
* - BIG_ENDIAN
* - BYTE_ORDER
* - where BYTE_ORDER == LITTLE_ENDIAN or BYTE_ORDER == BIG_ENDIAN
* Failing to conform will render this implementation utterly incorrect.
*/
#if defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
// Itanium is dead!
#define LITTLE_ENDIAN 1234
#define BIG_ENDIAN 4321
#define BYTE_ORDER LITTLE_ENDIAN
#else // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
#ifdef HAVE_SYS_PARAM_H
#include <sys/param.h>
#endif // HAVE_SYS_PARAM_H
#endif // ! defined(_WIN32) || defined(__INTEL_COMPILER) || defined (_MSC_VER)
#if !defined(LITTLE_ENDIAN) || !defined(BIG_ENDIAN) || !defined(BYTE_ORDER) || (LITTLE_ENDIAN != BYTE_ORDER && BIG_ENDIAN != BYTE_ORDER)
#error Unsupported byte order/endianess
#endif
// Lets spend some quality time mucking around with byte swap and endian-ness.
// First bswap32:
#if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUG__)
#define __crypto_bswap32(p) \
({ \
uint32_t t = p; \
__asm__ __volatile__("bswap %0" : "=r"(t) : "0"(t)); \
t; \
})
#elif defined(__GNUG__)
#define __crypto_bswap32 __builtin_bswap32
#else // defined(__GNUG__)
forceinline uint32_t __crypto_bswap32(uint32_t n)
{
n = ((n << 8) & 0xff00ff00) | ((n >> 8) & 0xff00ff);
return (n << 16) | (n >> 16);
}
#endif // defined(__GNUG__)
// Next up: bswap64
#if defined(__x86_64__) && defined(__GNUG__)
#define __crypto_bswap64(p) \
({ \
uint64_t t = p; \
__asm__ __volatile__("bswapq %q0" : "=r"(t) : "0"(t)); \
t; \
})
#elif defined(__GNUG__)
#define __crypto_bswap64 __builtin_bswap64
#else // defined(__GNUG__)
forceinline uint64_t __crypto_bswap64(uint64_t n)
{
n = ((n << 8) & 0xff00ff00ff00ff00) | ((n >> 8) & 0x00ff00ff00ff00ff);
n = ((n << 16) & 0xffff0000ffff0000) | ((n >> 16) & 0x0000ffff0000ffff);
return (n << 32) | (n >> 32);
}
#endif // defined(__GNUG__)
// Time for an implementation that makes reuse easier.
namespace {
template<typename T>
inline T __crypto_bswap(T n)
{
static_assert(sizeof(T) != sizeof(T), "Not implemented");
}
template<>
inline uint32_t __crypto_bswap(uint32_t n)
{
return __crypto_bswap32(n);
}
template<>
inline uint64_t __crypto_bswap(uint64_t n)
{
return __crypto_bswap64(n);
}
} // namespace
// __crypto_le and __crypto_be depending on byte order
#if LITTLE_ENDIAN == BYTE_ORDER
#define __crypto_be(n) __crypto_bswap(n)
#define __crypto_le(n) (n)
#else // LITTLE_ENDIAN == WORD_ORDER
#define __crypto_be(n) (n)
#define __crypto_le(n) __crypto_bswap(n)
#endif
} // namespace crypto
#endif // CRYPTO_ENDIAN_H

1140
src/crypto_hash.cc Normal file

File diff suppressed because it is too large Load Diff

103
src/crypto_hash.h Normal file
View File

@ -0,0 +1,103 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
// Written in 2014 by Nils Maier
#ifndef CRYPTO_HASH_H
#define CRYPTO_HASH_H
#include <cstdint>
#include <cstring>
#include <memory>
#include <set>
#include <string>
#include <limits>
namespace crypto {
namespace hash {
enum Algorithms {
algoNone = 0x0,
algoMD5 = 0x1,
algoSHA1 = 0x2,
algoSHA224 = 0x3,
algoSHA256 = 0x4,
algoSHA384 = 0x5,
algoSHA512 = 0x6,
};
class Algorithm
{
public:
Algorithm() {}
virtual ~Algorithm() {}
virtual void update(const void* data, uint64_t len) = 0;
inline void update(const std::string& data)
{
return update(data.data(), data.length());
}
virtual std::string finalize() = 0;
virtual void reset() = 0;
virtual uint_fast16_t length() const = 0;
virtual uint_fast16_t blocksize() const = 0;
private:
Algorithm(const Algorithm&) = delete;
Algorithm& operator=(const Algorithm&) = delete;
};
const std::set<std::string>& all();
Algorithms lookup(const std::string& name);
std::unique_ptr<Algorithm> create(Algorithms algo);
inline std::unique_ptr<Algorithm> create(const std::string& name)
{
return create(lookup(name));
}
inline uint_fast16_t length(Algorithms algo)
{
return create(algo)->length();
}
inline uint_fast16_t length(const std::string& name)
{
return create(name)->length();
}
inline std::string compute(Algorithms algo, const void* data, uint_fast64_t len)
{
auto ctx = create(algo);
ctx->update(data, len);
return ctx->finalize();
}
inline std::string compute(Algorithms algo, const std::string& data)
{
return compute(algo, data.data(), data.length());
}
inline std::string
compute(const std::string& name, const void* data, uint_fast64_t len)
{
return compute(lookup(name), data, len);
}
inline std::string compute(const std::string& name, const std::string& data)
{
return compute(lookup(name), data.data(), data.length());
}
} // namespace hash
} // namespace crypto
#endif // CRYPTO_HASH_H

311
src/md5.c
View File

@ -1,311 +0,0 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* (This is a heavily cut-down "BSD license".)
*
* This differs from Colin Plumb's older public domain implementation in that
* no exactly 32-bit integer data type is required (any 32-bit or wider
* unsigned integer data type will do), there's no compile-time endianness
* configuration, and the function prototypes match OpenSSL's. No code from
* Colin Plumb's implementation has been reused; this comment merely compares
* the properties of the two independent implementations.
*
* The primary goals of this implementation are portability and ease of use.
* It is meant to be fast, but not as fast as possible. Some known
* optimizations are not included to reduce source code size and avoid
* compile-time configuration.
*/
#include "md5.h"
#include <stdlib.h>
#include <string.h>
struct MD5_CTX {
size_t lo, hi;
size_t a, b, c, d;
uint8_t buffer[64];
size_t block[16];
};
/*
* The basic MD5 functions.
*
* F and G are optimized compared to their RFC 1321 definitions for
* architectures that lack an AND-NOT instruction, just like in Colin Plumb's
* implementation.
*/
#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z))))
#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y))))
#define H(x, y, z) ((x) ^ (y) ^ (z))
#define I(x, y, z) ((y) ^ ((x) | ~(z)))
/*
* The MD5 transformation for all four rounds.
*/
#define STEP(f, a, b, c, d, x, t, s) \
(a) += f((b), (c), (d)) + (x) + (t); \
(a) = (((a) << (s)) | (((a) & 0xffffffff) >> (32 - (s)))); \
(a) += (b);
/*
* SET reads 4 input bytes in little-endian byte order and stores them
* in a properly aligned word in host byte order.
*
* The check for little-endian architectures that tolerate unaligned
* memory accesses is just an optimization. Nothing will break if it
* doesn't work.
*/
#if defined(__i386__) || defined(__x86_64__) || defined(__vax__)
#define SET(n) \
(*(size_t *)&ptr[(n) * 4])
#define GET(n) \
SET(n)
#else
#define SET(n) \
(ctx->block[(n)] = \
(size_t)ptr[(n) * 4] | \
((size_t)ptr[(n) * 4 + 1] << 8) | \
((size_t)ptr[(n) * 4 + 2] << 16) | \
((size_t)ptr[(n) * 4 + 3] << 24))
#define GET(n) \
(ctx->block[(n)])
#endif
/*
* This processes one or more 64-byte data blocks, but does NOT update
* the bit counters. There are no alignment requirements.
*/
static const void *body(struct MD5_CTX *ctx, const void *data, size_t size)
{
const uint8_t *ptr;
size_t a, b, c, d;
size_t saved_a, saved_b, saved_c, saved_d;
ptr = data;
a = ctx->a;
b = ctx->b;
c = ctx->c;
d = ctx->d;
do {
saved_a = a;
saved_b = b;
saved_c = c;
saved_d = d;
/* Round 1 */
STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7)
STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12)
STEP(F, c, d, a, b, SET(2), 0x242070db, 17)
STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22)
STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7)
STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12)
STEP(F, c, d, a, b, SET(6), 0xa8304613, 17)
STEP(F, b, c, d, a, SET(7), 0xfd469501, 22)
STEP(F, a, b, c, d, SET(8), 0x698098d8, 7)
STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12)
STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17)
STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22)
STEP(F, a, b, c, d, SET(12), 0x6b901122, 7)
STEP(F, d, a, b, c, SET(13), 0xfd987193, 12)
STEP(F, c, d, a, b, SET(14), 0xa679438e, 17)
STEP(F, b, c, d, a, SET(15), 0x49b40821, 22)
/* Round 2 */
STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5)
STEP(G, d, a, b, c, GET(6), 0xc040b340, 9)
STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14)
STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20)
STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5)
STEP(G, d, a, b, c, GET(10), 0x02441453, 9)
STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14)
STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20)
STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5)
STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9)
STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14)
STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20)
STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5)
STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9)
STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14)
STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20)
/* Round 3 */
STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4)
STEP(H, d, a, b, c, GET(8), 0x8771f681, 11)
STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16)
STEP(H, b, c, d, a, GET(14), 0xfde5380c, 23)
STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4)
STEP(H, d, a, b, c, GET(4), 0x4bdecfa9, 11)
STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16)
STEP(H, b, c, d, a, GET(10), 0xbebfbc70, 23)
STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4)
STEP(H, d, a, b, c, GET(0), 0xeaa127fa, 11)
STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16)
STEP(H, b, c, d, a, GET(6), 0x04881d05, 23)
STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4)
STEP(H, d, a, b, c, GET(12), 0xe6db99e5, 11)
STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16)
STEP(H, b, c, d, a, GET(2), 0xc4ac5665, 23)
/* Round 4 */
STEP(I, a, b, c, d, GET(0), 0xf4292244, 6)
STEP(I, d, a, b, c, GET(7), 0x432aff97, 10)
STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15)
STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21)
STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6)
STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10)
STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15)
STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21)
STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6)
STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10)
STEP(I, c, d, a, b, GET(6), 0xa3014314, 15)
STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21)
STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6)
STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10)
STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15)
STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21)
a += saved_a;
b += saved_b;
c += saved_c;
d += saved_d;
ptr += 64;
} while (size -= 64);
ctx->a = a;
ctx->b = b;
ctx->c = c;
ctx->d = d;
return ptr;
}
int MD5_Init(struct MD5_CTX **ctx)
{
*ctx = malloc(sizeof(struct MD5_CTX));
if (!*ctx) {
return 0;
}
(*ctx)->a = 0x67452301;
(*ctx)->b = 0xefcdab89;
(*ctx)->c = 0x98badcfe;
(*ctx)->d = 0x10325476;
(*ctx)->lo = 0;
(*ctx)->hi = 0;
return 1;
}
void MD5_Update(struct MD5_CTX *ctx, const void *data, size_t size)
{
size_t saved_lo;
size_t used, free;
saved_lo = ctx->lo;
if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo)
ctx->hi++;
ctx->hi += size >> 29;
used = saved_lo & 0x3f;
if (used) {
free = 64 - used;
if (size < free) {
memcpy(&ctx->buffer[used], data, size);
return;
}
memcpy(&ctx->buffer[used], data, free);
data = (unsigned char *)data + free;
size -= free;
body(ctx, ctx->buffer, 64);
}
if (size >= 64) {
data = body(ctx, data, size & ~(size_t)0x3f);
size &= 0x3f;
}
memcpy(ctx->buffer, data, size);
}
void MD5_Final(struct MD5_CTX *ctx, unsigned char* result)
{
size_t used, free;
used = ctx->lo & 0x3f;
ctx->buffer[used++] = 0x80;
free = 64 - used;
if (free < 8) {
memset(&ctx->buffer[used], 0, free);
body(ctx, ctx->buffer, 64);
used = 0;
free = 64;
}
memset(&ctx->buffer[used], 0, free - 8);
ctx->lo <<= 3;
ctx->buffer[56] = ctx->lo;
ctx->buffer[57] = ctx->lo >> 8;
ctx->buffer[58] = ctx->lo >> 16;
ctx->buffer[59] = ctx->lo >> 24;
ctx->buffer[60] = ctx->hi;
ctx->buffer[61] = ctx->hi >> 8;
ctx->buffer[62] = ctx->hi >> 16;
ctx->buffer[63] = ctx->hi >> 24;
body(ctx, ctx->buffer, 64);
result[0] = ctx->a;
result[1] = ctx->a >> 8;
result[2] = ctx->a >> 16;
result[3] = ctx->a >> 24;
result[4] = ctx->b;
result[5] = ctx->b >> 8;
result[6] = ctx->b >> 16;
result[7] = ctx->b >> 24;
result[8] = ctx->c;
result[9] = ctx->c >> 8;
result[10] = ctx->c >> 16;
result[11] = ctx->c >> 24;
result[12] = ctx->d;
result[13] = ctx->d >> 8;
result[14] = ctx->d >> 16;
result[15] = ctx->d >> 24;
}
void MD5_Free(struct MD5_CTX** ctx) {
if (!ctx || !*ctx) {
return;
}
free(*ctx);
*ctx = NULL;
}

View File

@ -1,47 +0,0 @@
/*
* This is an OpenSSL-compatible implementation of the RSA Data Security, Inc.
* MD5 Message-Digest Algorithm (RFC 1321).
*
* Homepage:
* http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5
*
* Author:
* Alexander Peslyak, better known as Solar Designer <solar at openwall.com>
*
* This software was written by Alexander Peslyak in 2001. No copyright is
* claimed, and the software is hereby placed in the public domain.
* In case this attempt to disclaim copyright and place the software in the
* public domain is deemed null and void, then the software is
* Copyright (c) 2001 Alexander Peslyak and it is hereby released to the
* general public under the following terms:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted.
*
* There's ABSOLUTELY NO WARRANTY, express or implied.
*
* See md5.c for more information.
*/
#ifndef INTERNAL_MD5_H
#define INTERNAL_MD5_H
#include <sys/types.h>
#include <stdint.h>
struct MD5_CTX;
#define MD5_LENGTH 16
#ifdef __cplusplus
extern "C" {
#endif
int MD5_Init(struct MD5_CTX **ctx);
void MD5_Update(struct MD5_CTX *ctx, const void *data, size_t size);
void MD5_Final(struct MD5_CTX *ctx, uint8_t *result);
void MD5_Free(struct MD5_CTX **ctx);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INTERNAL_MD5_H */

View File

@ -1,160 +0,0 @@
/* This code is public-domain - it is based on libcrypt
* placed in the public domain by Wei Dai and other contributors.
*/
#include "sha1.h"
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#define BLOCK_LENGTH 64
union _buffer {
uint8_t b[BLOCK_LENGTH];
uint32_t w[BLOCK_LENGTH/4];
};
union _state {
uint8_t b[SHA1_LENGTH];
uint32_t w[SHA1_LENGTH/4];
};
struct SHA1_CTX {
union _buffer buffer;
uint8_t bufferOffset;
union _state state;
uint32_t byteCount;
uint8_t keyBuffer[BLOCK_LENGTH];
uint8_t innerHash[SHA1_LENGTH];
};
#define SHA1_K0 0x5a827999
#define SHA1_K20 0x6ed9eba1
#define SHA1_K40 0x8f1bbcdc
#define SHA1_K60 0xca62c1d6
const uint8_t sha1InitState[] = {
0x01,0x23,0x45,0x67, // H0
0x89,0xab,0xcd,0xef, // H1
0xfe,0xdc,0xba,0x98, // H2
0x76,0x54,0x32,0x10, // H3
0xf0,0xe1,0xd2,0xc3 // H4
};
static uint32_t sha1_rol32(uint32_t number, uint8_t bits) {
return ((number << bits) | (number >> (32-bits)));
}
static void sha1_hashBlock(struct SHA1_CTX *s) {
uint8_t i;
uint32_t a,b,c,d,e,t;
a=s->state.w[0];
b=s->state.w[1];
c=s->state.w[2];
d=s->state.w[3];
e=s->state.w[4];
for (i=0; i<80; i++) {
if (i>=16) {
t = s->buffer.w[(i+13)&15] ^ s->buffer.w[(i+8)&15] ^ s->buffer.w[(i+2)&15] ^ s->buffer.w[i&15];
s->buffer.w[i&15] = sha1_rol32(t,1);
}
if (i<20) {
t = (d ^ (b & (c ^ d))) + SHA1_K0;
} else if (i<40) {
t = (b ^ c ^ d) + SHA1_K20;
} else if (i<60) {
t = ((b & c) | (d & (b | c))) + SHA1_K40;
} else {
t = (b ^ c ^ d) + SHA1_K60;
}
t+=sha1_rol32(a,5) + e + s->buffer.w[i&15];
e=d;
d=c;
c=sha1_rol32(b,30);
b=a;
a=t;
}
s->state.w[0] += a;
s->state.w[1] += b;
s->state.w[2] += c;
s->state.w[3] += d;
s->state.w[4] += e;
}
static void sha1_addUncounted(struct SHA1_CTX *s, uint8_t data) {
s->buffer.b[s->bufferOffset ^ 3] = data;
s->bufferOffset++;
if (s->bufferOffset == BLOCK_LENGTH) {
sha1_hashBlock(s);
s->bufferOffset = 0;
}
}
static void sha1_writebyte(struct SHA1_CTX *s, uint8_t data) {
++s->byteCount;
sha1_addUncounted(s, data);
}
static void sha1_pad(struct SHA1_CTX *s) {
// Implement SHA-1 padding (fips180-2 §5.1.1)
// Pad with 0x80 followed by 0x00 until the end of the block
sha1_addUncounted(s, 0x80);
while (s->bufferOffset != 56) sha1_addUncounted(s, 0x00);
// Append length in the last 8 bytes
sha1_addUncounted(s, 0); // We're only using 32 bit lengths
sha1_addUncounted(s, 0); // But SHA-1 supports 64 bit lengths
sha1_addUncounted(s, 0); // So zero pad the top bits
sha1_addUncounted(s, s->byteCount >> 29); // Shifting to multiply by 8
sha1_addUncounted(s, s->byteCount >> 21); // as SHA-1 supports bitstreams as well as
sha1_addUncounted(s, s->byteCount >> 13); // byte.
sha1_addUncounted(s, s->byteCount >> 5);
sha1_addUncounted(s, s->byteCount << 3);
}
int SHA1_Init(struct SHA1_CTX **s) {
*s = malloc(sizeof(struct SHA1_CTX));
if (!*s) {
return 0;
}
memcpy((*s)->state.b, sha1InitState, SHA1_LENGTH);
(*s)->byteCount = 0;
(*s)->bufferOffset = 0;
return 1;
}
void SHA1_Update(struct SHA1_CTX *s, const void *data, size_t len) {
const uint8_t *bytes = data;
for (;len--;) sha1_writebyte(s, *bytes++);
}
void SHA1_Final(struct SHA1_CTX *s, unsigned char* result) {
int i;
// Pad to complete the last block
sha1_pad(s);
// Swap byte order back
for (i=0; i<5; i++) {
uint32_t a,b;
a=s->state.w[i];
b=a<<24;
b|=(a<<8) & 0x00ff0000;
b|=(a>>8) & 0x0000ff00;
b|=a>>24;
s->state.w[i]=b;
}
// Return pointer to hash (20 characters)
memcpy(result, s->state.b, sizeof(s->state.b));
}
void SHA1_Free(struct SHA1_CTX** s) {
if (!s || !*s) {
return;
}
free(*s);
*s = NULL;
}

View File

@ -1,28 +0,0 @@
/* This code is public-domain - it is based on libcrypt
* placed in the public domain by Wei Dai and other contributors.
*/
#ifndef INTERNAL_SHA1_H
#define INTERNAL_SHA1_H
#include <sys/types.h>
#include <stdint.h>
#define SHA1_LENGTH 20
struct SHA1_CTX;
#ifdef __cplusplus
extern "C" {
#endif
int SHA1_Init(struct SHA1_CTX **s);
void SHA1_Update(struct SHA1_CTX *s, const void *data, size_t len);
void SHA1_Final(struct SHA1_CTX *s, uint8_t *result);
void SHA1_Free(struct SHA1_CTX **s);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* INTERNAL_SHA1_H */

View File

@ -37,6 +37,7 @@
#include "FatalException.h"
#include "util.h"
#include "crypto_endian.h"
namespace {
using namespace aria2;
@ -156,13 +157,6 @@ HMACResult PBKDF2(HMAC* hmac,
if (key_length == 0) {
key_length = hmac_length;
}
typedef union
{
uint8_t bytes[4];
uint32_t count;
} counter_t;
counter_t counter, swapped;
counter.count = 1;
auto work = make_unique<char[]>(hmac_length);
char* p = work.get();
@ -170,10 +164,10 @@ HMACResult PBKDF2(HMAC* hmac,
hmac->reset();
while (key_length) {
for (uint32_t counter = 1; key_length; ++counter) {
hmac->update(salt, salt_length);
swapped.count = htonl(counter.count++);
hmac->update((char*)swapped.bytes, sizeof(swapped.bytes));
const uint32_t c = crypto::__crypto_be(counter);
hmac->update((char*)&c, sizeof(c));
auto bytes = hmac->getResult().getBytes();
memcpy(p, bytes.data(), bytes.length());

View File

@ -685,20 +685,14 @@ void HttpResponseTest::testGetDigest()
"MD5=LJDK2+9ClF8Nz/K5WZd/+A==");
std::vector<Checksum> result;
httpResponse.getDigest(result);
#ifdef USE_INTERNAL_MD
CPPUNIT_ASSERT_EQUAL((size_t)2, result.size());
#else // USE_INTERNAL_MD
CPPUNIT_ASSERT_EQUAL((size_t)3, result.size());
#endif // USE_INTERNAL_MD
Checksum c = result[0];
#ifndef USE_INTERNAL_MD
CPPUNIT_ASSERT_EQUAL(std::string("sha-256"), c.getHashType());
CPPUNIT_ASSERT_EQUAL(std::string("f83f271ae773dc6fe4a6454a41e0eb237c43e7bbf451e426cc60993a4d379ec5"),
util::toHex(c.getDigest()));
c = result[1];
#endif
CPPUNIT_ASSERT_EQUAL(std::string("sha-1"), c.getHashType());
CPPUNIT_ASSERT_EQUAL(std::string("f36003f22b462ffa184390533c500d8989e9f681"),
util::toHex(c.getDigest()));