Harmonic Flow Framework (libhffwk)
Cross platform C++ 2D Game Engine Framework
Crypto.cpp
1 /*
2  Harmonic Flow Framework
3  Copyright (C) 2011-2018 Andreas Widen <andreas@harmonicflow.org>
4 
5  This software is provided 'as-is', without any express or implied
6  warranty. In no event will the authors be held liable for any damages
7  arising from the use of this software.
8 
9  Permission is granted to anyone to use this software for any purpose,
10  including commercial applications, and to alter it and redistribute it
11  freely, subject to the following restrictions:
12 
13  1. The origin of this software must not be misrepresented; you must not
14  claim that you wrote the original software. If you use this software
15  in a product, an acknowledgment in the product documentation would be
16  appreciated but is not required.
17  2. Altered source versions must be plainly marked as such, and must not be
18  misrepresented as being the original software.
19  3. This notice may not be removed or altered from any source distribution.
20 */
21 #include "Crypto.h"
22 
23 #include "AES.h"
24 
25 #include "platform/PakInterface.h"
26 #include "platform/Environment.h"
27 #include "storage/Storage.h"
28 
29 #include <assert.h>
30 #include <stdio.h>
31 #include <string.h> /* memset(), memcpy() */
32 #include "md5.h"
33 #include "sha1.h"
34 #include "sha224.h"
35 #include "sha256.h"
36 #include "sha384.h"
37 #include "sha512.h"
38 
39 using namespace HFCore;
40 
41 #include "debug/CrtDbgNew.h"
42 
43 void Crypto::aesEncrypt(const uint8_hf *key, AESKeySize keySize, const int8_hf *inData,
44  int32_hf inDataSize, int8_hf **outData, int32_hf *outDataSize)
45 {
46  // allocate output data buffer:
47  *outDataSize = (inDataSize + 15) & (~15); // round up
48  *outData = new int8_hf[*outDataSize];
49 
50  // if there's no key, we don't need to decrypt anything, simply copy:
51  if (key == NULL)
52  {
53  memset(*outData, 0, *outDataSize * sizeof(int8_hf)); // zero out the memory
54  memcpy(*outData, inData, inDataSize); // copy input data to output buffer
55  return;
56  }
57 
58  // encrypt temporary buffer into output data:
59  AES crypt;
60  crypt.SetParameters((int32_hf)keySize);
61  crypt.StartEncryption(key); // set encryption key
62  crypt.Encrypt(
63  reinterpret_cast<const uint8_hf *>(inData),
64  reinterpret_cast<uint8_hf *>(*outData),
65  *outDataSize / 16); // encrypt
66 }
67 
68 void Crypto::aesDecrypt(const uint8_hf *key, AESKeySize keySize, const int8_hf *inData,
69  int32_hf inDataSize, int8_hf **outData, int32_hf *outDataSize)
70 {
71  // allocate output data buffer:
72  *outDataSize = (inDataSize + 15) & (~15); // round up
73  assert(*outDataSize == inDataSize);
74  *outData = new int8_hf[*outDataSize];
75 
76  // if there's no key, we don't need to encrypt anything, simply copy:
77  if (key == NULL)
78  {
79  memset(*outData, 0, *outDataSize * sizeof(int8_hf)); // zero out the memory
80  memcpy(*outData, inData, inDataSize); // copy input data to output buffer
81  return;
82  }
83 
84  // encrypt temporary buffer into output data:
85  AES crypt;
86  crypt.SetParameters((int32_hf)keySize);
87  crypt.StartDecryption(key); // set encryption key
88  crypt.Decrypt(
89  reinterpret_cast<const uint8_hf *>(inData),
90  reinterpret_cast<uint8_hf *>(*outData),
91  *outDataSize / 16); // decrypt
92 }
93 
94 bool Crypto::loadAESDecrypt(const uint8_hf *key, AESKeySize keySize, const int8_hf *filename,
95  int8_hf **outData, int32_hf *outDataSize)
96 {
97  // read file contents:
98  int8_hf *inData = NULL;
99  int32_hf size = 0;
100  if (Crypto::readFileContents(filename, &inData, &size) == 0)
101  {
102  return false;
103  }
104 
105  if (key != NULL && inData != NULL)
106  {
107  // decrypt it:
108  Crypto::aesDecrypt(key, keySize, inData, size, outData, outDataSize);
109  }
110  else
111  {
112  *outData = inData;
113  *outDataSize = size;
114  }
115 
116  // delete the input data buffer:
117  HF_SAFE_DELETE_ARR(inData);
118 
119  return true;
120 }
121 
122 std::string Crypto::md5sum(const std::string &s)
123 {
124  // init:
125  md5_state_t pms;
126  memset(&pms, 0, sizeof(md5_state_t));
127  md5_init(&pms);
128 
129  // get digest:
130  md5_byte_t digest[16];
131  md5_append(&pms, (const md5_byte_t *)s.c_str(), (int32_hf)s.length());
132  md5_finish(&pms, digest);
133 
134  // hex representation of digest as string:
135  std::string checksum = getHexStringForDigest(digest, 16);
136 
137  return checksum;
138 }
139 
140 std::string Crypto::md5sumForFile(const std::string &fileName)
141 {
142  std::string sum = Crypto::getHashChecksumForFile(fileName, HASH_TYPE_MD5);
143  return sum;
144 }
145 
146 std::string Crypto::sha1sum(const std::string &s)
147 {
148  std::string sha1checksum = "";
149 
150  SHA1 sha1;
151  sha1.update(s);
152  sha1checksum = sha1.final();
153 
154  return sha1checksum;
155 }
156 
157 std::string Crypto::sha1sumForFile(const std::string &fileName)
158 {
159  std::string sum = Crypto::getHashChecksumForFile(fileName, HASH_TYPE_SHA1);
160  return sum;
161 }
162 
163 std::string Crypto::sha224sum(const std::string &s)
164 {
165  uint8_hf digest[SHA224::DIGEST_SIZE];
166  memset(digest, 0, SHA224::DIGEST_SIZE);
167 
168  SHA224 ctx = SHA224();
169  ctx.init();
170  ctx.update((uint8_hf *)s.c_str(), s.length());
171  ctx.final(digest);
172 
173  // hex representation of digest as string:
174  std::string checksum = getHexStringForDigest(digest, SHA224::DIGEST_SIZE);
175 
176  return checksum;
177 }
178 
179 std::string Crypto::sha224sumForFile(const std::string &fileName)
180 {
181  std::string sum = Crypto::getHashChecksumForFile(fileName, HASH_TYPE_SHA224);
182  return sum;
183 }
184 
185 std::string Crypto::sha256sum(const std::string &s)
186 {
187  uint8_hf digest[SHA256::DIGEST_SIZE];
188  memset(digest, 0, SHA256::DIGEST_SIZE);
189 
190  SHA256 ctx = SHA256();
191  ctx.init();
192  ctx.update((uint8_hf *)s.c_str(), s.length());
193  ctx.final(digest);
194 
195  // hex representation of digest as string:
196  std::string checksum = getHexStringForDigest(digest, SHA256::DIGEST_SIZE);
197 
198  return checksum;
199 }
200 
201 std::string Crypto::sha256sumForFile(const std::string &fileName)
202 {
203  std::string sum = Crypto::getHashChecksumForFile(fileName, HASH_TYPE_SHA256);
204  return sum;
205 }
206 
207 std::string Crypto::sha384sum(const std::string &s)
208 {
209  uint8_hf digest[SHA384::DIGEST_SIZE];
210  memset(digest, 0, SHA384::DIGEST_SIZE);
211  SHA384 ctx = SHA384();
212  ctx.init();
213  ctx.update((uint8_hf *)s.c_str(), s.length());
214  ctx.final(digest);
215 
216  // hex representation of digest as string:
217  std::string checksum = getHexStringForDigest(digest, SHA384::DIGEST_SIZE);
218 
219  return checksum;
220 }
221 
222 std::string Crypto::sha384sumForFile(const std::string &fileName)
223 {
224  std::string sum = Crypto::getHashChecksumForFile(fileName, HASH_TYPE_SHA384);
225  return sum;
226 }
227 
228 std::string Crypto::sha512sum(const std::string &s)
229 {
230  uint8_hf digest[SHA512::DIGEST_SIZE];
231  memset(digest, 0, SHA512::DIGEST_SIZE);
232  SHA512 ctx = SHA512();
233  ctx.init();
234  ctx.update((uint8_hf *)s.c_str(), s.length());
235  ctx.final(digest);
236 
237  // hex representation of digest as string:
238  std::string checksum = getHexStringForDigest(digest, SHA512::DIGEST_SIZE);
239 
240  return checksum;
241 }
242 
243 std::string Crypto::sha512sumForFile(const std::string &fileName)
244 {
245  std::string sum = Crypto::getHashChecksumForFile(fileName, HASH_TYPE_SHA512);
246  return sum;
247 }
248 
249 size_t Crypto::readFileContents(const std::string &fileName,
250  int8_hf **outData,
251  int32_hf *outDataSize)
252 {
253  *outData = NULL;
254  *outDataSize = 0;
255 
256  // open the input file:
257  int32_hf fileSize = 0;
258  int8_hf *inData = HFCORE_STORAGE->GetFileContents(fileName.c_str(), &fileSize);
259  if (inData == NULL)
260  {
261  return 0;
262  }
263 
264  *outData = inData;
265  *outDataSize = fileSize;
266  return (size_t)fileSize;
267 }
268 
269 std::string Crypto::getHashChecksumForFile(const std::string &fileName,
270  HashType hashType)
271 {
272  std::string checksum = "";
273 
274  // open the input file:
275  PFILE *file = p_fopen(fileName.c_str(), "rb");
276  if (file == NULL)
277  {
278  return checksum;
279  }
280 
281  // figure out how big it is:
282  p_fseek(file, 0, SEEK_END);
283  size_t totalSize = (size_t)p_ftell(file);
284  p_fseek(file, 0, SEEK_SET);
285 
286  size_t chunkSize = 4096;
287  size_t curChunkSize = chunkSize;
288  size_t totalRead = 0;
289  size_t numChunks = (size_t)(ceil((fp64_hf)totalSize / (fp64_hf)chunkSize));
290  size_t readdata = 0;
291  bool lastChunk = false;
292  bool init = true;
293 
294  // ctx:
295  md5_state_t pms;
296  SHA1 sha1;
297  SHA224 ctxSHA224 = SHA224();
298  SHA256 ctxSHA256 = SHA256();
299  SHA384 ctxSHA384 = SHA384();
300  SHA512 ctxSHA512 = SHA512();
301 
302  for (size_t i = 1; i <= numChunks; i++)
303  {
304  curChunkSize = chunkSize;
305  if (i == numChunks)
306  {
307  curChunkSize = totalSize - totalRead;
308  lastChunk = true;
309  }
310 
311  int8_hf *chunk = new int8_hf[curChunkSize];
312  if (chunk == NULL)
313  {
314  return checksum;
315  }
316  memset(chunk, 0, curChunkSize * sizeof(int8_hf));
317  readdata = p_fread(chunk, 1, curChunkSize, file);
318  totalRead += readdata;
319 
320  if (hashType == HASH_TYPE_MD5)
321  {
322  if (init)
323  {
324  // init:
325  memset(&pms, 0, sizeof(md5_state_t));
326  md5_init(&pms);
327  init = false;
328  }
329 
330  // append chunk:
331  md5_append(&pms, (const md5_byte_t *)chunk, curChunkSize);
332 
333  if (lastChunk)
334  {
335  // get digest:
336  md5_byte_t digest[16];
337  md5_finish(&pms, digest);
338 
339  // hex representation of digest as string:
340  checksum = getHexStringForDigest(digest, 16);
341  }
342  }
343  else if (hashType == HASH_TYPE_SHA1)
344  {
345  std::string s(chunk, curChunkSize);
346  // append chunk:
347  sha1.update(s);
348  if (lastChunk)
349  {
350  // hex representation of digest as string:
351  checksum = sha1.final();
352  }
353  }
354  else if (hashType == HASH_TYPE_SHA224)
355  {
356  if (init)
357  {
358  ctxSHA224.init();
359  init = false;
360  }
361 
362  // append chunk:
363  ctxSHA224.update((uint8_hf *)chunk, curChunkSize);
364 
365  if (lastChunk)
366  {
367  // get digest:
368  uint8_hf digest[SHA224::DIGEST_SIZE];
369  memset(digest, 0, SHA224::DIGEST_SIZE);
370  ctxSHA224.final(digest);
371 
372  // hex representation of digest as string:
373  checksum = getHexStringForDigest(digest, SHA224::DIGEST_SIZE);
374  }
375  }
376  else if (hashType == HASH_TYPE_SHA256)
377  {
378  if (init)
379  {
380  ctxSHA256.init();
381  init = false;
382  }
383 
384  // append chunk:
385  ctxSHA256.update((uint8_hf *)chunk, curChunkSize);
386 
387  if (lastChunk)
388  {
389  // get digest:
390  uint8_hf digest[SHA256::DIGEST_SIZE];
391  memset(digest, 0, SHA256::DIGEST_SIZE);
392  ctxSHA256.final(digest);
393 
394  // hex representation of digest as string:
395  checksum = getHexStringForDigest(digest, SHA256::DIGEST_SIZE);
396  }
397  }
398  else if (hashType == HASH_TYPE_SHA384)
399  {
400  if (init)
401  {
402  ctxSHA384.init();
403  init = false;
404  }
405 
406  // append chunk:
407  ctxSHA384.update((uint8_hf *)chunk, curChunkSize);
408 
409  if (lastChunk)
410  {
411  // get digest:
412  uint8_hf digest[SHA384::DIGEST_SIZE];
413  memset(digest, 0, SHA384::DIGEST_SIZE);
414  ctxSHA384.final(digest);
415 
416  // hex representation of digest as string:
417  checksum = getHexStringForDigest(digest, SHA384::DIGEST_SIZE);
418  }
419  }
420  else if (hashType == HASH_TYPE_SHA512)
421  {
422  if (init)
423  {
424  ctxSHA512.init();
425  init = false;
426  }
427 
428  // append chunk:
429  ctxSHA512.update((uint8_hf *)chunk, curChunkSize);
430 
431  if (lastChunk)
432  {
433  // get digest:
434  uint8_hf digest[SHA512::DIGEST_SIZE];
435  memset(digest, 0, SHA512::DIGEST_SIZE);
436  ctxSHA512.final(digest);
437 
438  // hex representation of digest as string:
439  checksum = getHexStringForDigest(digest, SHA512::DIGEST_SIZE);
440  }
441  }
442  HF_SAFE_DELETE_ARR(chunk);
443  }
444  p_fclose(file);
445 
446  return checksum;
447 }
448 
449 std::string Crypto::getHexStringForDigest(const uint8_hf *digest,
450  uint32_hf digestSize)
451 {
452  // create buffer to hold hex string:
453  int32_hf bufSize = 2 * digestSize + 1;
454  int8_hf *buf = new int8_hf[bufSize];
455  if (buf == NULL)
456  {
457  return std::string("");
458  }
459  buf[bufSize - 1] = 0;
460 
461  // hex representation of digest as string:
462  for (uint32_hf i = 0; i < digestSize; i++)
463  {
464  HFCORE_ENV->hf_sprintf(buf + i * 2, bufSize - (i * 2), "%02x", digest[i]);
465  }
466  std::string hexsum(buf, bufSize);
467  HF_SAFE_DELETE_ARR(buf);
468 
469  return hexsum;
470 }
unsigned int uint32_hf
A type definition for unsigned int.
Definition: HFDataTypes.h:354
double fp64_hf
A type definition for double.
Definition: HFDataTypes.h:364
static void aesDecrypt(const uint8_hf *key, AESKeySize keySize, const int8_hf *inData, int32_hf inDataSize, int8_hf **outData, int32_hf *outDataSize)
AES decrypt inData using key.
Definition: Crypto.cpp:68
HFCore::PFILE * p_fopen(const int8_hf *fileName, const int8_hf *access)
Open a file (within pak file or outside of it).
int int32_hf
A type definition for int.
Definition: HFDataTypes.h:349
static std::string sha224sum(const std::string &s)
Get the sha224 checksum hash as hex representation for input s.
Definition: Crypto.cpp:163
int32_hf p_fclose(HFCore::PFILE *file)
Closes and deletes a HFCore::PFILE.
Interface useful for AES encryption / decryption and for cryptographic hash checksums.
static std::string sha1sumForFile(const std::string &fileName)
Get the sha1 checksum hash as hex representation for file.
Definition: Crypto.cpp:157
size_t p_fread(void *ptr, int32_hf size, int32_hf count, HFCore::PFILE *file)
Reads an array of count elements, each one with a size of size bytes, from the stream and stores them...
#define HF_SAFE_DELETE_ARR(p)
Check if not NULL, delete array and set to NULL.
Definition: HFDataTypes.h:56
Interface for Storage and File IO stuff.
static std::string sha256sumForFile(const std::string &fileName)
Get the sha256 checksum hash as hex representation for file.
Definition: Crypto.cpp:201
#define NULL
Convenient define for 0.
Definition: HFDataTypes.h:42
static std::string md5sum(const std::string &s)
Get the md5 checksum hash as hex representation for input s.
Definition: Crypto.cpp:122
char int8_hf
A type definition for char.
Definition: HFDataTypes.h:329
static void aesEncrypt(const uint8_hf *key, AESKeySize keySize, const int8_hf *inData, int32_hf inDataSize, int8_hf **outData, int32_hf *outDataSize)
AES encrypt inData using key.
Definition: Crypto.cpp:43
int32_hf p_fseek(HFCore::PFILE *file, long offset, int32_hf origin)
Sets the position indicator associated with the stream to a new position.
HashType
Cryptographic hash types.
Definition: Crypto.h:72
static std::string sha512sumForFile(const std::string &fileName)
Get the sha512 checksum hash as hex representation for file.
Definition: Crypto.cpp:243
static std::string sha224sumForFile(const std::string &fileName)
Get the sha224 checksum hash as hex representation for file.
Definition: Crypto.cpp:179
static std::string md5sumForFile(const std::string &fileName)
Get the md5 checksum hash as hex representation for file.
Definition: Crypto.cpp:140
Definition: Actor.h:34
Singleton interface for platform specific things.
static std::string sha256sum(const std::string &s)
Get the sha256 checksum hash as hex representation for input s.
Definition: Crypto.cpp:185
Struct holding PakRecord, pointer to actual FILE and position.
Definition: PakInterface.h:146
static std::string sha512sum(const std::string &s)
Get the sha512 checksum hash as hex representation for input s.
Definition: Crypto.cpp:228
#define HFCORE_ENV
Get HFCore::Environment instance shortcut macro.
Definition: Environment.h:68
int32_hf p_ftell(HFCore::PFILE *file)
Returns the current value of the position indicator of the HFCore::PFILE stream.
unsigned char uint8_hf
A type definition for unsigned char.
Definition: HFDataTypes.h:334
static bool loadAESDecrypt(const uint8_hf *key, AESKeySize keySize, const int8_hf *filename, int8_hf **outData, int32_hf *outDataSize)
Open AES encrypted filename and decrypt it.
Definition: Crypto.cpp:94
static std::string sha384sum(const std::string &s)
Get the sha384 checksum hash as hex representation for input s.
Definition: Crypto.cpp:207
#define HFCORE_STORAGE
Get HFCore::Storage instance shortcut macro.
Definition: Environment.h:93
AESKeySize
AES keysize bits.
Definition: Crypto.h:62
Interface for accessing pak files created with tool hfpak.
static std::string sha1sum(const std::string &s)
Get the sha1 checksum hash as hex representation for input s.
Definition: Crypto.cpp:146
static std::string sha384sumForFile(const std::string &fileName)
Get the sha384 checksum hash as hex representation for file.
Definition: Crypto.cpp:222