osquery-1/osquery/core/hash.cpp

163 lines
4.6 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2014, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
*/
2015-01-20 22:05:01 +00:00
#include <iomanip>
#include <sstream>
#include <osquery/filesystem.h>
2015-01-20 18:49:58 +00:00
#include <osquery/hash.h>
2015-01-20 22:05:01 +00:00
#include <osquery/logger.h>
namespace osquery {
2015-01-20 18:49:58 +00:00
#ifdef __APPLE__
2015-12-07 05:42:47 +00:00
#import <CommonCrypto/CommonDigest.h>
#define __HASH_API(name) CC_##name
2015-01-20 18:49:58 +00:00
#else
2015-12-07 05:42:47 +00:00
#include <openssl/sha.h>
#include <openssl/md5.h>
#define __HASH_API(name) name
2015-12-07 05:42:47 +00:00
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
#define SHA1_CTX SHA_CTX
2015-01-20 18:49:58 +00:00
#endif
2015-11-05 18:10:11 +00:00
#define HASH_CHUNK_SIZE 4096
2015-01-20 22:05:01 +00:00
Hash::~Hash() {
if (ctx_ != nullptr) {
free(ctx_);
}
}
Hash::Hash(HashType algorithm) : algorithm_(algorithm) {
2015-01-20 22:05:01 +00:00
if (algorithm_ == HASH_TYPE_MD5) {
length_ = __HASH_API(MD5_DIGEST_LENGTH);
ctx_ = (__HASH_API(MD5_CTX)*)malloc(sizeof(__HASH_API(MD5_CTX)));
__HASH_API(MD5_Init)((__HASH_API(MD5_CTX)*)ctx_);
} else if (algorithm_ == HASH_TYPE_SHA1) {
length_ = __HASH_API(SHA1_DIGEST_LENGTH);
ctx_ = (__HASH_API(SHA1_CTX)*)malloc(sizeof(__HASH_API(SHA1_CTX)));
__HASH_API(SHA1_Init)((__HASH_API(SHA1_CTX)*)ctx_);
} else if (algorithm_ == HASH_TYPE_SHA256) {
length_ = __HASH_API(SHA256_DIGEST_LENGTH);
ctx_ = (__HASH_API(SHA256_CTX)*)malloc(sizeof(__HASH_API(SHA256_CTX)));
__HASH_API(SHA256_Init)((__HASH_API(SHA256_CTX)*)ctx_);
} else {
throw std::domain_error("Unknown hash function");
2015-01-16 20:03:23 +00:00
}
2015-01-20 22:05:01 +00:00
}
2015-01-20 22:52:07 +00:00
void Hash::update(const void* buffer, size_t size) {
2015-01-20 22:05:01 +00:00
if (algorithm_ == HASH_TYPE_MD5) {
__HASH_API(MD5_Update)((__HASH_API(MD5_CTX)*)ctx_, buffer, size);
} else if (algorithm_ == HASH_TYPE_SHA1) {
__HASH_API(SHA1_Update)((__HASH_API(SHA1_CTX)*)ctx_, buffer, size);
} else if (algorithm_ == HASH_TYPE_SHA256) {
__HASH_API(SHA256_Update)((__HASH_API(SHA256_CTX)*)ctx_, buffer, size);
2015-01-16 20:03:23 +00:00
}
2015-01-20 22:05:01 +00:00
}
2015-01-20 22:05:01 +00:00
std::string Hash::digest() {
unsigned char hash[length_];
memset(hash, 0, length_);
2015-01-20 22:05:01 +00:00
if (algorithm_ == HASH_TYPE_MD5) {
__HASH_API(MD5_Final)(hash, (__HASH_API(MD5_CTX)*)ctx_);
} else if (algorithm_ == HASH_TYPE_SHA1) {
__HASH_API(SHA1_Final)(hash, (__HASH_API(SHA1_CTX)*)ctx_);
} else if (algorithm_ == HASH_TYPE_SHA256) {
__HASH_API(SHA256_Final)(hash, (__HASH_API(SHA256_CTX)*)ctx_);
}
// The hash value is only relevant as a hex digest.
std::stringstream digest;
for (size_t i = 0; i < length_; i++) {
2015-01-20 22:05:01 +00:00
digest << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
}
return digest.str();
}
2015-12-07 05:42:47 +00:00
std::string hashFromBuffer(HashType hash_type,
const void* buffer,
size_t size) {
2015-01-20 22:05:01 +00:00
Hash hash(hash_type);
hash.update(buffer, size);
return hash.digest();
}
2015-12-11 08:36:16 +00:00
MultiHashes hashMultiFromFile(int mask, const std::string& path) {
// Perform a dry-run of a file read without filling in any content.
auto status = readFile(path);
if (!status.ok()) {
2015-12-11 08:36:16 +00:00
return MultiHashes();
}
2015-01-20 22:05:01 +00:00
2015-12-11 08:36:16 +00:00
std::map<HashType, std::shared_ptr<Hash> > hashes = {
{HASH_TYPE_MD5, std::make_shared<Hash>(HASH_TYPE_MD5)},
{HASH_TYPE_SHA1, std::make_shared<Hash>(HASH_TYPE_SHA1)},
{HASH_TYPE_SHA256, std::make_shared<Hash>(HASH_TYPE_SHA256)},
};
{
// Drop privileges to the user controlling the file.
auto dropper = DropPrivileges::get();
if (!dropper->dropToParent(path)) {
return MultiHashes();
}
// Use the canonicalized path returned from a successful readFile dry-run.
FILE* file = fopen(status.what().c_str(), "rb");
if (file == nullptr) {
VLOG(1) << "Cannot hash/open file: " << path;
return MultiHashes();
}
// Then call updates with read chunks.
size_t bytes_read = 0;
unsigned char buffer[HASH_CHUNK_SIZE];
while ((bytes_read = fread(buffer, 1, HASH_CHUNK_SIZE, file))) {
for (auto& hash : hashes) {
if (mask & hash.first) {
hash.second->update(buffer, bytes_read);
}
}
}
fclose(file);
}
2015-12-11 08:36:16 +00:00
MultiHashes mh;
mh.mask = mask;
if (mask & HASH_TYPE_MD5) {
mh.md5 = hashes.at(HASH_TYPE_MD5)->digest();
2015-01-16 20:03:23 +00:00
}
2015-12-11 08:36:16 +00:00
if (mask & HASH_TYPE_SHA1) {
mh.sha1 = hashes.at(HASH_TYPE_SHA1)->digest();
2015-01-16 20:03:23 +00:00
}
2015-12-11 08:36:16 +00:00
if (mask & HASH_TYPE_SHA256) {
mh.sha256 = hashes.at(HASH_TYPE_SHA256)->digest();
}
return mh;
}
2015-01-20 22:05:01 +00:00
2015-12-11 08:36:16 +00:00
std::string hashFromFile(HashType hash_type, const std::string& path) {
auto hashes = hashMultiFromFile(hash_type, path);
if (hash_type == HASH_TYPE_MD5) {
return hashes.md5;
} else if (hash_type == HASH_TYPE_SHA1) {
return hashes.sha1;
} else {
return hashes.sha256;
}
2015-01-20 22:05:01 +00:00
}
2015-01-20 22:52:07 +00:00
}