mirror of
https://github.com/zeek/zeek.git
synced 2025-10-02 06:38:20 +00:00
1075 lines
29 KiB
C++
1075 lines
29 KiB
C++
// See the file "COPYING" in the main distribution directory for copyright.
|
|
|
|
// When using OpenSSL 3, we use deprecated APIs for MD5, SHA1 and SHA256. The reason is that, as of
|
|
// OpenSSL 3.0, there is no API anymore that lets you store the internal state of hashing functions.
|
|
// For more information, see https://github.com/zeek/zeek/issues/1379 and
|
|
// https://github.com/openssl/openssl/issues/14222 Since I don't feel like getting warnings every
|
|
// time we compile this file - let's silence them.
|
|
|
|
#define OPENSSL_SUPPRESS_DEPRECATED
|
|
|
|
#include "zeek/OpaqueVal.h"
|
|
|
|
#include <broker/data.hh>
|
|
#include <broker/error.hh>
|
|
#include <openssl/evp.h>
|
|
#include <openssl/md5.h>
|
|
#include <openssl/sha.h>
|
|
#include <memory>
|
|
|
|
#include "zeek/CompHash.h"
|
|
#include "zeek/Desc.h"
|
|
#include "zeek/Reporter.h"
|
|
#include "zeek/Scope.h"
|
|
#include "zeek/Var.h"
|
|
#include "zeek/broker/Data.h"
|
|
#include "zeek/digest.h"
|
|
#include "zeek/probabilistic/BloomFilter.h"
|
|
#include "zeek/probabilistic/CardinalityCounter.h"
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x10100000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
inline void* EVP_MD_CTX_md_data(const EVP_MD_CTX* ctx) { return ctx->md_data; }
|
|
#endif
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
#include <openssl/md5.h>
|
|
#endif
|
|
|
|
namespace zeek {
|
|
|
|
// Helper to retrieve a broker count out of a list at a specified index, and
|
|
// casted to the expected destination type.
|
|
template<typename V, typename D>
|
|
bool get_vector_idx_if_count(V& v, size_t i, D* dst) {
|
|
if ( i >= v.Size() || ! v[i].IsCount() )
|
|
return false;
|
|
|
|
*dst = static_cast<D>(v[i].ToCount());
|
|
return true;
|
|
}
|
|
|
|
OpaqueMgr* OpaqueMgr::mgr() {
|
|
static OpaqueMgr mgr;
|
|
return &mgr;
|
|
}
|
|
|
|
OpaqueVal::OpaqueVal(OpaqueTypePtr t) : Val(std::move(t)) {}
|
|
|
|
const std::string& OpaqueMgr::TypeID(const OpaqueVal* v) const {
|
|
auto x = _types.find(v->OpaqueName());
|
|
|
|
if ( x == _types.end() )
|
|
reporter->InternalError("OpaqueMgr::TypeID: opaque type %s not registered", v->OpaqueName());
|
|
|
|
return x->first;
|
|
}
|
|
|
|
OpaqueValPtr OpaqueMgr::Instantiate(const std::string& id) const {
|
|
auto x = _types.find(id);
|
|
return x != _types.end() ? (*x->second)() : nullptr;
|
|
}
|
|
|
|
std::optional<BrokerData> OpaqueVal::SerializeData() const {
|
|
auto type = OpaqueMgr::mgr()->TypeID(this);
|
|
|
|
auto d = DoSerializeData();
|
|
if ( ! d )
|
|
return std::nullopt;
|
|
|
|
BrokerListBuilder builder;
|
|
builder.Add(std::move(type));
|
|
builder.Add(std::move(*d));
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
OpaqueValPtr OpaqueVal::UnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return nullptr;
|
|
|
|
return UnserializeData(data.ToList());
|
|
}
|
|
|
|
OpaqueValPtr OpaqueVal::UnserializeData(BrokerListView v) {
|
|
if ( v.Size() != 2 || ! v[0].IsString() )
|
|
return nullptr;
|
|
|
|
auto type = v[0].ToString();
|
|
|
|
auto val = OpaqueMgr::mgr()->Instantiate(std::string{type});
|
|
if ( ! val )
|
|
return nullptr;
|
|
|
|
if ( ! val->DoUnserializeData(v[1]) )
|
|
return nullptr;
|
|
|
|
return val;
|
|
}
|
|
|
|
std::optional<BrokerData> OpaqueVal::DoSerializeData() const { return std::nullopt; }
|
|
|
|
bool OpaqueVal::DoUnserializeData(BrokerDataView data) { return false; }
|
|
|
|
std::optional<BrokerData> OpaqueVal::SerializeType(const TypePtr& t) {
|
|
if ( t->InternalType() == TYPE_INTERNAL_ERROR )
|
|
return std::nullopt;
|
|
|
|
BrokerListBuilder builder;
|
|
|
|
if ( t->InternalType() == TYPE_INTERNAL_OTHER ) {
|
|
// Serialize by name.
|
|
assert(! t->GetName().empty());
|
|
builder.Add(true);
|
|
builder.Add(t->GetName());
|
|
}
|
|
else {
|
|
// A base type.
|
|
builder.Add(false);
|
|
builder.Add(static_cast<uint64_t>(t->Tag()));
|
|
}
|
|
|
|
return {std::move(builder).Build()};
|
|
}
|
|
|
|
TypePtr OpaqueVal::UnserializeType(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return nullptr;
|
|
|
|
auto v = data.ToList();
|
|
|
|
if ( v.Size() != 2 || ! v[0].IsBool() )
|
|
return nullptr;
|
|
|
|
if ( v[0].ToBool() ) // Get by name?
|
|
{
|
|
if ( ! v[1].IsString() )
|
|
return nullptr;
|
|
|
|
const auto& id = detail::global_scope()->Find(v[1].ToString());
|
|
if ( ! id )
|
|
return nullptr;
|
|
|
|
if ( ! id->IsType() )
|
|
return nullptr;
|
|
|
|
return id->GetType();
|
|
}
|
|
|
|
if ( ! v[1].IsCount() )
|
|
return nullptr;
|
|
|
|
return base_type(static_cast<TypeTag>(v[1].ToCount()));
|
|
}
|
|
|
|
ValPtr OpaqueVal::DoClone(CloneState* state) {
|
|
auto d = OpaqueVal::SerializeData();
|
|
if ( ! d )
|
|
return nullptr;
|
|
|
|
auto rval = OpaqueVal::UnserializeData(d->AsView());
|
|
return state->NewClone(this, std::move(rval));
|
|
}
|
|
|
|
void OpaqueVal::ValDescribe(ODesc* d) const { d->Add(util::fmt("<opaque of %s>", OpaqueName())); }
|
|
|
|
void OpaqueVal::ValDescribeReST(ODesc* d) const { d->Add(util::fmt("<opaque of %s>", OpaqueName())); }
|
|
|
|
bool HashVal::IsValid() const { return valid; }
|
|
|
|
bool HashVal::Init() {
|
|
if ( valid )
|
|
return false;
|
|
|
|
valid = DoInit();
|
|
return valid;
|
|
}
|
|
|
|
StringValPtr HashVal::Get() {
|
|
if ( ! valid )
|
|
return val_mgr->EmptyString();
|
|
|
|
auto result = DoGet();
|
|
valid = false;
|
|
return result;
|
|
}
|
|
|
|
bool HashVal::Feed(const void* data, size_t size) {
|
|
if ( valid )
|
|
return DoFeed(data, size);
|
|
|
|
Error("attempt to update an invalid opaque hash value");
|
|
return false;
|
|
}
|
|
|
|
bool HashVal::DoInit() {
|
|
assert(! "missing implementation of DoInit()");
|
|
return false;
|
|
}
|
|
|
|
bool HashVal::DoFeed(const void*, size_t) {
|
|
assert(! "missing implementation of DoFeed()");
|
|
return false;
|
|
}
|
|
|
|
StringValPtr HashVal::DoGet() {
|
|
assert(! "missing implementation of DoGet()");
|
|
return val_mgr->EmptyString();
|
|
}
|
|
|
|
HashVal::HashVal(OpaqueTypePtr t) : OpaqueVal(std::move(t)) { valid = false; }
|
|
|
|
namespace {
|
|
|
|
constexpr size_t MD5VAL_STATE_SIZE = sizeof(MD5_CTX);
|
|
|
|
constexpr size_t SHA1VAL_STATE_SIZE = sizeof(SHA_CTX);
|
|
|
|
constexpr size_t SHA256VAL_STATE_SIZE = sizeof(SHA256_CTX);
|
|
|
|
#if ( OPENSSL_VERSION_NUMBER < 0x30000000L ) || defined(LIBRESSL_VERSION_NUMBER)
|
|
|
|
// -- MD5
|
|
|
|
auto* to_native_ptr(MD5Val::StatePtr ptr) { return reinterpret_cast<EVP_MD_CTX*>(ptr); }
|
|
|
|
auto* to_digest_ptr(MD5Val::StatePtr ptr) { return reinterpret_cast<detail::HashDigestState*>(ptr); }
|
|
|
|
void do_init(MD5Val::StatePtr& ptr) { ptr = reinterpret_cast<MD5Val::StatePtr>(detail::hash_init(detail::Hash_MD5)); }
|
|
|
|
void do_clone(MD5Val::StatePtr out, MD5Val::StatePtr in) { hash_copy(to_digest_ptr(out), to_digest_ptr(in)); }
|
|
|
|
void do_feed(MD5Val::StatePtr ptr, const void* data, size_t size) {
|
|
detail::hash_update(to_digest_ptr(ptr), data, size);
|
|
}
|
|
|
|
void do_get(MD5Val::StatePtr ptr, u_char* digest) { detail::hash_final_no_free(to_digest_ptr(ptr), digest); }
|
|
|
|
std::string do_serialize(MD5Val::StatePtr ptr) {
|
|
auto* md = reinterpret_cast<MD5_CTX*>(EVP_MD_CTX_md_data(to_native_ptr(ptr)));
|
|
return {reinterpret_cast<const char*>(md), sizeof(MD5_CTX)};
|
|
}
|
|
|
|
void do_unserialize(MD5Val::StatePtr ptr, const char* bytes, size_t len) {
|
|
auto* md = reinterpret_cast<MD5_CTX*>(EVP_MD_CTX_md_data(to_native_ptr(ptr)));
|
|
memcpy(md, bytes, len);
|
|
}
|
|
|
|
void do_destroy(MD5Val::StatePtr ptr) { hash_state_free(to_digest_ptr(ptr)); }
|
|
|
|
// -- SHA1
|
|
|
|
auto* to_native_ptr(SHA1Val::StatePtr ptr) { return reinterpret_cast<EVP_MD_CTX*>(ptr); }
|
|
|
|
auto* to_digest_ptr(SHA1Val::StatePtr ptr) { return reinterpret_cast<detail::HashDigestState*>(ptr); }
|
|
|
|
void do_init(SHA1Val::StatePtr& ptr) {
|
|
ptr = reinterpret_cast<SHA1Val::StatePtr>(detail::hash_init(detail::Hash_SHA1));
|
|
}
|
|
|
|
void do_clone(SHA1Val::StatePtr out, SHA1Val::StatePtr in) { detail::hash_copy(to_digest_ptr(out), to_digest_ptr(in)); }
|
|
|
|
void do_feed(SHA1Val::StatePtr ptr, const void* data, size_t size) {
|
|
detail::hash_update(to_digest_ptr(ptr), data, size);
|
|
}
|
|
|
|
void do_get(SHA1Val::StatePtr ptr, u_char* digest) { detail::hash_final_no_free(to_digest_ptr(ptr), digest); }
|
|
|
|
std::string do_serialize(SHA1Val::StatePtr ptr) {
|
|
auto* md = reinterpret_cast<SHA_CTX*>(EVP_MD_CTX_md_data(to_native_ptr(ptr)));
|
|
return {reinterpret_cast<const char*>(md), sizeof(SHA_CTX)};
|
|
}
|
|
|
|
void do_unserialize(SHA1Val::StatePtr ptr, const char* bytes, size_t len) {
|
|
auto* md = reinterpret_cast<SHA_CTX*>(EVP_MD_CTX_md_data(to_native_ptr(ptr)));
|
|
memcpy(md, bytes, len);
|
|
}
|
|
|
|
void do_destroy(SHA1Val::StatePtr ptr) { hash_state_free(to_digest_ptr(ptr)); }
|
|
|
|
// -- SHA256
|
|
|
|
auto* to_native_ptr(SHA256Val::StatePtr ptr) { return reinterpret_cast<EVP_MD_CTX*>(ptr); }
|
|
|
|
auto* to_digest_ptr(SHA256Val::StatePtr ptr) { return reinterpret_cast<detail::HashDigestState*>(ptr); }
|
|
|
|
void do_init(SHA256Val::StatePtr& ptr) {
|
|
ptr = reinterpret_cast<SHA256Val::StatePtr>(detail::hash_init(detail::Hash_SHA256));
|
|
}
|
|
|
|
void do_clone(SHA256Val::StatePtr out, SHA256Val::StatePtr in) {
|
|
detail::hash_copy(to_digest_ptr(out), to_digest_ptr(in));
|
|
}
|
|
|
|
void do_feed(SHA256Val::StatePtr ptr, const void* data, size_t size) {
|
|
detail::hash_update(to_digest_ptr(ptr), data, size);
|
|
}
|
|
|
|
void do_get(SHA256Val::StatePtr ptr, u_char* digest) { detail::hash_final_no_free(to_digest_ptr(ptr), digest); }
|
|
|
|
std::string do_serialize(SHA256Val::StatePtr ptr) {
|
|
auto* md = reinterpret_cast<SHA256_CTX*>(EVP_MD_CTX_md_data(to_native_ptr(ptr)));
|
|
return {reinterpret_cast<const char*>(md), sizeof(SHA256_CTX)};
|
|
}
|
|
|
|
void do_unserialize(SHA256Val::StatePtr ptr, const char* bytes, size_t len) {
|
|
auto* md = reinterpret_cast<SHA256_CTX*>(EVP_MD_CTX_md_data(to_native_ptr(ptr)));
|
|
memcpy(md, bytes, len);
|
|
}
|
|
|
|
void do_destroy(SHA256Val::StatePtr ptr) { hash_state_free(to_digest_ptr(ptr)); }
|
|
|
|
#else
|
|
|
|
// -- MD5
|
|
|
|
auto* to_native_ptr(MD5Val::StatePtr ptr) { return reinterpret_cast<MD5_CTX*>(ptr); }
|
|
|
|
void do_init(MD5Val::StatePtr& ptr) {
|
|
auto ctx = new MD5_CTX;
|
|
MD5_Init(ctx);
|
|
ptr = reinterpret_cast<MD5Val::StatePtr>(ctx);
|
|
}
|
|
|
|
void do_clone(MD5Val::StatePtr out, MD5Val::StatePtr in) { *to_native_ptr(out) = *to_native_ptr(in); }
|
|
|
|
void do_feed(MD5Val::StatePtr ptr, const void* data, size_t size) { MD5_Update(to_native_ptr(ptr), data, size); }
|
|
|
|
void do_get(MD5Val::StatePtr ptr, u_char* digest) { MD5_Final(digest, to_native_ptr(ptr)); }
|
|
|
|
std::string do_serialize(MD5Val::StatePtr ptr) { return {reinterpret_cast<const char*>(ptr), sizeof(MD5_CTX)}; }
|
|
|
|
void do_unserialize(MD5Val::StatePtr ptr, const char* bytes, size_t len) { memcpy(ptr, bytes, len); }
|
|
|
|
void do_destroy(MD5Val::StatePtr ptr) { delete to_native_ptr(ptr); }
|
|
|
|
// -- SHA1
|
|
|
|
auto* to_native_ptr(SHA1Val::StatePtr ptr) { return reinterpret_cast<SHA_CTX*>(ptr); }
|
|
|
|
void do_init(SHA1Val::StatePtr& ptr) {
|
|
auto ctx = new SHA_CTX;
|
|
SHA1_Init(ctx);
|
|
ptr = reinterpret_cast<SHA1Val::StatePtr>(ctx);
|
|
}
|
|
|
|
void do_clone(SHA1Val::StatePtr out, SHA1Val::StatePtr in) { *to_native_ptr(out) = *to_native_ptr(in); }
|
|
|
|
void do_feed(SHA1Val::StatePtr ptr, const void* data, size_t size) { SHA1_Update(to_native_ptr(ptr), data, size); }
|
|
|
|
void do_get(SHA1Val::StatePtr ptr, u_char* digest) { SHA1_Final(digest, to_native_ptr(ptr)); }
|
|
|
|
std::string do_serialize(SHA1Val::StatePtr ptr) { return {reinterpret_cast<const char*>(ptr), sizeof(SHA_CTX)}; }
|
|
|
|
void do_unserialize(SHA1Val::StatePtr ptr, const char* bytes, size_t len) { memcpy(ptr, bytes, len); }
|
|
|
|
void do_destroy(SHA1Val::StatePtr ptr) { delete to_native_ptr(ptr); }
|
|
|
|
// -- SHA256
|
|
|
|
auto* to_native_ptr(SHA256Val::StatePtr ptr) { return reinterpret_cast<SHA256_CTX*>(ptr); }
|
|
|
|
void do_init(SHA256Val::StatePtr& ptr) {
|
|
auto ctx = new SHA256_CTX;
|
|
SHA256_Init(ctx);
|
|
ptr = reinterpret_cast<SHA256Val::StatePtr>(ctx);
|
|
}
|
|
|
|
void do_clone(SHA256Val::StatePtr out, SHA256Val::StatePtr in) { *to_native_ptr(out) = *to_native_ptr(in); }
|
|
|
|
void do_feed(SHA256Val::StatePtr ptr, const void* data, size_t size) { SHA256_Update(to_native_ptr(ptr), data, size); }
|
|
|
|
void do_get(SHA256Val::StatePtr ptr, u_char* digest) { SHA256_Final(digest, to_native_ptr(ptr)); }
|
|
|
|
std::string do_serialize(SHA256Val::StatePtr ptr) { return {reinterpret_cast<const char*>(ptr), sizeof(SHA256_CTX)}; }
|
|
|
|
void do_unserialize(SHA256Val::StatePtr ptr, const char* bytes, size_t len) { memcpy(ptr, bytes, len); }
|
|
|
|
void do_destroy(SHA256Val::StatePtr ptr) { delete to_native_ptr(ptr); }
|
|
|
|
#endif
|
|
|
|
} // namespace
|
|
|
|
MD5Val::MD5Val() : HashVal(md5_type) {}
|
|
|
|
MD5Val::~MD5Val() { do_destroy(ctx); }
|
|
|
|
void HashVal::digest_one(detail::HashDigestState* h, const Val* v) {
|
|
if ( v->GetType()->Tag() == TYPE_STRING ) {
|
|
const String* str = v->AsString();
|
|
detail::hash_update(h, str->Bytes(), str->Len());
|
|
}
|
|
else {
|
|
ODesc d(DESC_BINARY);
|
|
v->Describe(&d);
|
|
detail::hash_update(h, (const u_char*)d.Bytes(), d.Size());
|
|
}
|
|
}
|
|
|
|
void HashVal::digest_one(detail::HashDigestState* h, const ValPtr& v) { digest_one(h, v.get()); }
|
|
|
|
ValPtr MD5Val::DoClone(CloneState* state) {
|
|
auto out = make_intrusive<MD5Val>();
|
|
|
|
if ( IsValid() ) {
|
|
if ( ! out->Init() )
|
|
return nullptr;
|
|
do_clone(out->ctx, ctx);
|
|
}
|
|
|
|
return state->NewClone(this, std::move(out));
|
|
}
|
|
|
|
bool MD5Val::DoInit() {
|
|
assert(! IsValid());
|
|
do_init(ctx);
|
|
return true;
|
|
}
|
|
|
|
bool MD5Val::DoFeed(const void* data, size_t size) {
|
|
if ( ! IsValid() )
|
|
return false;
|
|
do_feed(ctx, data, size);
|
|
return true;
|
|
}
|
|
|
|
StringValPtr MD5Val::DoGet() {
|
|
if ( ! IsValid() )
|
|
return val_mgr->EmptyString();
|
|
|
|
u_char digest[ZEEK_MD5_DIGEST_LENGTH];
|
|
do_get(ctx, digest);
|
|
return make_intrusive<StringVal>(detail::md5_digest_print(digest));
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(MD5Val)
|
|
|
|
std::optional<BrokerData> MD5Val::DoSerializeData() const {
|
|
BrokerListBuilder builder;
|
|
|
|
if ( ! IsValid() ) {
|
|
builder.Add(false);
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
builder.Reserve(2);
|
|
builder.Add(true);
|
|
builder.Add(do_serialize(ctx));
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool MD5Val::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
auto d = data.ToList();
|
|
|
|
if ( d.IsEmpty() || ! d[0].IsBool() )
|
|
return false;
|
|
|
|
if ( ! d[0].ToBool() ) {
|
|
assert(! IsValid()); // default set by ctor
|
|
return true;
|
|
}
|
|
|
|
if ( d.Size() != 2 || ! d[1].IsString() )
|
|
return false;
|
|
|
|
auto s = d[1].ToString();
|
|
|
|
if ( s.size() != MD5VAL_STATE_SIZE )
|
|
return false;
|
|
|
|
Init();
|
|
do_unserialize(ctx, s.data(), s.size());
|
|
return true;
|
|
}
|
|
|
|
SHA1Val::SHA1Val() : HashVal(sha1_type) {}
|
|
|
|
SHA1Val::~SHA1Val() { do_destroy(ctx); }
|
|
|
|
ValPtr SHA1Val::DoClone(CloneState* state) {
|
|
auto out = make_intrusive<SHA1Val>();
|
|
|
|
if ( IsValid() ) {
|
|
if ( ! out->Init() )
|
|
return nullptr;
|
|
|
|
do_clone(out->ctx, ctx);
|
|
}
|
|
|
|
return state->NewClone(this, std::move(out));
|
|
}
|
|
|
|
bool SHA1Val::DoInit() {
|
|
assert(! IsValid());
|
|
do_init(ctx);
|
|
return true;
|
|
}
|
|
|
|
bool SHA1Val::DoFeed(const void* data, size_t size) {
|
|
if ( ! IsValid() )
|
|
return false;
|
|
|
|
do_feed(ctx, data, size);
|
|
return true;
|
|
}
|
|
|
|
StringValPtr SHA1Val::DoGet() {
|
|
if ( ! IsValid() )
|
|
return val_mgr->EmptyString();
|
|
|
|
u_char digest[SHA_DIGEST_LENGTH];
|
|
do_get(ctx, digest);
|
|
return make_intrusive<StringVal>(detail::sha1_digest_print(digest));
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(SHA1Val)
|
|
|
|
std::optional<BrokerData> SHA1Val::DoSerializeData() const {
|
|
BrokerListBuilder builder;
|
|
|
|
if ( ! IsValid() ) {
|
|
builder.Add(false);
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
builder.Reserve(2);
|
|
builder.Add(true);
|
|
builder.Add(do_serialize(ctx));
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool SHA1Val::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
|
|
auto d = data.ToList();
|
|
|
|
if ( d.IsEmpty() || ! d[0].IsBool() )
|
|
return false;
|
|
|
|
if ( ! d[0].ToBool() ) {
|
|
assert(! IsValid()); // default set by ctor
|
|
return true;
|
|
}
|
|
|
|
if ( d.Size() != 2 || ! d[1].IsString() )
|
|
return false;
|
|
|
|
auto s = d[1].ToString();
|
|
|
|
if ( s.size() != SHA1VAL_STATE_SIZE )
|
|
return false;
|
|
|
|
Init();
|
|
do_unserialize(ctx, s.data(), s.size());
|
|
return true;
|
|
}
|
|
|
|
SHA256Val::SHA256Val() : HashVal(sha256_type) {}
|
|
|
|
SHA256Val::~SHA256Val() {
|
|
if ( ctx != nullptr )
|
|
do_destroy(ctx);
|
|
}
|
|
|
|
ValPtr SHA256Val::DoClone(CloneState* state) {
|
|
auto out = make_intrusive<SHA256Val>();
|
|
|
|
if ( IsValid() ) {
|
|
if ( ! out->Init() )
|
|
return nullptr;
|
|
|
|
do_clone(out->ctx, ctx);
|
|
}
|
|
|
|
return state->NewClone(this, std::move(out));
|
|
}
|
|
|
|
bool SHA256Val::DoInit() {
|
|
assert(! IsValid());
|
|
do_init(ctx);
|
|
return true;
|
|
}
|
|
|
|
bool SHA256Val::DoFeed(const void* data, size_t size) {
|
|
if ( ! IsValid() )
|
|
return false;
|
|
|
|
do_feed(ctx, data, size);
|
|
return true;
|
|
}
|
|
|
|
StringValPtr SHA256Val::DoGet() {
|
|
if ( ! IsValid() )
|
|
return val_mgr->EmptyString();
|
|
|
|
u_char digest[SHA256_DIGEST_LENGTH];
|
|
do_get(ctx, digest);
|
|
return make_intrusive<StringVal>(detail::sha256_digest_print(digest));
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(SHA256Val)
|
|
|
|
std::optional<BrokerData> SHA256Val::DoSerializeData() const {
|
|
BrokerListBuilder builder;
|
|
|
|
if ( ! IsValid() ) {
|
|
builder.Add(false);
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
builder.Add(true);
|
|
builder.Add(do_serialize(ctx));
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool SHA256Val::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
|
|
auto d = data.ToList();
|
|
|
|
if ( d.IsEmpty() || ! d[0].IsBool() )
|
|
return false;
|
|
|
|
if ( ! d[0].ToBool() ) {
|
|
assert(! IsValid()); // default set by ctor
|
|
return true;
|
|
}
|
|
|
|
if ( d.Size() != 2 || ! d[1].IsString() )
|
|
return false;
|
|
|
|
auto s = d[1].ToString();
|
|
|
|
if ( s.size() != SHA256VAL_STATE_SIZE )
|
|
return false;
|
|
|
|
Init();
|
|
do_unserialize(ctx, s.data(), s.size());
|
|
return true;
|
|
}
|
|
|
|
EntropyVal::EntropyVal() : OpaqueVal(entropy_type) {}
|
|
|
|
bool EntropyVal::Feed(const void* data, size_t size) {
|
|
state.add(data, size);
|
|
return true;
|
|
}
|
|
|
|
bool EntropyVal::Get(double* r_ent, double* r_chisq, double* r_mean, double* r_montepicalc, double* r_scc) {
|
|
state.end(r_ent, r_chisq, r_mean, r_montepicalc, r_scc);
|
|
return true;
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(EntropyVal)
|
|
|
|
std::optional<BrokerData> EntropyVal::DoSerializeData() const {
|
|
constexpr size_t numMembers = 14; // RandTest has 14 non-array members.
|
|
|
|
BrokerListBuilder builder;
|
|
builder.Reserve(numMembers + std::size(state.ccount) + std::size(state.monte));
|
|
|
|
builder.Add(static_cast<uint64_t>(state.totalc));
|
|
builder.Add(static_cast<uint64_t>(state.mp));
|
|
builder.Add(static_cast<uint64_t>(state.sccfirst));
|
|
builder.Add(static_cast<uint64_t>(state.inmont));
|
|
builder.Add(static_cast<uint64_t>(state.mcount));
|
|
builder.Add(static_cast<uint64_t>(state.cexp));
|
|
builder.Add(static_cast<uint64_t>(state.montex));
|
|
builder.Add(static_cast<uint64_t>(state.montey));
|
|
builder.Add(static_cast<uint64_t>(state.montepi));
|
|
builder.Add(static_cast<uint64_t>(state.sccu0));
|
|
builder.Add(static_cast<uint64_t>(state.scclast));
|
|
builder.Add(static_cast<uint64_t>(state.scct1));
|
|
builder.Add(static_cast<uint64_t>(state.scct2));
|
|
builder.Add(static_cast<uint64_t>(state.scct3));
|
|
|
|
for ( auto bin : state.ccount )
|
|
builder.Add(static_cast<uint64_t>(bin));
|
|
|
|
for ( auto val : state.monte )
|
|
builder.Add(static_cast<uint64_t>(val));
|
|
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool EntropyVal::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
|
|
auto index = size_t{0};
|
|
|
|
auto d = data.ToList();
|
|
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.totalc) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.mp) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.sccfirst) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.inmont) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.mcount) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.cexp) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.montex) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.montey) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.montepi) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.sccu0) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.scclast) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.scct1) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.scct2) )
|
|
return false;
|
|
if ( ! get_vector_idx_if_count(d, index++, &state.scct3) )
|
|
return false;
|
|
|
|
for ( auto& bin : state.ccount ) {
|
|
if ( ! get_vector_idx_if_count(d, index++, &bin) )
|
|
return false;
|
|
}
|
|
|
|
for ( auto& val : state.monte ) {
|
|
if ( ! get_vector_idx_if_count(d, index++, &val) )
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
BloomFilterVal::BloomFilterVal() : OpaqueVal(bloomfilter_type) {
|
|
hash = nullptr;
|
|
bloom_filter = nullptr;
|
|
}
|
|
|
|
BloomFilterVal::BloomFilterVal(probabilistic::BloomFilter* bf) : OpaqueVal(bloomfilter_type) {
|
|
hash = nullptr;
|
|
bloom_filter = bf;
|
|
}
|
|
|
|
ValPtr BloomFilterVal::DoClone(CloneState* state) {
|
|
if ( bloom_filter ) {
|
|
auto bf = make_intrusive<BloomFilterVal>(bloom_filter->Clone());
|
|
assert(type);
|
|
if ( ! bf->Typify(type) )
|
|
reporter->InternalError("Failed to typify new bloom_filter clone, clone already had valid type");
|
|
|
|
return state->NewClone(this, std::move(bf));
|
|
}
|
|
|
|
return state->NewClone(this, make_intrusive<BloomFilterVal>());
|
|
}
|
|
|
|
bool BloomFilterVal::Typify(TypePtr arg_type) {
|
|
if ( type )
|
|
return false;
|
|
|
|
type = std::move(arg_type);
|
|
|
|
auto tl = make_intrusive<TypeList>(type);
|
|
tl->Append(type);
|
|
hash = new detail::CompositeHash(std::move(tl));
|
|
|
|
return true;
|
|
}
|
|
|
|
void BloomFilterVal::Add(const Val* val) {
|
|
auto key = hash->MakeHashKey(*val, true);
|
|
bloom_filter->Add(key.get());
|
|
}
|
|
|
|
bool BloomFilterVal::Decrement(const Val* val) {
|
|
auto key = hash->MakeHashKey(*val, true);
|
|
return bloom_filter->Decrement(key.get());
|
|
}
|
|
|
|
size_t BloomFilterVal::Count(const Val* val) const {
|
|
auto key = hash->MakeHashKey(*val, true);
|
|
size_t cnt = bloom_filter->Count(key.get());
|
|
return cnt;
|
|
}
|
|
|
|
void BloomFilterVal::Clear() { bloom_filter->Clear(); }
|
|
|
|
bool BloomFilterVal::Empty() const { return bloom_filter->Empty(); }
|
|
|
|
std::string BloomFilterVal::InternalState() const { return bloom_filter->InternalState(); }
|
|
|
|
BloomFilterValPtr BloomFilterVal::Merge(const BloomFilterVal* x, const BloomFilterVal* y) {
|
|
if ( x->Type() && // any one 0 is ok here
|
|
y->Type() && ! same_type(x->Type(), y->Type()) ) {
|
|
reporter->Error("cannot merge Bloom filters with different types");
|
|
return nullptr;
|
|
}
|
|
|
|
auto final_type = x->Type() ? x->Type() : y->Type();
|
|
|
|
if ( typeid(*x->bloom_filter) != typeid(*y->bloom_filter) ) {
|
|
reporter->Error("cannot merge different Bloom filter types");
|
|
return nullptr;
|
|
}
|
|
|
|
probabilistic::BloomFilter* copy = x->bloom_filter->Clone();
|
|
|
|
if ( ! copy->Merge(y->bloom_filter) ) {
|
|
delete copy;
|
|
reporter->Error("failed to merge Bloom filter");
|
|
return nullptr;
|
|
}
|
|
|
|
auto merged = make_intrusive<BloomFilterVal>(copy);
|
|
|
|
if ( final_type && ! merged->Typify(final_type) ) {
|
|
reporter->Error("failed to set type on merged Bloom filter");
|
|
return nullptr;
|
|
}
|
|
|
|
return merged;
|
|
}
|
|
|
|
BloomFilterValPtr BloomFilterVal::Intersect(const BloomFilterVal* x, const BloomFilterVal* y) {
|
|
if ( x->Type() && // any one 0 is ok here
|
|
y->Type() && ! same_type(x->Type(), y->Type()) ) {
|
|
reporter->Error("cannot merge Bloom filters with different types");
|
|
return nullptr;
|
|
}
|
|
|
|
if ( typeid(*x->bloom_filter) != typeid(*y->bloom_filter) ) {
|
|
reporter->Error("cannot intersect different Bloom filter types");
|
|
return nullptr;
|
|
}
|
|
|
|
auto intersected_bf = x->bloom_filter->Intersect(y->bloom_filter);
|
|
|
|
if ( ! intersected_bf ) {
|
|
reporter->Error("failed to intersect Bloom filter");
|
|
return nullptr;
|
|
}
|
|
|
|
auto final_type = x->Type() ? x->Type() : y->Type();
|
|
|
|
auto intersected = make_intrusive<BloomFilterVal>(intersected_bf);
|
|
|
|
if ( final_type && ! intersected->Typify(final_type) ) {
|
|
reporter->Error("Failed to set type on intersected bloom filter");
|
|
return nullptr;
|
|
}
|
|
|
|
return intersected;
|
|
}
|
|
|
|
BloomFilterVal::~BloomFilterVal() {
|
|
delete hash;
|
|
delete bloom_filter;
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(BloomFilterVal)
|
|
|
|
std::optional<BrokerData> BloomFilterVal::DoSerializeData() const {
|
|
BrokerListBuilder builder;
|
|
|
|
if ( type ) {
|
|
auto t = SerializeType(type);
|
|
if ( ! t )
|
|
return std::nullopt;
|
|
|
|
builder.Add(std::move(*t));
|
|
}
|
|
else
|
|
builder.AddNil();
|
|
|
|
auto bf = bloom_filter->SerializeData();
|
|
if ( ! bf )
|
|
return std::nullopt;
|
|
|
|
builder.Add(std::move(*bf));
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool BloomFilterVal::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
|
|
auto v = data.ToList();
|
|
|
|
if ( v.Size() != 2 )
|
|
return false;
|
|
|
|
if ( ! v[0].IsNil() ) {
|
|
auto t = UnserializeType(v[0]);
|
|
|
|
if ( ! (t && Typify(std::move(t))) )
|
|
return false;
|
|
}
|
|
|
|
auto bf = probabilistic::BloomFilter::UnserializeData(v[1]);
|
|
if ( ! bf )
|
|
return false;
|
|
|
|
bloom_filter = bf.release();
|
|
return true;
|
|
}
|
|
|
|
CardinalityVal::CardinalityVal() : OpaqueVal(cardinality_type) {
|
|
c = nullptr;
|
|
hash = nullptr;
|
|
}
|
|
|
|
CardinalityVal::CardinalityVal(probabilistic::detail::CardinalityCounter* arg_c) : OpaqueVal(cardinality_type) {
|
|
c = arg_c;
|
|
hash = nullptr;
|
|
}
|
|
|
|
CardinalityVal::~CardinalityVal() {
|
|
delete c;
|
|
delete hash;
|
|
}
|
|
|
|
ValPtr CardinalityVal::DoClone(CloneState* state) {
|
|
return state->NewClone(this, make_intrusive<CardinalityVal>(new probabilistic::detail::CardinalityCounter(*c)));
|
|
}
|
|
|
|
bool CardinalityVal::Typify(TypePtr arg_type) {
|
|
if ( type )
|
|
return false;
|
|
|
|
type = std::move(arg_type);
|
|
|
|
auto tl = make_intrusive<TypeList>(type);
|
|
tl->Append(type);
|
|
hash = new detail::CompositeHash(std::move(tl));
|
|
|
|
return true;
|
|
}
|
|
|
|
void CardinalityVal::Add(const Val* val) {
|
|
auto key = hash->MakeHashKey(*val, true);
|
|
c->AddElement(key->Hash());
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(CardinalityVal)
|
|
|
|
std::optional<BrokerData> CardinalityVal::DoSerializeData() const {
|
|
BrokerListBuilder builder;
|
|
builder.Reserve(2);
|
|
|
|
if ( type ) {
|
|
auto t = SerializeType(type);
|
|
if ( ! t )
|
|
return std::nullopt;
|
|
|
|
builder.Add(std::move(*t));
|
|
}
|
|
else
|
|
builder.AddNil();
|
|
|
|
auto cs = c->Serialize();
|
|
if ( ! cs )
|
|
return std::nullopt;
|
|
|
|
builder.Add(std::move(*cs));
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool CardinalityVal::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
|
|
auto v = data.ToList();
|
|
|
|
if ( v.Size() != 2 )
|
|
return false;
|
|
|
|
if ( ! v[0].IsNil() ) {
|
|
auto t = UnserializeType(v[0]);
|
|
|
|
if ( ! (t && Typify(std::move(t))) )
|
|
return false;
|
|
}
|
|
|
|
auto cu = probabilistic::detail::CardinalityCounter::Unserialize(v[1]);
|
|
if ( ! cu )
|
|
return false;
|
|
|
|
c = cu.release();
|
|
return true;
|
|
}
|
|
|
|
ParaglobVal::ParaglobVal(std::unique_ptr<paraglob::Paraglob> p) : OpaqueVal(paraglob_type) {
|
|
this->internal_paraglob = std::move(p);
|
|
}
|
|
|
|
VectorValPtr ParaglobVal::Get(StringVal*& pattern) {
|
|
auto rval = make_intrusive<VectorVal>(id::string_vec);
|
|
std::string string_pattern(reinterpret_cast<const char*>(pattern->Bytes()), pattern->Len());
|
|
|
|
std::vector<std::string> matches = this->internal_paraglob->get(string_pattern);
|
|
for ( size_t i = 0; i < matches.size(); i++ )
|
|
rval->Assign(i, make_intrusive<StringVal>(matches.at(i)));
|
|
|
|
return rval;
|
|
}
|
|
|
|
bool ParaglobVal::operator==(const ParaglobVal& other) const {
|
|
return *(this->internal_paraglob) == *(other.internal_paraglob);
|
|
}
|
|
|
|
IMPLEMENT_OPAQUE_VALUE(ParaglobVal)
|
|
|
|
std::optional<BrokerData> ParaglobVal::DoSerializeData() const {
|
|
std::unique_ptr<std::vector<uint8_t>> iv = this->internal_paraglob->serialize();
|
|
BrokerListBuilder builder;
|
|
builder.Reserve(iv->size());
|
|
for ( uint8_t a : *iv )
|
|
builder.AddCount(a);
|
|
return std::move(builder).Build();
|
|
}
|
|
|
|
bool ParaglobVal::DoUnserializeData(BrokerDataView data) {
|
|
if ( ! data.IsList() )
|
|
return false;
|
|
|
|
auto d = data.ToList();
|
|
|
|
auto iv = std::make_unique<std::vector<uint8_t>>();
|
|
iv->resize(d.Size());
|
|
|
|
for ( size_t index = 0; index < d.Size(); ++index ) {
|
|
if ( ! get_vector_idx_if_count(d, index, iv->data() + index) )
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
this->internal_paraglob = std::make_unique<paraglob::Paraglob>(std::move(iv));
|
|
} catch ( const paraglob::underflow_error& e ) {
|
|
reporter->Error("Paraglob underflow error -> %s", e.what());
|
|
return false;
|
|
} catch ( const paraglob::overflow_error& e ) {
|
|
reporter->Error("Paraglob overflow error -> %s", e.what());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
ValPtr ParaglobVal::DoClone(CloneState* state) {
|
|
try {
|
|
return make_intrusive<ParaglobVal>(std::make_unique<paraglob::Paraglob>(this->internal_paraglob->serialize()));
|
|
} catch ( const paraglob::underflow_error& e ) {
|
|
reporter->Error("Paraglob underflow error while cloning -> %s", e.what());
|
|
return nullptr;
|
|
} catch ( const paraglob::overflow_error& e ) {
|
|
reporter->Error("Paraglob overflow error while cloning -> %s", e.what());
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
} // namespace zeek
|