Skip to content

Commit

Permalink
Fix endian issue copying md5 result to byte buffer.
Browse files Browse the repository at this point in the history
Fix the sha1 and md5 unit tests for endian correctness.
Originally identified by BinCaoWR in GitHub issue boostorg#86 and PR boostorg#87

This fixes boostorg#86
This closes boostorg#87
  • Loading branch information
jeking3 committed Jun 25, 2019
1 parent 5e55711 commit eabf964
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 65 deletions.
25 changes: 21 additions & 4 deletions include/boost/uuid/detail/md5.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/uuid/uuid.hpp> // for version
#include <boost/predef/other/endian.h>
#include <string.h>

namespace boost {
Expand Down Expand Up @@ -287,12 +288,28 @@ class md5
memcpy(ctx->buffer, data, size);
}

// This must remain consistent no matter the endianness
#define BOOST_UUID_DETAIL_MD5_OUT(dst, src) \
(dst)[0] = (unsigned char)(src); \
(dst)[1] = (unsigned char)((src) >> 8); \
(dst)[2] = (unsigned char)((src) >> 16); \
(dst)[3] = (unsigned char)((src) >> 24);

// When we copy into a byte buffer, take endianness into account
#if BOOST_ENDIAN_LITTLE_BYTE
#define BOOST_UUID_DETAIL_MD5_BYTE_OUT(dst, src) \
(dst)[0] = (unsigned char)((src) >> 24); \
(dst)[1] = (unsigned char)((src) >> 16); \
(dst)[2] = (unsigned char)((src) >> 8); \
(dst)[3] = (unsigned char)(src);
#else
#define BOOST_UUID_DETAIL_MD5_BYTE_OUT(dst, src) \
(dst)[0] = (unsigned char)(src); \
(dst)[1] = (unsigned char)((src) >> 8); \
(dst)[2] = (unsigned char)((src) >> 16); \
(dst)[3] = (unsigned char)((src) >> 24);
#endif

void MD5_Final(unsigned char *result, MD5_CTX *ctx)
{
unsigned long used, available;
Expand All @@ -318,10 +335,10 @@ class md5

body(ctx, ctx->buffer, 64);

BOOST_UUID_DETAIL_MD5_OUT(&result[0], ctx->a)
BOOST_UUID_DETAIL_MD5_OUT(&result[4], ctx->b)
BOOST_UUID_DETAIL_MD5_OUT(&result[8], ctx->c)
BOOST_UUID_DETAIL_MD5_OUT(&result[12], ctx->d)
BOOST_UUID_DETAIL_MD5_BYTE_OUT(&result[0], ctx->a)
BOOST_UUID_DETAIL_MD5_BYTE_OUT(&result[4], ctx->b)
BOOST_UUID_DETAIL_MD5_BYTE_OUT(&result[8], ctx->c)
BOOST_UUID_DETAIL_MD5_BYTE_OUT(&result[12], ctx->d)

memset(ctx, 0, sizeof(*ctx));
}
Expand Down
2 changes: 1 addition & 1 deletion include/boost/uuid/detail/sha1.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ inline void sha1::process_block()
inline unsigned char sha1::get_version() const
{
// RFC 4122 Section 4.1.3
return uuid::version_name_based_sha1;
return uuid::version_name_based_sha1;
}

inline void sha1::get_digest(digest_type& digest)
Expand Down
73 changes: 73 additions & 0 deletions test/digestutils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// Copyright (C) 2019 James E. King III
//
// Permission to copy, use, modify, sell and
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_UUID_TEST_ENDIAN_2019
#define BOOST_UUID_TEST_ENDIAN_2019

#include <boost/predef/other/endian.h>

namespace boost {
namespace uuids {
namespace test {

//
// A utility to copy a raw digest out from one of the detail hash functions
// to a byte string for comparisons in testing to known values.
//
static void copy_raw_digest(unsigned char* out, const unsigned int *in, size_t inlen)
{
for (size_t chunk = 0; chunk < inlen; ++chunk)
{
const unsigned char * cin = reinterpret_cast<const unsigned char *>(&in[chunk]);
for (size_t byte = 0; byte < 4; ++byte)
{
#if BOOST_ENDIAN_LITTLE_BYTE
*out++ = *(cin + (3-byte));
#else
*out++ = *(cin + byte);
#endif
}
}
}

//
// A utility to compare and report two raw hashes
//
static void test_digest_equal_array(char const * file, int line, char const * function,
const unsigned char *lhs,
const unsigned char *rhs,
size_t len)
{
for (size_t i=0; i<len; i++) {
if ( lhs[i] != rhs[i]) {
std::cerr << file << "(" << line << "): digest [";
for (size_t l=0; l<len; l++) {
std::cerr << std::hex << (int)lhs[l];
}

std::cerr << "] not equal [";
for (size_t r=0; r<len; r++) {
std::cerr << std::hex << (int)rhs[r];
}
std::cerr << "] in function '" << function << "'" << std::endl;
++boost::detail::test_errors();
return;
}
}
}

}
}
}

