2015-01-16 01:16:05 +00:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2014, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
2015-01-20 23:36:53 +00:00
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
2015-01-16 01:16:05 +00:00
|
|
|
* 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>
|
|
|
|
|
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-01-20 23:36:53 +00:00
|
|
|
#import <CommonCrypto/CommonDigest.h>
|
|
|
|
#define __HASH_API(name) CC_##name
|
2015-01-20 18:49:58 +00:00
|
|
|
#else
|
2015-01-20 23:36:53 +00:00
|
|
|
#include <openssl/sha.h>
|
|
|
|
#include <openssl/md5.h>
|
|
|
|
#define __HASH_API(name) name
|
|
|
|
|
|
|
|
#define SHA1_DIGEST_LENGTH SHA_DIGEST_LENGTH
|
|
|
|
#define SHA1_CTX SHA_CTX
|
2015-01-20 18:49:58 +00:00
|
|
|
#endif
|
|
|
|
|
2015-01-20 22:05:01 +00:00
|
|
|
#define HASH_CHUNK_SIZE 1024
|
|
|
|
|
|
|
|
Hash::~Hash() {
|
|
|
|
if (ctx_ != nullptr) {
|
|
|
|
free(ctx_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-01-20 23:36:53 +00:00
|
|
|
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-16 01:16:05 +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-16 01:16:05 +00:00
|
|
|
|
2015-01-20 22:05:01 +00:00
|
|
|
std::string Hash::digest() {
|
|
|
|
unsigned char hash[length_];
|
|
|
|
|
|
|
|
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 (int i = 0; i < length_; i++) {
|
|
|
|
digest << std::hex << std::setw(2) << std::setfill('0') << (int)hash[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
return digest.str();
|
|
|
|
}
|
|
|
|
|
2015-01-20 22:52:07 +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();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string hashFromFile(HashType hash_type, const std::string& path) {
|
|
|
|
Hash hash(hash_type);
|
|
|
|
|
|
|
|
FILE* file = fopen(path.c_str(), "rb");
|
|
|
|
if (file == nullptr) {
|
|
|
|
VLOG(1) << "Cannot hash/open file " << path;
|
|
|
|
return "";
|
2015-01-16 20:03:23 +00:00
|
|
|
}
|
2015-01-20 22:05:01 +00:00
|
|
|
|
|
|
|
// 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))) {
|
|
|
|
hash.update(buffer, bytes_read);
|
2015-01-16 20:03:23 +00:00
|
|
|
}
|
2015-01-20 22:05:01 +00:00
|
|
|
|
|
|
|
fclose(file);
|
|
|
|
return hash.digest();
|
|
|
|
}
|
2015-01-20 22:52:07 +00:00
|
|
|
}
|