示例#1
0
NS_IMETHODIMP 
nsCryptoHash::Init(uint32_t algorithm)
{
  nsNSSShutDownPreventionLock locker;

  HASH_HashType hashType = (HASH_HashType)algorithm;
  if (mHashContext)
  {
    if ((!mInitialized) && (HASH_GetType(mHashContext) == hashType))
    {
      mInitialized = true;
      HASH_Begin(mHashContext);
      return NS_OK;
    }

    // Destroy current hash context if the type was different
    // or Finish method wasn't called.
    HASH_Destroy(mHashContext);
    mInitialized = false;
  }

  mHashContext = HASH_Create(hashType);
  if (!mHashContext)
    return NS_ERROR_INVALID_ARG;

  HASH_Begin(mHashContext);
  mInitialized = true;
  return NS_OK; 
}
示例#2
0
文件: nss_hmac_sha1.c 项目: SSSD/sssd
int sss_hmac_sha1(const unsigned char *key,
                  size_t key_len,
                  const unsigned char *in,
                  size_t in_len,
                  unsigned char *out)
{
    int ret;
    unsigned char ikey[HMAC_SHA1_BLOCKSIZE], okey[HMAC_SHA1_BLOCKSIZE];
    size_t i;
    HASHContext *sha1;
    unsigned char hash[SSS_SHA1_LENGTH];
    unsigned int res_len;

    ret = nspr_nss_init();
    if (ret != EOK) {
        return ret;
    }

    sha1 = HASH_Create(HASH_AlgSHA1);
    if (!sha1) {
        return ENOMEM;
    }

    if (key_len > HMAC_SHA1_BLOCKSIZE) {
        /* keys longer than blocksize are shortened */
        HASH_Begin(sha1);
        HASH_Update(sha1, key, key_len);
        HASH_End(sha1, ikey, &res_len, SSS_SHA1_LENGTH);
        memset(ikey + SSS_SHA1_LENGTH, 0, HMAC_SHA1_BLOCKSIZE - SSS_SHA1_LENGTH);
    } else {
        /* keys shorter than blocksize are zero-padded */
        memcpy(ikey, key, key_len);
        if (key_len < HMAC_SHA1_BLOCKSIZE) {
            memset(ikey + key_len, 0, HMAC_SHA1_BLOCKSIZE - key_len);
        }
    }

    /* HMAC(key, msg) = HASH(key XOR opad, HASH(key XOR ipad, msg)) */
    for (i = 0; i < HMAC_SHA1_BLOCKSIZE; i++) {
        okey[i] = ikey[i] ^ 0x5c;
        ikey[i] ^= 0x36;
    }

    HASH_Begin(sha1);
    HASH_Update(sha1, ikey, HMAC_SHA1_BLOCKSIZE);
    HASH_Update(sha1, in, in_len);
    HASH_End(sha1, hash, &res_len, SSS_SHA1_LENGTH);

    HASH_Begin(sha1);
    HASH_Update(sha1, okey, HMAC_SHA1_BLOCKSIZE);
    HASH_Update(sha1, hash, SSS_SHA1_LENGTH);
    HASH_End(sha1, out, &res_len, SSS_SHA1_LENGTH);

    HASH_Destroy(sha1);

    return EOK;
}
示例#3
0
int
sha_response(int fd, fence_auth_type_t auth, void *key,
             size_t key_len, int timeout)
{
    fd_set rfds;
    struct timeval tv;
    unsigned char challenge[MAX_HASH_LENGTH];
    unsigned char hash[MAX_HASH_LENGTH];
    HASHContext *h;
    HASH_HashType ht;
    unsigned int rlen;

    FD_ZERO(&rfds);
    FD_SET(fd, &rfds);
    tv.tv_sec = timeout;
    tv.tv_usec = 0;
    if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
        perror("select");
        return 0;
    }

    if (read(fd, challenge, sizeof(challenge)) < 0) {
        perror("read");
        return 0;
    }

    switch(auth) {
    case AUTH_SHA1:
        ht = HASH_AlgSHA1;
        break;
    case AUTH_SHA256:
        ht = HASH_AlgSHA256;
        break;
    case AUTH_SHA512:
        ht = HASH_AlgSHA512;
        break;
    default:
        dbg_printf(3, "%s: no-op (AUTH_NONE)\n", __FUNCTION__);
        return 0;
    }

    memset(hash, 0, sizeof(hash));
    h = HASH_Create(ht); /* */
    if (!h)
        return 0;

    HASH_Begin(h);
    HASH_Update(h, key, key_len);
    HASH_Update(h, challenge, sizeof(challenge));
    HASH_End(h, hash, &rlen, sizeof(hash));
    HASH_Destroy(h);

    if (write(fd, hash, sizeof(hash)) < sizeof(hash)) {
        perror("read");
        return 0;
    }

    return 1;
}
示例#4
0
static int
sha_verify(fence_req_t *req, void *key, size_t key_len)
{
	unsigned char hash[SHA512_LENGTH];
	unsigned char pkt_hash[SHA512_LENGTH];
	HASHContext *h = NULL;
	HASH_HashType ht;
	unsigned int rlen;
	int ret;

	switch(req->hashtype) {
		case HASH_SHA1:
			ht = HASH_AlgSHA1;
			break;
		case HASH_SHA256:
			ht = HASH_AlgSHA256;
			break;
		case HASH_SHA512:
			ht = HASH_AlgSHA512;
			break;
		default:
			dbg_printf(3, "%s: no-op (HASH_NONE)\n", __FUNCTION__);
			return 0;
	}

	if (!key || !key_len) {
		dbg_printf(3, "%s: Hashing requested when we have no key data\n",
			   __FUNCTION__);
		return 0;
	}

	memset(hash, 0, sizeof(hash));
	h = HASH_Create(ht);
	if (!h)
		return 0;

	memcpy(pkt_hash, req->hash, sizeof(pkt_hash));
	memset(req->hash, 0, sizeof(req->hash));

	HASH_Begin(h);
	HASH_Update(h, key, key_len);
	HASH_Update(h, (void *)req, sizeof(*req));
	HASH_End(h, hash, &rlen, sizeof(hash));
	HASH_Destroy(h);

	memcpy(req->hash, pkt_hash, sizeof(req->hash));

	ret = !memcmp(hash, pkt_hash, sizeof(hash));
	if (!ret) {
		printf("Hash mismatch:\nPKT = ");
		print_hash(pkt_hash, sizeof(pkt_hash));
		printf("\nEXP = ");
		print_hash(hash, sizeof(hash));
		printf("\n");
	}

	return ret;
}
示例#5
0
static void
sha_sign(fence_req_t *req, void *key, size_t key_len)
{
	unsigned char hash[SHA512_LENGTH];
	HASHContext *h;
	HASH_HashType ht;
	unsigned int rlen;
	int devrand;

	switch(req->hashtype) {
		case HASH_SHA1:
			ht = HASH_AlgSHA1;
			break;
		case HASH_SHA256:
			ht = HASH_AlgSHA256;
			break;
		case HASH_SHA512:
			ht = HASH_AlgSHA512;
			break;
		default:
			return;
	}

	dbg_printf(4, "Opening /dev/urandom\n");
	devrand = open("/dev/urandom", O_RDONLY);
	if (devrand >= 0) {
		if (read(devrand, req->random, sizeof(req->random)) < 0) {
			perror("read /dev/urandom");
		}
		close(devrand);
	}

	memset(hash, 0, sizeof(hash));
	h = HASH_Create(ht);
	if (!h)
		return;

	HASH_Begin(h);
	HASH_Update(h, key, key_len);
	HASH_Update(h, (void *)req, sizeof(*req));
	HASH_End(h, hash, &rlen, sizeof(hash));
	HASH_Destroy(h);

	memcpy(req->hash, hash, sizeof(req->hash));
}
示例#6
0
文件: conn.cpp 项目: Peppar/mist-conn
std::string
hash(const std::uint8_t *begin, const std::uint8_t *end)
{
  SECOidTag hashOIDTag = SEC_OID_SHA256;
  std::array<std::uint8_t, 64> digest;
  unsigned int len;
  
  HASH_HashType hashType = HASH_GetHashTypeByOidTag(hashOIDTag);
  
  auto ctx = to_unique(HASH_Create(hashType));
  HASH_Begin(ctx.get());
  HASH_Update(ctx.get(),
    reinterpret_cast<const unsigned char *>(begin), end - begin);
  HASH_End(ctx.get(),
    reinterpret_cast<unsigned char *>(digest.data()), &len, digest.size());
  
  return std::string(reinterpret_cast<const char *>(digest.data()), len);
}
static void TransformToSha256(InspectionBuffer *buffer)
{
    const uint8_t *input = buffer->inspect;
    const uint32_t input_len = buffer->inspect_len;
    uint8_t output[SHA256_LENGTH];

    //PrintRawDataFp(stdout, input, input_len);

    HASHContext *sha256_ctx = HASH_Create(HASH_AlgSHA256);
    if (sha256_ctx) {
        HASH_Begin(sha256_ctx);
        HASH_Update(sha256_ctx, input, input_len);
        unsigned int len = 0;
        HASH_End(sha256_ctx, output, &len, sizeof(output));
        HASH_Destroy(sha256_ctx);

        InspectionBufferCopy(buffer, output, sizeof(output));
    }
}
示例#8
0
DIGEST_CTX
rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
{
    HASH_HashType type = getHashType(hashalgo);
    HASHContext *hashctx = NULL;
    DIGEST_CTX ctx = NULL;

    if (type == HASH_AlgNULL || rpmInitCrypto() < 0)
	goto exit;

    if ((hashctx = HASH_Create(type)) != NULL) {
	ctx = xcalloc(1, sizeof(*ctx));
	ctx->flags = flags;
	ctx->algo = hashalgo;
	ctx->hashctx = hashctx;
    	HASH_Begin(ctx->hashctx);
    }
    
DPRINTF((stderr, "*** Init(%x) ctx %p hashctx %p\n", flags, ctx, ctx->hashctx));
exit:
    return ctx;
}
示例#9
0
SECStatus
HASH_HashBuf(HASH_HashType type,
             unsigned char *dest,
             const unsigned char *src,
             PRUint32 src_len)
{
    HASHContext *cx;
    unsigned int part;

    if ((type < HASH_AlgNULL) || (type >= HASH_AlgTOTAL)) {
        return (SECFailure);
    }

    cx = HASH_Create(type);
    if (cx == NULL) {
        return (SECFailure);
    }
    HASH_Begin(cx);
    HASH_Update(cx, src, src_len);
    HASH_End(cx, dest, &part, HASH_ResultLenContext(cx));
    HASH_Destroy(cx);

    return (SECSuccess);
}
示例#10
0
static int sha512_crypt_r(const char *key,
                          const char *salt,
                          char *buffer, size_t buflen)
{
    unsigned char temp_result[64] __attribute__((__aligned__(ALIGN64)));
    unsigned char alt_result[64] __attribute__((__aligned__(ALIGN64)));
    size_t rounds = ROUNDS_DEFAULT;
    bool rounds_custom = false;
    HASHContext *alt_ctx = NULL;
    HASHContext *ctx = NULL;
    size_t salt_len;
    size_t key_len;
    size_t cnt;
    char *copied_salt = NULL;
    char *copied_key = NULL;
    char *p_bytes = NULL;
    char *s_bytes = NULL;
    int p1, p2, p3, pt, n;
    unsigned int part;
    char *cp, *tmp;
    int ret;

    /* Find beginning of salt string. The prefix should normally always be
     * present. Just in case it is not. */
    if (strncmp(salt, sha512_salt_prefix, SALT_PREF_SIZE) == 0) {
        /* Skip salt prefix.  */
        salt += SALT_PREF_SIZE;
    }

    if (strncmp(salt, sha512_rounds_prefix, ROUNDS_SIZE) == 0) {
        unsigned long int srounds;
        const char *num;
        char *endp;

        num = salt + ROUNDS_SIZE;
        srounds = strtoul(num, &endp, 10);
        if (*endp == '$') {
            salt = endp + 1;
            if (srounds < ROUNDS_MIN) srounds = ROUNDS_MIN;
            if (srounds > ROUNDS_MAX) srounds = ROUNDS_MAX;
            rounds = srounds;
            rounds_custom = true;
        }
    }

    salt_len = MIN(strcspn(salt, "$"), SALT_LEN_MAX);
    key_len = strlen(key);

    if ((PTR_2_INT(key) % ALIGN64) != 0) {
        tmp = (char *)alloca(key_len + ALIGN64);
        key = copied_key = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, key, key_len);
    }

    if (PTR_2_INT(salt) % ALIGN64 != 0) {
        tmp = (char *)alloca(salt_len + ALIGN64);
        salt = copied_salt = memcpy(tmp + ALIGN64 - PTR_2_INT(tmp) % ALIGN64, salt, salt_len);
    }

    ret = nspr_nss_init();
    if (ret != EOK) {
        ret = EIO;
        goto done;
    }

    ctx = HASH_Create(HASH_AlgSHA512);
    if (!ctx) {
        ret = EIO;
        goto done;
    }

    alt_ctx = HASH_Create(HASH_AlgSHA512);
    if (!alt_ctx) {
        ret = EIO;
        goto done;
    }

    /* Prepare for the real work.  */
    HASH_Begin(ctx);

    /* Add the key string.  */
    HASH_Update(ctx, (const unsigned char *)key, key_len);

    /* The last part is the salt string. This must be at most 16
     * characters and it ends at the first `$' character (for
     * compatibility with existing implementations). */
    HASH_Update(ctx, (const unsigned char *)salt, salt_len);


    /* Compute alternate SHA512 sum with input KEY, SALT, and KEY.
     * The final result will be added to the first context. */
    HASH_Begin(alt_ctx);

    /* Add key. */
    HASH_Update(alt_ctx, (const unsigned char *)key, key_len);

    /* Add salt. */
    HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);

    /* Add key again. */
    HASH_Update(alt_ctx, (const unsigned char *)key, key_len);

    /* Now get result of this (64 bytes) and add it to the other context. */
    HASH_End(alt_ctx, alt_result, &part, HASH_ResultLenContext(alt_ctx));

    /* Add for any character in the key one byte of the alternate sum. */
    for (cnt = key_len; cnt > 64; cnt -= 64) {
        HASH_Update(ctx, alt_result, 64);
    }
    HASH_Update(ctx, alt_result, cnt);

    /* Take the binary representation of the length of the key and for every
     * 1 add the alternate sum, for every 0 the key. */
    for (cnt = key_len; cnt > 0; cnt >>= 1) {
        if ((cnt & 1) != 0) {
            HASH_Update(ctx, alt_result, 64);
        } else {
            HASH_Update(ctx, (const unsigned char *)key, key_len);
        }
    }

    /* Create intermediate result. */
    HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));

    /* Start computation of P byte sequence. */
    HASH_Begin(alt_ctx);

    /* For every character in the password add the entire password. */
    for (cnt = 0; cnt < key_len; cnt++) {
        HASH_Update(alt_ctx, (const unsigned char *)key, key_len);
    }

    /* Finish the digest. */
    HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));

    /* Create byte sequence P. */
    cp = p_bytes = alloca(key_len);
    for (cnt = key_len; cnt >= 64; cnt -= 64) {
        cp = mempcpy(cp, temp_result, 64);
    }
    memcpy(cp, temp_result, cnt);

    /* Start computation of S byte sequence. */
    HASH_Begin(alt_ctx);

    /* For every character in the password add the entire salt. */
    for (cnt = 0; cnt < 16 + alt_result[0]; cnt++) {
        HASH_Update(alt_ctx, (const unsigned char *)salt, salt_len);
    }

    /* Finish the digest. */
    HASH_End(alt_ctx, temp_result, &part, HASH_ResultLenContext(alt_ctx));

    /* Create byte sequence S.  */
    cp = s_bytes = alloca(salt_len);
    for (cnt = salt_len; cnt >= 64; cnt -= 64) {
        cp = mempcpy(cp, temp_result, 64);
    }
    memcpy(cp, temp_result, cnt);

    /* Repeatedly run the collected hash value through SHA512 to burn CPU cycles. */
    for (cnt = 0; cnt < rounds; cnt++) {

        HASH_Begin(ctx);

        /* Add key or last result. */
        if ((cnt & 1) != 0) {
            HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
        } else {
            HASH_Update(ctx, alt_result, 64);
        }

        /* Add salt for numbers not divisible by 3. */
        if (cnt % 3 != 0) {
            HASH_Update(ctx, (const unsigned char *)s_bytes, salt_len);
        }

        /* Add key for numbers not divisible by 7. */
        if (cnt % 7 != 0) {
            HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
        }

        /* Add key or last result. */
        if ((cnt & 1) != 0) {
            HASH_Update(ctx, alt_result, 64);
        } else {
            HASH_Update(ctx, (const unsigned char *)p_bytes, key_len);
        }

        /* Create intermediate result. */
        HASH_End(ctx, alt_result, &part, HASH_ResultLenContext(ctx));
    }

    /* Now we can construct the result string.
     * It consists of three parts. */
    if (buflen <= SALT_PREF_SIZE) {
        ret = ERANGE;
        goto done;
    }

    cp = __stpncpy(buffer, sha512_salt_prefix, SALT_PREF_SIZE);
    buflen -= SALT_PREF_SIZE;

    if (rounds_custom) {
        n = snprintf(cp, buflen, "%s%zu$",
                     sha512_rounds_prefix, rounds);
        if (n < 0 || n >= buflen) {
            ret = ERANGE;
            goto done;
        }
        cp += n;
        buflen -= n;
    }

    if (buflen <= salt_len + 1) {
        ret = ERANGE;
        goto done;
    }
    cp = __stpncpy(cp, salt, salt_len);
    *cp++ = '$';
    buflen -= salt_len + 1;

    /* fuzzyfill the base 64 string */
    p1 = 0;
    p2 = 21;
    p3 = 42;
    for (n = 0; n < 21; n++) {
        b64_from_24bit(&cp, &buflen, 4, alt_result[p1], alt_result[p2], alt_result[p3]);
        if (buflen == 0) {
            ret = ERANGE;
            goto done;
        }
        pt = p1;
        p1 = p2 + 1;
        p2 = p3 + 1;
        p3 = pt + 1;
    }
    /* 64th and last byte */
    b64_from_24bit(&cp, &buflen, 2, 0, 0, alt_result[p3]);
    if (buflen == 0) {
        ret = ERANGE;
        goto done;
    }

    *cp = '\0';
    ret = EOK;