#endif
12 changes: 9 additions & 3 deletions test/test_md5.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// libs/uuid/test/test_md5.cpp --------------------------------//

// (C) Copyright 2017 James E. King III
// (C) Copyright 2017 - 2019 James E. King III

// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
Expand All @@ -10,6 +10,11 @@
#include <boost/detail/lightweight_test.hpp>
#include <boost/uuid/detail/md5.hpp>

#include "digestutils.hpp"

#define BOOST_TEST_MD5_DIGEST(lhs, rhs) \
( boost::uuids::test::test_digest_equal_array(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (lhs), (rhs), 16) )

int main(int, char**)
{
typedef struct
Expand Down Expand Up @@ -37,8 +42,9 @@ int main(int, char**)
hash.process_bytes(expectations[i].data, expectations[i].len);
boost::uuids::detail::md5::digest_type result;
hash.get_digest(result);
BOOST_TEST_EQ(0, memcmp(result, expectations[i].expected,
sizeof(boost::uuids::detail::md5::digest_type)));
unsigned char raw_result[16];
boost::uuids::test::copy_raw_digest(raw_result, result, 4);
BOOST_TEST_MD5_DIGEST(raw_result, expectations[i].expected);
BOOST_TEST_EQ(hash.get_version(), 0x03);

}
Expand Down
2 changes: 1 addition & 1 deletion test/test_name_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ int main(int, char*[])

uuid correct_sha1 = {{0x21, 0xf7, 0xf8, 0xde, 0x80, 0x51, 0x5b, 0x89, 0x86, 0x80, 0x01, 0x95, 0xef, 0x79, 0x8b, 0x6a}};
uuid wcorrect_sha1 = {{0xc3, 0x15, 0x27, 0x0b, 0xa4, 0x66, 0x58, 0x72, 0xac, 0xa4, 0x96, 0x26, 0xce, 0xc0, 0xf4, 0xbe}};
uuid correct_md5 = {{0xec, 0x5c, 0x20, 0x06, 0x0e, 0x00, 0x3b, 0x25, 0xa0, 0xa8, 0xbc, 0xe8, 0x4e, 0x24, 0xb8, 0x5a}};
uuid correct_md5 = {{0x06, 0x20, 0x5c, 0xec, 0x25, 0x5b, 0x30, 0x0e, 0xa8, 0xbc, 0xa8, 0x60, 0x5a, 0xb8, 0x24, 0x4e}};

name_generator_sha1 gen(ns::dns());

Expand Down
92 changes: 36 additions & 56 deletions test/test_sha1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@
// distribute this software is granted provided this copyright notice appears
// in all copies. This software is provided "as is" without express or implied
// warranty, and with no claim as to its suitability for any purpose.

//
// Copyright (C) 2019 James E. King III
//
// Distributed under the Boost Software License, Version 1.0. (See
// accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)
Expand All @@ -15,73 +17,50 @@
#include <cstring>
#include <cstddef>

#include "digestutils.hpp"

#ifdef BOOST_NO_STDC_NAMESPACE
namespace std {
using ::strlen;
using ::size_t;
} //namespace std
#endif

void test_sha1_digest_equal_array(char const * file, int line, char const * function,
const unsigned int (&lhs)[5], const unsigned int (&rhs)[5])
{
for (size_t i=0; i<5; i++) {
if ( lhs[i] != rhs[i]) {
std::cerr << file << "(" << line << "): sha1 digest [";
for (size_t l=0; l<5; l++) {
if (l != 0) {
std::cerr << " ";
}
std::cerr << std::hex << (int)lhs[l];
}

std::cerr << "] not equal [";
for (size_t r=0; r<5; r++) {
if (r != 0) {
std::cerr << " ";
}
std::cerr << std::hex << (int)rhs[r];
}
std::cerr << "] in function '" << function << "'" << std::endl;
++boost::detail::test_errors();
return;
}
}
}


