aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-06-29 16:18:57 +0000
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2006-06-29 16:18:57 +0000
commitc5e5d9f414b4e2144741110fd6b6566780fa31e6 (patch)
treec0d5d9d39af4e7fc977ed073a93e83504d6c5816
parent812803b2abd25658b22638f1bb0b30a95f39c9b3 (diff)
downloadpaludis-c5e5d9f414b4e2144741110fd6b6566780fa31e6.tar.gz
paludis-c5e5d9f414b4e2144741110fd6b6566780fa31e6.tar.xz
Implement MD5 internally, to avoid linkage problems with external md5sum on upgrade
-rw-r--r--ebuild/digests/Makefile.am19
-rwxr-xr-xebuild/digests/domd54
-rw-r--r--ebuild/digests/domd5.cc53
-rw-r--r--ebuild/digests/md5.cc220
-rw-r--r--ebuild/digests/md5.hh67
-rw-r--r--ebuild/digests/md5_TEST.cc93
6 files changed, 446 insertions, 10 deletions
diff --git a/ebuild/digests/Makefile.am b/ebuild/digests/Makefile.am
index 46455f8..99b18dd 100644
--- a/ebuild/digests/Makefile.am
+++ b/ebuild/digests/Makefile.am
@@ -4,12 +4,10 @@ SUBDIRS = .
libexecprogdir = $(libexecdir)/paludis/digests/
-libexecprog_SCRIPTS = \
- domd5
-
libexecprog_PROGRAMS = \
dosha256 \
- dormd160
+ dormd160 \
+ domd5
dosha256_SOURCES = \
sha256.cc \
@@ -21,13 +19,18 @@ dormd160_SOURCES = \
rmd160.hh \
dormd160.cc
+domd5_SOURCES = \
+ md5.hh \
+ md5.cc \
+ domd5.cc
+
TESTS_ENVIRONMENT = env \
PALUDIS_EBUILD_DIR="$(srcdir)/ebuild/" \
TEST_SCRIPT_DIR="$(srcdir)/" \
bash $(top_srcdir)/test/run_test.sh
-TESTS = dosha256_TEST dormd160_TEST
-EXTRA_DIST = $(libexecprog_SCRIPTS) dosha256_TEST.cc dormd160_TEST.cc
+TESTS = dosha256_TEST dormd160_TEST domd5_TEST
+EXTRA_DIST = $(libexecprog_SCRIPTS) dosha256_TEST.cc dormd160_TEST.cc domd5_TEST.cc
check_SCRIPTS =
check_PROGRAMS = $(TESTS)
@@ -42,3 +45,7 @@ dormd160_TEST_SOURCES = rmd160.cc rmd160.hh dormd160_TEST.cc
dormd160_TEST_CXXFLAGS = -I$(top_srcdir)
dormd160_TEST_LDADD = $(top_builddir)/test/libtest.a
+domd5_TEST_SOURCES = md5.cc md5.hh md5_TEST.cc
+domd5_TEST_CXXFLAGS = -I$(top_srcdir)
+domd5_TEST_LDADD = $(top_builddir)/test/libtest.a
+
diff --git a/ebuild/digests/domd5 b/ebuild/digests/domd5
deleted file mode 100755
index cb82761..0000000
--- a/ebuild/digests/domd5
+++ /dev/null
@@ -1,4 +0,0 @@
-#!/bin/bash
-
-md5sum "$1" | cut -d\ -f1
-
diff --git a/ebuild/digests/domd5.cc b/ebuild/digests/domd5.cc
new file mode 100644
index 0000000..80c6821
--- /dev/null
+++ b/ebuild/digests/domd5.cc
@@ -0,0 +1,53 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "md5.hh"
+#include <iostream>
+#include <cstdlib>
+
+int
+main(int argc, char * argv[])
+{
+ if (argc >= 3)
+ {
+ std::cerr << "usage: " << argv[0] << " [filename]" << std::endl;
+ return EXIT_FAILURE;
+ }
+
+ if (argc == 2)
+ {
+ std::ifstream f(argv[1]);
+ if (! f)
+ {
+ std::cerr << argv[0] << ": could not open '" << argv[1] << "'" << std::endl;
+ return EXIT_FAILURE;
+ }
+ md5::MD5 sum(f);
+ std::cout << sum.hexsum() << std::endl;
+ }
+ else
+ {
+ md5::MD5 sum(std::cin);
+ std::cout << sum.hexsum() << std::endl;
+ }
+
+}
+
+
+
diff --git a/ebuild/digests/md5.cc b/ebuild/digests/md5.cc
new file mode 100644
index 0000000..cad7b9c
--- /dev/null
+++ b/ebuild/digests/md5.cc
@@ -0,0 +1,220 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "md5.hh"
+#include <paludis/util/attributes.hh>
+#include <sstream>
+
+using namespace md5;
+
+/*
+ * Implemented based upon the description in RFC1321.
+ */
+
+namespace
+{
+ inline uint32_t _rl(uint32_t x, unsigned int shift) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _rl(uint32_t x, unsigned int shift)
+ {
+ return (x << shift) | (x >> (32 - shift));
+ }
+
+ inline uint32_t _f(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _f(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return (x & y) | (~x & z);
+ }
+
+ inline uint32_t _g(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _g(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return (x & z) | (y & ~z);
+ }
+
+ inline uint32_t _h(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _h(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return x ^ y ^ z;
+ }
+
+ inline uint32_t _i(uint32_t x, uint32_t y, uint32_t z) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _i(uint32_t x, uint32_t y, uint32_t z)
+ {
+ return y ^ (x | ~z);
+ }
+
+ inline uint32_t _x(unsigned i, const uint8_t * const block) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _x(unsigned i, const uint8_t * const block)
+ {
+ return
+ (block[(i << 2) + 3] << 24) |
+ (block[(i << 2) + 2] << 16) |
+ (block[(i << 2) + 1] << 8) |
+ (block[(i << 2) + 0]);
+ }
+
+ inline uint32_t _e(const uint32_t x) PALUDIS_ATTRIBUTE((always_inline));
+ inline uint32_t _e(const uint32_t x)
+ {
+ return
+ ((x & 0xff) << 24) |
+ ((x & 0xff00) << 8) |
+ ((x & 0xff0000) >> 8) |
+ ((x & 0xff000000) >> 24);
+ }
+}
+
+void
+MD5::_update(const uint8_t * const block)
+{
+ uint32_t a(_r[0]), b(_r[1]), c(_r[2]), d(_r[3]), f, g, t;
+
+ for (int i(0) ; i < 16 ; ++i)
+ {
+ f = _f(b, c, d);
+ g = i;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ for (int i(16) ; i < 32 ; ++i)
+ {
+ f = _g(b, c, d);
+ g = (5 * i + 1) & 0x0f;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ for (int i(32) ; i < 48 ; ++i)
+ {
+ f = _h(b, c, d);
+ g = (3 * i + 5) & 0x0f;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ for (int i(48) ; i < 64 ; ++i)
+ {
+ f = _i(b, c, d);
+ g = (7 * i) & 0x0f;
+
+ t = d;
+ d = c;
+ c = b;
+ b = _rl(a + f + _t[i] + _x(g, block), _s[i]) + b;
+ a = t;
+ }
+
+ _r[0] += a;
+ _r[1] += b;
+ _r[2] += c;
+ _r[3] += d;
+}
+
+MD5::MD5(std::istream & stream) :
+ _size(0),
+ _done_one_pad(false)
+{
+ _r[0] = 0x67452301;
+ _r[1] = 0xefcdab89;
+ _r[2] = 0x98badcfe;
+ _r[3] = 0x10325476;
+
+ uint8_t buffer[64];
+ int c, s(0);
+ while (-1 != ((c = _get(stream))))
+ {
+ buffer[s++] = c;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+ while (56 != s)
+ {
+ buffer[s++] = 0;
+ if (64 == s)
+ {
+ _update(&buffer[0]);
+ s = 0;
+ }
+ }
+
+ buffer[56] = static_cast<uint8_t>(_size >> (0 * 8));
+ buffer[57] = static_cast<uint8_t>(_size >> (1 * 8));
+ buffer[58] = static_cast<uint8_t>(_size >> (2 * 8));
+ buffer[59] = static_cast<uint8_t>(_size >> (3 * 8));
+ buffer[60] = static_cast<uint8_t>(_size >> (4 * 8));
+ buffer[61] = static_cast<uint8_t>(_size >> (5 * 8));
+ buffer[62] = static_cast<uint8_t>(_size >> (6 * 8));
+ buffer[63] = static_cast<uint8_t>(_size >> (7 * 8));
+ _update(&buffer[0]);
+}
+
+std::string
+MD5::hexsum() const
+{
+ std::stringstream result;
+
+ for (int j(0) ; j < 4 ; ++j)
+ result << std::hex << std::right << std::setw(8) << std::setfill('0') <<
+ _e(static_cast<unsigned int>(_r[j])) << std::flush;
+
+ return result.str();
+}
+
+const uint8_t MD5::_s[64] = {
+ 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
+ 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
+ 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
+ 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21
+};
+
+const uint32_t MD5::_t[64] = {
+ 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
+ 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
+ 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
+ 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
+ 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
+ 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
+ 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
+ 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
+ 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
+ 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
+ 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
+ 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
+ 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
+ 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
+ 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
+ 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391
+};
+
diff --git a/ebuild/digests/md5.hh b/ebuild/digests/md5.hh
new file mode 100644
index 0000000..fb15578
--- /dev/null
+++ b/ebuild/digests/md5.hh
@@ -0,0 +1,67 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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
+ */
+
+#ifndef PALUDIS_GUARD_EBUILD_DIGESTS_MD5_HH
+#define PALUDIS_GUARD_EBUILD_DIGESTS_MD5_HH 1
+
+#include <fstream>
+#include <iomanip>
+#include <string>
+#include <inttypes.h>
+
+namespace md5
+{
+ class MD5
+ {
+ private:
+ static const uint32_t _t[64];
+ static const uint8_t _s[64];
+ uint32_t _r[4];
+ uint64_t _size;
+ bool _done_one_pad;
+
+ void _update(const uint8_t * const block);
+
+ inline int _get(std::istream & stream) __attribute__((always_inline))
+ {
+ char c;
+ if (stream.get(c))
+ {
+ _size += 8;
+ return static_cast<unsigned char>(c);
+ }
+ else if (! _done_one_pad)
+ {
+ _done_one_pad = true;
+ return 0x80;
+ }
+ else
+ return -1;
+ }
+
+ public:
+ MD5(std::istream & stream);
+
+ std::string hexsum() const;
+ };
+
+}
+
+
+#endif
diff --git a/ebuild/digests/md5_TEST.cc b/ebuild/digests/md5_TEST.cc
new file mode 100644
index 0000000..eeac37e
--- /dev/null
+++ b/ebuild/digests/md5_TEST.cc
@@ -0,0 +1,93 @@
+/* vim: set sw=4 sts=4 et foldmethod=syntax : */
+
+/*
+ * Copyright (c) 2006 Ciaran McCreesh <ciaran.mccreesh@blueyonder.co.uk>
+ *
+ * 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 "md5.hh"
+#include <test/test_framework.hh>
+#include <test/test_runner.hh>
+
+using namespace test;
+
+namespace
+{
+ unsigned char dehex_c(unsigned char c)
+ {
+ if (c >= '0' && c <= '9')
+ return c - '0';
+ else if (c >= 'a' && c <= 'f')
+ return c + 10 - 'a';
+ else
+ throw "meh!";
+ }
+
+ std::string dehex(const std::string & s)
+ {
+ std::string result;
+ std::string::size_type p(0);
+ while (p < s.length())
+ {
+ unsigned char c;
+ c = (dehex_c(s.at(p)) << 4) + dehex_c(s.at(p + 1));
+ result.append(1, c);
+ p += 2;
+ }
+ return result;
+ }
+}
+
+namespace test_cases
+{
+ struct MD5TestCase : TestCase
+ {
+ std::string data;
+ std::string expected;
+
+ MD5TestCase(const std::string & s, const std::string & d,
+ const std::string & e) :
+ TestCase("md5 " + s),
+ data(d),
+ expected(e)
+ {
+ }
+
+ void run()
+ {
+ std::stringstream ss(data);
+ md5::MD5 s(ss);
+ TEST_CHECK_EQUAL(s.hexsum(), expected);
+ }
+ };
+
+ MD5TestCase t_0("empty", "", "d41d8cd98f00b204e9800998ecf8427e");
+ MD5TestCase t_1("a", "a", "0cc175b9c0f1b6a831c399e269772661");
+ MD5TestCase t_2("abc", "abc", "900150983cd24fb0d6963f7d28e17f72");
+ MD5TestCase t_3("message digest", "message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+ MD5TestCase t_4("a..z", "abcdefghijklmnopqrstuvwxyz",
+ "c3fcd3d76192e4007dfb496cca67e13b");
+ MD5TestCase t_6("A...Za...z0...9",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ "d174ab98d277d9f5a5611c2c9f419d9f");
+ MD5TestCase t_7("8 times 1234567890",
+ "12345678901234567890123456789012345678901234567890123456789012345678901234567890",
+ "57edf4a22be3c955ac49da2e2107b67a");
+ MD5TestCase t_8("one million times a",
+ std::string(1000000, 'a'),
+ "7707d6ae4e027c70eea2a935c2296f21");
+}
+
+