File: sha256.c

package info (click to toggle)
win32-loader 0.10.6
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, sid
  • size: 1,868 kB
  • sloc: ansic: 2,492; sh: 706; asm: 344; makefile: 338
file content (178 lines) | stat: -rw-r--r-- 4,800 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/* Licensed under the zlib/libpng license (same as NSIS) */

/*
 SHA256 hepler module for the Nullsoft Installer (NSIS).
 */

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

#include <stdint.h>

#define BUFFER_SIZE 262144
#define SHA256_BLOCK_LEN 64
#define SHA256_STATE_LEN 8

extern void
sha256_compress(uint32_t state[SHA256_STATE_LEN],
                const uint8_t block[SHA256_BLOCK_LEN]) asm("sha256_compress");

typedef struct {
  uint32_t hash[SHA256_STATE_LEN];
  uint64_t size; /* total size */
  size_t n;      /* bytes in block */
  uint8_t block[SHA256_BLOCK_LEN];
} sha256_context_t;

/**
 * Allocate and acquire context
 * @return Pointer of allocated and intialized context which has to be freed by
 * caller via destroy
 */
sha256_context_t *__declspec(dllexport) __stdcall init(void) {
  sha256_context_t *context = GlobalAlloc(GPTR, sizeof(sha256_context_t));
  if (context) {
    uint32_t *hash = context->hash;
    *(hash++) = UINT32_C(0x6A09E667);
    *(hash++) = UINT32_C(0xBB67AE85);
    *(hash++) = UINT32_C(0x3C6EF372);
    *(hash++) = UINT32_C(0xA54FF53A);
    *(hash++) = UINT32_C(0x510E527F);
    *(hash++) = UINT32_C(0x9B05688C);
    *(hash++) = UINT32_C(0x1F83D9AB);
    *hash = UINT32_C(0x5BE0CD19);
  }
  return context;
}

/**
 * Include provided data into the computation of the hash value
 * @param context Pointer to context information
 * @param data Pointer of a buffer containing data to be added
 * @param len Number of bytes of data to be added
 * @return 0 if the function failed
 */
int __declspec(dllexport) __stdcall update(sha256_context_t *context,
                                           const uint8_t *data, size_t len) {
  uint32_t *hash = context->hash;
  register const uint8_t *p = data, *q;
  size_t n = context->n;

  if (n > 0) {
    /* Take care of last block */
    size_t r = SHA256_BLOCK_LEN - n;
    if (r > len) {
      r = len;
    }
    /* Fill remaining space of last block with current data */
    CopyMemory(context->block + n, p, r);
    p += r;
    n += r;
    if (n < SHA256_BLOCK_LEN) {
      context->n = n;
    } else {
      /* Process complete block */
      sha256_compress(hash, context->block);
      context->n = 0;
    }
    n = len - r;
  } else {
    n = len;
  }

  /* Determine starting address of the first incomplete block
   *
   * SHA256_BLOCK_LEN must be a power of 2 number so that the
   * bit mask works as expected.
   */
  q = p + (n & ((size_t) ~(SHA256_BLOCK_LEN - 1)));

  while (p < q) {
    sha256_compress(hash, p);
    p += SHA256_BLOCK_LEN;
  }

  n = p - data;
  if (n < len) {
    /* Copy left over data into block */
    n = len - n;
    CopyMemory(context->block, p, n);
    context->n = n;
  }

  context->size += len;
  return 1;
}

/**
 * Complete hashing and get hash value
 * @param context Pointer to context information
 * @param hash Array of eight unsigned 32-bit integers receiving the final
 *             hash value
 */
void __declspec(dllexport) __stdcall final(sha256_context_t *context,
                                           uint32_t hash[SHA256_STATE_LEN]) {
  uint64_t size = context->size;
  register uint8_t *p = context->block;
  uint8_t *q = p + SHA256_BLOCK_LEN;
  const uint8_t *r = q - sizeof(size);
  size_t n = context->n;

  CopyMemory(hash, context->hash, sizeof((*context).hash));

  p += n;
  *(p++) = 0x80;
  if (p > r) {
    SecureZeroMemory(p, (q - p));
    p = context->block;
    sha256_compress(hash, p);
  }
  SecureZeroMemory(p, (r - p));

  /* Append total size in bits (1 byte = 8 bits, times 8 = left shift by 3) */
  p = q;
  size <<= 3;
  while (p > r) {
    *(--p) = (size & 0xFF);
    size >>= 8;
  }
  sha256_compress(hash, context->block);
}

/**
 * Destroys the context information
 * @param context Pointer to context information
 * @return 0 if the function failed
 */
int __declspec(dllexport) __stdcall destroy(sha256_context_t *context) {
  return (NULL == GlobalFree(context));
}

/**
 * Compute SHA256 hash value of the content read from provided file handle
 * @param fh Handle of file to read from
 * @param hash Array of eight unsigned 32-bit integers receiving the final
 *             hash value
 */
void __declspec(dllexport) __stdcall hash(HANDLE fh,
                                          uint32_t hash[SHA256_STATE_LEN]) {
  uint8_t *buffer = GlobalAlloc(GMEM_FIXED, BUFFER_SIZE);

  if (buffer) {
    sha256_context_t *context = init();
    if (context) {
      DWORD n;
      while (ReadFile(fh, buffer, BUFFER_SIZE, &n, NULL) && n > 0) {
        update(context, buffer, n);
      }
      final(context, hash);
      destroy(context);
    }
    GlobalFree(buffer);
  }
}

BOOL __stdcall DllMainCRTStartup(HINSTANCE hinstDll, DWORD dwReason,
                                 LPVOID lpvReserved) {
  return TRUE;
}