#define BOOST_TEST_SHA1_DIGEST(lhs, rhs) ( test_sha1_digest_equal_array(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, lhs, rhs) )

void test_sha1(char const*const message, std::size_t length, const unsigned int (&correct_digest)[5])
{
boost::uuids::detail::sha1 sha;
sha.process_bytes(message, length);

unsigned int digest[5];
sha.get_digest(digest);

BOOST_TEST_SHA1_DIGEST(digest, correct_digest);
}
#define BOOST_TEST_SHA1_DIGEST(lhs, rhs) \
( boost::uuids::test::test_digest_equal_array(__FILE__, __LINE__, BOOST_CURRENT_FUNCTION, (lhs), (rhs), 20) )

void test_quick()
{
struct test_case
typedef struct
{
char const* message;
unsigned int digest[5];
};
test_case cases[] =
{ { "",
{ 0xda39a3ee, 0x5e6b4b0d, 0x3255bfef, 0x95601890, 0xafd80709 } }
, { "The quick brown fox jumps over the lazy dog",
{ 0x2fd4e1c6, 0x7a2d28fc, 0xed849ee1, 0xbb76e739, 0x1b93eb12 } }
, { "The quick brown fox jumps over the lazy cog",
{ 0xde9f2c7f, 0xd25e1b3a, 0xfad3e85a, 0x0bd17d9b, 0x100db4b3 } }
const char * data;
boost::uint32_t len;
unsigned char expected[20];
} Expectation;

/* http://www.febooti.com/products/filetweak/members/hash-and-crc/test-vectors/ */
Expectation expectations[3] = {
{ "The quick brown fox jumps over the lazy dog", 43,
{ 0x2f, 0xd4, 0xe1, 0xc6, 0x7a, 0x2d, 0x28, 0xfc, 0xed, 0x84,
0x9e, 0xe1, 0xbb, 0x76, 0xe7, 0x39, 0x1b, 0x93, 0xeb, 0x12 }},
{ "Test vector from febooti.com", 28,
{ 0xa7, 0x63, 0x17, 0x95, 0xf6, 0xd5, 0x9c, 0xd6, 0xd1, 0x4e,
0xbd, 0x00, 0x58, 0xa6, 0x39, 0x4a, 0x4b, 0x93, 0xd8, 0x68 }},
{ "", 0,
{ 0xda, 0x39, 0xa3, 0xee, 0x5e, 0x6b, 0x4b, 0x0d, 0x32, 0x55,
0xbf, 0xef, 0x95, 0x60, 0x18, 0x90, 0xaf, 0xd8, 0x07, 0x09 }}
};

for (int i=0; i!=sizeof(cases)/sizeof(cases[0]); ++i) {
test_case const& tc = cases[i];
test_sha1(tc.message, std::strlen(tc.message), tc.digest);
for (boost::uint32_t i = 0; i < 3; ++i) {
boost::uuids::detail::sha1 hash;
hash.process_bytes(expectations[i].data, expectations[i].len);
boost::uuids::detail::sha1::digest_type result;
hash.get_digest(result);
unsigned char raw_result[20];
boost::uuids::test::copy_raw_digest(raw_result, result, 5);
BOOST_TEST_SHA1_DIGEST(raw_result, expectations[i].expected);
BOOST_TEST_EQ(0, memcmp(raw_result, expectations[i].expected, 20));
BOOST_TEST_EQ(hash.get_version(), 0x05);
}
}

Expand Down Expand Up @@ -259,7 +238,8 @@ void test_short_messages()
unsigned int digest[5];
sha.get_digest(digest);

BOOST_TEST_SHA1_DIGEST(digest, tc.digest);
BOOST_TEST_SHA1_DIGEST(reinterpret_cast<const unsigned char *>(&digest[0]),
reinterpret_cast<const unsigned char *>(&tc.digest[0]));
}
}

Expand Down
1 change: 1 addition & 0 deletions test/test_string_generator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ int main(int, char*[])
const uuid u_decreasing = {{ 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10,0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 }};

u = gen("0123456789abcdef0123456789ABCDEF");
BOOST_TEST_EQ(memcmp(&u, &u_increasing, sizeof(uuid)), 0);
BOOST_TEST_EQ(u, u_increasing);

u = gen("{0123456789abcdef0123456789ABCDEF}");
Expand Down

0 comments on commit eabf964

Please sign in to comment.