Exheredludis/paludis/util/sha1.cc
2011-10-14 23:04:29 +01:00

194 lines
4.7 KiB
C++

/* vim: set sw=4 sts=4 et foldmethod=syntax : */
/*
* Copyright (c) 2008 David Leverton
*
* This file is part of the Paludis package manager. Paludis is free software;
* you can redistribute it and/or modify it under the terms of the GNU General
* Public License version 2, as published by the Free Software Foundation.
*
* Paludis is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <paludis/util/sha1.hh>
#include <paludis/util/byte_swap.hh>
#include <paludis/util/digest_registry.hh>
#include <sstream>
#include <istream>
#include <iomanip>
#include <algorithm>
using namespace paludis;
/*
* Implemented based upon the description in RFC3174.
*/
namespace
{
template <int n_>
inline uint32_t s(uint32_t x)
{
return (x << n_) | (x >> (32 - n_));
}
template <int, int> struct ChunkParams;
template<>
struct ChunkParams<0, 20>
{
static uint32_t f(uint32_t b, uint32_t c, uint32_t d)
{
return (b & c) | (~b & d);
}
static const uint32_t k = 0x5A827999U;
};
template<>
struct ChunkParams<20, 40>
{
static uint32_t f(uint32_t b, uint32_t c, uint32_t d)
{
return b ^ c ^ d;
}
static const uint32_t k = 0x6ED9EBA1U;
};
template<>
struct ChunkParams<40, 60>
{
static uint32_t f(uint32_t b, uint32_t c, uint32_t d)
{
return (b & c) | (b & d) | (c & d);
}
static const uint32_t k = 0x8F1BBCDCU;
};
template<>
struct ChunkParams<60, 80>
{
static uint32_t f(uint32_t b, uint32_t c, uint32_t d)
{
return b ^ c ^ d;
}
static const uint32_t k = 0xCA62C1D6U;
};
template <int t_, int u_, int i_ = t_>
struct ProcessChunk : ChunkParams<t_, u_>
{
using ChunkParams<t_, u_>::f;
using ChunkParams<t_, u_>::k;
static void process(uint32_t * w, uint32_t & a, uint32_t & b, uint32_t & c, uint32_t & d, uint32_t & e)
{
uint32_t temp(s<5>(a) + f(b, c, d) + e + w[i_] + k);
e = d;
d = c;
c = s<30>(b);
b = a;
a = temp;
ProcessChunk<t_, u_, i_ + 1>::process(w, a, b, c, d, e);
}
};
template <int t_, int u_>
struct ProcessChunk<t_, u_, u_>
{
static void process(uint32_t *, uint32_t &, uint32_t &, uint32_t &, uint32_t &, uint32_t &)
{
}
};
}
void
SHA1::process_block(uint32_t * w)
{
uint32_t a(h0), b(h1), c(h2), d(h3), e(h4);
std::transform(&w[0], &w[16], &w[0], from_bigendian<uint32_t>);
for (int t = 16; t < 80; ++t)
w[t] = s<1>(w[t - 3] ^ w[t - 8] ^ w[t - 14] ^ w[t - 16]);
ProcessChunk< 0, 20>::process(w, a, b, c, d, e);
ProcessChunk<20, 40>::process(w, a, b, c, d, e);
ProcessChunk<40, 60>::process(w, a, b, c, d, e);
ProcessChunk<60, 80>::process(w, a, b, c, d, e);
h0 += a;
h1 += b;
h2 += c;
h3 += d;
h4 += e;
}
SHA1::SHA1(std::istream & s) :
h0(0x67452301U),
h1(0xEFCDAB89U),
h2(0x98BADCFEU),
h3(0x10325476U),
h4(0xC3D2E1F0U)
{
std::streambuf * buf(s.rdbuf());
uint64_t size(0);
union
{
uint8_t m[64];
uint32_t w[80];
} block;
std::streamsize block_size;
do
{
block_size = buf->sgetn(reinterpret_cast<char *>(block.m), 64);
size += block_size * 8;
if (64 != block_size)
{
block.m[block_size++] = 0x80U;
if (56 < block_size)
{
std::fill(&block.m[block_size], &block.m[64], 0);
process_block(block.w);
block_size = 0;
}
std::fill(&block.m[block_size], &block.m[56], 0);
block.w[14] = to_bigendian<uint32_t>((size >> 32) & 0xFFFFFFFFU);
block.w[15] = to_bigendian<uint32_t>(size & 0xFFFFFFFFU);
}
process_block(block.w);
} while (64 == block_size);
}
std::string
SHA1::hexsum() const
{
std::stringstream result;
result << std::hex << std::right << std::setfill('0');
result << std::setw(8) << h0;
result << std::setw(8) << h1;
result << std::setw(8) << h2;
result << std::setw(8) << h3;
result << std::setw(8) << h4;
return result.str();
}
namespace
{
DigestRegistry::Registration<SHA1> registration("SHA1");
}