Browse Source

SHA: Fix some implementation-defined behaviour (#343)

* SHA: Fix negative base shift UB

* SHA: Avoid signed integer overflow

We do cast from uint32_t to int32_t but that should be OK everywhere.

* SHA: Always use portable arithmetic right shift
pull/350/head
Gleb Mazovetskiy 7 years ago committed by Anders Jenbo
parent
commit
c2056c6cbf
  1. 35
      Source/sha.cpp
  2. 5
      Source/sha.h
  3. 4
      structs.h

35
Source/sha.cpp

@ -1,7 +1,36 @@
#include "diablo.h"
#include <cstdint>
DEVILUTION_BEGIN_NAMESPACE
// Diablo's "SHA1" is different from actual SHA1 in that it uses arithmetic
// right shifts (sign bit extension).
//
// Note that:
// 1. Tere is a C++20 proposal to make right shift always defined
// as an arithmetic shift with sign extension:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0907r1.html
// 2. Modern C++ compilers (GCC 8+, Clang 7+) compile the portable code
// to the same assembly as the implementation defined `value >> bits`:
// https://stackoverflow.com/a/53766752
namespace {
std::uint32_t asr(std::int32_t value, std::int32_t amount)
{
return value < 0 ? ~(~value >> amount) : value >> amount;
}
/*
* Diablo-"SHA1" circular left shift.
*/
std::uint32_t SHA1CircularShift(std::uint32_t bits, std::uint32_t word) {
return (word << bits) | asr(word, 32 - bits);
}
} // namespace
SHA1Context sgSHA1[3];
void SHA1Clear()
@ -50,9 +79,9 @@ void SHA1Input(SHA1Context *context, const char *message_array, int len)
void SHA1ProcessMessageBlock(SHA1Context *context)
{
int i, temp;
int W[80];
int A, B, C, D, E;
DWORD i, temp;
DWORD W[80];
DWORD A, B, C, D, E;
DWORD *buf = (DWORD *)context->buffer;
for (i = 0; i < 16; i++)

5
Source/sha.h

@ -2,11 +2,6 @@
#ifndef __SHA_H__
#define __SHA_H__
/*
* Define the SHA1 circular left shift macro
*/
#define SHA1CircularShift(bits, word) \
(((word) << (bits)) | ((word) >> (32 - (bits))))
#define SHA1HashSize 20
//sha

4
structs.h

@ -1433,8 +1433,8 @@ typedef struct PATHNODE {
//////////////////////////////////////////////////
typedef struct SHA1Context {
int state[5];
int count[2];
DWORD state[5];
DWORD count[2];
char buffer[64];
} SHA1Context;

Loading…
Cancel
Save