done:
    /* Clear the buffer for the intermediate result so that people attaching
     * to processes or reading core dumps cannot get any information. We do it
     * in this way to clear correct_words[] inside the SHA512 implementation
     * as well.  */
    if (ctx) HASH_Destroy(ctx);
    if (alt_ctx) HASH_Destroy(alt_ctx);
    if (p_bytes) memset(p_bytes, '\0', key_len);
    if (s_bytes) memset(s_bytes, '\0', salt_len);
    if (copied_key) memset(copied_key, '\0', key_len);
    if (copied_salt) memset(copied_salt, '\0', salt_len);
    memset(temp_result, '\0', sizeof(temp_result));

    return ret;
}
示例#11
0
int
sha_challenge(int fd, fence_auth_type_t auth, void *key,
	      size_t key_len, int timeout)
{
	fd_set rfds;
	struct timeval tv;
	unsigned char hash[MAX_HASH_LENGTH];
	unsigned char challenge[MAX_HASH_LENGTH];
	unsigned char response[MAX_HASH_LENGTH];
	int devrand;
	int ret;
	HASHContext *h;
	HASH_HashType ht;
	unsigned int rlen;

	devrand = open("/dev/urandom", O_RDONLY);
	if (devrand < 0) {
		perror("open /dev/urandom");
		return 0;
	}
	if (read(devrand, challenge, sizeof(challenge)) < 0) {
		perror("read /dev/urandom");
		close(devrand);
		return 0;
	}
	close(devrand);

	if (write(fd, challenge, sizeof(challenge)) < 0) {
		perror("write");
		return 0;
	}

	switch(auth) {
		case HASH_SHA1:
			ht = HASH_AlgSHA1;
			break;
		case HASH_SHA256:
			ht = HASH_AlgSHA256;
			break;
		case HASH_SHA512:
			ht = HASH_AlgSHA512;
			break;
		default:
			return 0;
	}

	memset(hash, 0, sizeof(hash));
	h = HASH_Create(ht);
	if (!h)
		return 0;

	HASH_Begin(h);
	HASH_Update(h, key, key_len);
	HASH_Update(h, challenge, sizeof(challenge));
	HASH_End(h, hash, &rlen, sizeof(hash));
	HASH_Destroy(h);

	memset(response, 0, sizeof(response));

	FD_ZERO(&rfds);
	FD_SET(fd, &rfds);
	tv.tv_sec = timeout;
	tv.tv_usec = 0;
	if (select(fd + 1, &rfds, NULL, NULL, &tv) <= 0) {
		perror("select");
		return 0;
	}

	ret = read(fd, response, sizeof(response));
	if (ret < 0) {
		perror("read");
		return 0;
	} else if (ret < sizeof(response)) {
		fprintf(stderr,
			"read data from socket is too short(actual: %d, expected: %lu)\n",
			ret, sizeof(response));
		return 0;
	}

	ret = !memcmp(response, hash, sizeof(response));
	if (!ret) {
		printf("Hash mismatch:\nC = ");
		print_hash(challenge, sizeof(challenge));
		printf("\nH = ");
		print_hash(hash, sizeof(hash));
		printf("\nR = ");
		print_hash(response, sizeof(response));
		printf("\n");
	}

	return ret;
}
示例#12
0
static string ComputeDumpHash() {
#ifdef XP_LINUX
  // On Linux we rely on the system-provided libcurl which uses nss so we have
  // to also use the system-provided nss instead of the ones we have bundled.
  const char* libnssNames[] = {
    "libnss3.so",
#ifndef HAVE_64BIT_BUILD
    // 32-bit versions on 64-bit hosts
    "/usr/lib32/libnss3.so",
#endif
  };
  void* lib = nullptr;

  for (const char* libname : libnssNames) {
    lib = dlopen(libname, RTLD_NOW);

    if (lib) {
      break;
    }
  }

  if (!lib) {
    return "";
  }

  SECStatus (*NSS_Initialize)(const char*, const char*, const char*,
                              const char*, PRUint32);
  HASHContext* (*HASH_Create)(HASH_HashType);
  void (*HASH_Destroy)(HASHContext*);
  void (*HASH_Begin)(HASHContext*);
  void (*HASH_Update)(HASHContext*, const unsigned char*, unsigned int);
  void (*HASH_End)(HASHContext*, unsigned char*, unsigned int*, unsigned int);

  *(void**) (&NSS_Initialize) = dlsym(lib, "NSS_Initialize");
  *(void**) (&HASH_Create) = dlsym(lib, "HASH_Create");
  *(void**) (&HASH_Destroy) = dlsym(lib, "HASH_Destroy");
  *(void**) (&HASH_Begin) = dlsym(lib, "HASH_Begin");
  *(void**) (&HASH_Update) = dlsym(lib, "HASH_Update");
  *(void**) (&HASH_End) = dlsym(lib, "HASH_End");

  if (!HASH_Create || !HASH_Destroy || !HASH_Begin || !HASH_Update ||
      !HASH_End) {
    return "";
  }
#endif
  // Minimal NSS initialization so we can use the hash functions
  const PRUint32 kNssFlags = NSS_INIT_READONLY | NSS_INIT_NOROOTINIT |
                             NSS_INIT_NOMODDB | NSS_INIT_NOCERTDB;
  if (NSS_Initialize(nullptr, "", "", "", kNssFlags) != SECSuccess) {
    return "";
  }

  HASHContext* hashContext = HASH_Create(HASH_AlgSHA256);

  if (!hashContext) {
    return "";
  }

  HASH_Begin(hashContext);

  ifstream* f = UIOpenRead(gReporterDumpFile, /* binary */ true);
  bool error = false;

  // Read the minidump contents
  if (f->is_open()) {
    uint8_t buff[4096];

    do {
      f->read((char*) buff, sizeof(buff));

      if (f->bad()) {
        error = true;
        break;
      }

      HASH_Update(hashContext, buff, f->gcount());
    } while (!f->eof());

    f->close();
  } else {
    error = true;
  }

  delete f;

  // Finalize the hash computation
  uint8_t result[SHA256_LENGTH];
  uint32_t resultLen = 0;

  HASH_End(hashContext, result, &resultLen, SHA256_LENGTH);

  if (resultLen != SHA256_LENGTH) {
    error = true;
  }

  HASH_Destroy(hashContext);

  if (!error) {
    ostringstream hash;

    for (size_t i = 0; i < SHA256_LENGTH; i++) {
      hash << std::setw(2) << std::setfill('0') << std::hex
           << static_cast<unsigned int>(result[i]);
    }

    return hash.str();
  } else {
    return ""; // If we encountered an error, return an empty hash
  }
}