diff --git a/src/OpaqueVal.cc b/src/OpaqueVal.cc index d2f95da29b..a5e65e7e7e 100644 --- a/src/OpaqueVal.cc +++ b/src/OpaqueVal.cc @@ -398,3 +398,103 @@ bool SHA256Val::DoUnserialize(UnserialInfo* info) return true; } + + +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_SERIAL(EntropyVal, SER_ENTROPY_VAL); + +bool EntropyVal::DoSerialize(SerialInfo* info) const + { + DO_SERIALIZE(SER_ENTROPY_VAL, OpaqueVal); + + for ( int i = 0; i < 256; ++i ) + if ( ! SERIALIZE(state.ccount[i]) ) + return false; + if ( ! SERIALIZE(state.totalc) ) + return false; + if ( ! SERIALIZE(state.mp) ) + return false; + if ( ! SERIALIZE(state.sccfirst) ) + return false; + for ( int i = 0; i < RT_MONTEN; ++i ) + if ( ! SERIALIZE(state.monte[i]) ) + return false; + if ( ! SERIALIZE(state.inmont) ) + return false; + if ( ! SERIALIZE(state.mcount) ) + return false; + if ( ! SERIALIZE(state.cexp) ) + return false; + if ( ! SERIALIZE(state.montex) ) + return false; + if ( ! SERIALIZE(state.montey) ) + return false; + if ( ! SERIALIZE(state.montepi) ) + return false; + if ( ! SERIALIZE(state.sccu0) ) + return false; + if ( ! SERIALIZE(state.scclast) ) + return false; + if ( ! SERIALIZE(state.scct1) ) + return false; + if ( ! SERIALIZE(state.scct2) ) + return false; + if ( ! SERIALIZE(state.scct3) ) + return false; + + return true; + } + +bool EntropyVal::DoUnserialize(UnserialInfo* info) + { + DO_UNSERIALIZE(OpaqueVal); + + for ( int i = 0; i < 256; ++i ) + if ( ! UNSERIALIZE(&state.ccount[i]) ) + return false; + if ( ! UNSERIALIZE(&state.totalc) ) + return false; + if ( ! UNSERIALIZE(&state.mp) ) + return false; + if ( ! UNSERIALIZE(&state.sccfirst) ) + return false; + for ( int i = 0; i < RT_MONTEN; ++i ) + if ( ! UNSERIALIZE(&state.monte[i]) ) + return false; + if ( ! UNSERIALIZE(&state.inmont) ) + return false; + if ( ! UNSERIALIZE(&state.mcount) ) + return false; + if ( ! UNSERIALIZE(&state.cexp) ) + return false; + if ( ! UNSERIALIZE(&state.montex) ) + return false; + if ( ! UNSERIALIZE(&state.montey) ) + return false; + if ( ! UNSERIALIZE(&state.montepi) ) + return false; + if ( ! UNSERIALIZE(&state.sccu0) ) + return false; + if ( ! UNSERIALIZE(&state.scclast) ) + return false; + if ( ! UNSERIALIZE(&state.scct1) ) + return false; + if ( ! UNSERIALIZE(&state.scct2) ) + return false; + if ( ! UNSERIALIZE(&state.scct3) ) + return false; + + return true; + } diff --git a/src/OpaqueVal.h b/src/OpaqueVal.h index 04f614e095..02e532aeec 100644 --- a/src/OpaqueVal.h +++ b/src/OpaqueVal.h @@ -1,6 +1,7 @@ #ifndef OPAQUEVAL_H #define OPAQUEVAL_H +#include "RandTest.h" #include "Val.h" #include "digest.h" @@ -86,4 +87,22 @@ private: SHA256_CTX ctx; }; +class EntropyVal : public OpaqueVal { +public: + EntropyVal() : OpaqueVal(new OpaqueType("entropy")) { } + + bool Feed(const void* data, size_t size); + bool Get(double *r_ent, double *r_chisq, double *r_mean, + double *r_montepicalc, double *r_scc); + +protected: + friend class Val; + EntropyVal(OpaqueType* t); + + DECLARE_SERIAL(EntropyVal); + +private: + RandTest state; +}; + #endif diff --git a/src/RandTest.cc b/src/RandTest.cc index 99237e114e..94e76500b5 100644 --- a/src/RandTest.cc +++ b/src/RandTest.cc @@ -12,6 +12,7 @@ Modified for Bro by Seth Hall - July 2010 */ +#include #include "RandTest.h" #define log2of10 3.32192809488736234787 diff --git a/src/RandTest.h b/src/RandTest.h index d787392e14..bb1eb3c6b4 100644 --- a/src/RandTest.h +++ b/src/RandTest.h @@ -1,11 +1,14 @@ -#include +#ifndef RANDTEST_H +#define RANDTEST_H -class EntropyVal; +#include "util.h" #define RT_MONTEN 6 /* Bytes used as Monte Carlo co-ordinates. This should be no more bits than the mantissa of your "double" floating point type. */ +class EntropyVal; + class RandTest { public: @@ -17,12 +20,14 @@ class RandTest { private: friend class EntropyVal; - long ccount[256]; /* Bins to count occurrences of values */ - long totalc; /* Total bytes counted */ + int64 ccount[256]; /* Bins to count occurrences of values */ + int64 totalc; /* Total bytes counted */ int mp; int sccfirst; unsigned int monte[RT_MONTEN]; - long inmont, mcount; + int64 inmont, mcount; double cexp, montex, montey, montepi, sccu0, scclast, scct1, scct2, scct3; - }; +}; + +#endif diff --git a/src/SerialTypes.h b/src/SerialTypes.h index 0eac79a04b..e103c1c40e 100644 --- a/src/SerialTypes.h +++ b/src/SerialTypes.h @@ -103,6 +103,7 @@ SERIAL_VAL(HASH_VAL, 15) SERIAL_VAL(MD5_VAL, 16) SERIAL_VAL(SHA1_VAL, 17) SERIAL_VAL(SHA256_VAL, 18) +SERIAL_VAL(ENTROPY_VAL, 19) #define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR) SERIAL_EXPR(EXPR, 1) diff --git a/src/bro.bif b/src/bro.bif index aec9a56609..260e19c00c 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -878,11 +878,6 @@ function identify_data%(data: string, return_mime: bool%): string return new StringVal(descr); %} -%%{ -#include -static map entropy_states; -%%} - ## Performs an entropy test on the given data. ## See http://www.fourmilab.ch/random. ## @@ -927,13 +922,11 @@ function find_entropy%(data: string%): entropy_test_result %{ double montepi, scc, ent, mean, chisq; montepi = scc = ent = mean = chisq = 0.0; + EntropyVal e; + e.Feed(data->Bytes(), data->Len()); + e.Get(&ent, &chisq, &mean, &montepi, &scc); + RecordVal* ent_result = new RecordVal(entropy_test_result); - RandTest *rt = new RandTest(); - - rt->add((char*) data->Bytes(), data->Len()); - rt->end(&ent, &chisq, &mean, &montepi, &scc); - delete rt; - ent_result->Assign(0, new Val(ent, TYPE_DOUBLE)); ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE)); ent_result->Assign(2, new Val(mean, TYPE_DOUBLE)); @@ -942,98 +935,54 @@ function find_entropy%(data: string%): entropy_test_result return ent_result; %} -%%{ -BroString* convert_index_to_string(Val* index) - { - ODesc d; - index->Describe(&d); - BroString* s = new BroString(1, d.TakeBytes(), d.Len()); - s->SetUseFreeToDelete(1); - return s; - } -%%} - ## Initializes data structures for incremental entropy calculation. ## -## index: An arbitrary unique value per distinct computation. -## -## Returns: True on success. +## Returns: An opaque handle to be used in subsequent operations. ## ## .. bro:see:: find_entropy entropy_test_add entropy_test_finish -function entropy_test_init%(index: any%): bool +function entropy_test_init%(%): opaque of entropy %{ - BroString* s = convert_index_to_string(index); - int status = 0; - - if ( entropy_states.count(*s) < 1 ) - { - entropy_states[*s] = new RandTest(); - status = 1; - } - - delete s; - return new Val(status, TYPE_BOOL); + return new EntropyVal(); %} -## Adds data to an incremental entropy calculation. Before using this function, -## one needs to invoke :bro:id:`entropy_test_init`. +## Adds data to an incremental entropy calculation. +## +## handle: The opaque handle representing the entropy calculation state. ## ## data: The data to add to the entropy calculation. ## -## index: An arbitrary unique value that identifies a particular entropy -## computation. -## ## Returns: True on success. ## ## .. bro:see:: find_entropy entropy_test_add entropy_test_finish -function entropy_test_add%(index: any, data: string%): bool +function entropy_test_add%(handle: opaque of entropy, data: string%): bool %{ - BroString* s = convert_index_to_string(index); - int status = 0; - - if ( entropy_states.count(*s) > 0 ) - { - entropy_states[*s]->add((char*) data->Bytes(), data->Len()); - status = 1; - } - - delete s; + bool status = static_cast(handle)->Feed(data->Bytes(), + data->Len()); return new Val(status, TYPE_BOOL); %} ## Finishes an incremental entropy calculation. Before using this function, -## one needs to initialize the computation with :bro:id:`entropy_test_init` and +## one needs to obtain an opaque handle with :bro:id:`entropy_test_init` and ## add data to it via :bro:id:`entropy_test_add`. ## -## index: An arbitrary unique value that identifies a particular entropy -## computation. +## handle: The opaque handle representing the entropy calculation state. ## ## Returns: The result of the entropy test. See :bro:id:`find_entropy` for a ## description of the individual components. ## ## .. bro:see:: find_entropy entropy_test_init entropy_test_add -function entropy_test_finish%(index: any%): entropy_test_result +function entropy_test_finish%(handle: opaque of entropy%): entropy_test_result %{ - BroString* s = convert_index_to_string(index); double montepi, scc, ent, mean, chisq; montepi = scc = ent = mean = chisq = 0.0; + static_cast(handle)->Get(&ent, &chisq, &mean, &montepi, &scc); + RecordVal* ent_result = new RecordVal(entropy_test_result); - - if ( entropy_states.count(*s) > 0 ) - { - RandTest *rt = entropy_states[*s]; - rt->end(&ent, &chisq, &mean, &montepi, &scc); - entropy_states.erase(*s); - delete rt; - } - ent_result->Assign(0, new Val(ent, TYPE_DOUBLE)); ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE)); ent_result->Assign(2, new Val(mean, TYPE_DOUBLE)); ent_result->Assign(3, new Val(montepi, TYPE_DOUBLE)); ent_result->Assign(4, new Val(scc, TYPE_DOUBLE)); - - delete s; return ent_result; %} diff --git a/testing/btest/bifs/entropy_test.bro b/testing/btest/bifs/entropy_test.bro index 8dc54e09b2..2a2dd422d1 100644 --- a/testing/btest/bifs/entropy_test.bro +++ b/testing/btest/bifs/entropy_test.bro @@ -5,20 +5,14 @@ event bro_init() { local a = "dh3Hie02uh^s#Sdf9L3frd243h$d78r2G4cM6*Q05d(7rh46f!0|4-f"; - if ( entropy_test_init(1) != T ) + local handle = entropy_test_init(); + if ( ! entropy_test_add(handle, a) ) exit(1); - - if ( entropy_test_add(1, a) != T ) - exit(1); - - print entropy_test_finish(1); + print entropy_test_finish(handle); local b = "0011000aaabbbbcccc000011111000000000aaaabbbbcccc0000000"; - if ( entropy_test_init(2) != T ) + handle = entropy_test_init(); + if ( ! entropy_test_add(handle, b) ) exit(1); - - if ( entropy_test_add(2, b) != T ) - exit(1); - - print entropy_test_finish(2); + print entropy_test_finish(handle); }