Migrate entropy testing to opaque.

This commit is contained in:
Matthias Vallentin 2012-12-13 19:18:47 -08:00
parent 86faab1e06
commit b9d05f56d0
7 changed files with 156 additions and 87 deletions

View file

@ -398,3 +398,103 @@ bool SHA256Val::DoUnserialize(UnserialInfo* info)
return true; 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;
}

View file

@ -1,6 +1,7 @@
#ifndef OPAQUEVAL_H #ifndef OPAQUEVAL_H
#define OPAQUEVAL_H #define OPAQUEVAL_H
#include "RandTest.h"
#include "Val.h" #include "Val.h"
#include "digest.h" #include "digest.h"
@ -86,4 +87,22 @@ private:
SHA256_CTX ctx; 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 #endif

View file

@ -12,6 +12,7 @@
Modified for Bro by Seth Hall - July 2010 Modified for Bro by Seth Hall - July 2010
*/ */
#include <math.h>
#include "RandTest.h" #include "RandTest.h"
#define log2of10 3.32192809488736234787 #define log2of10 3.32192809488736234787

View file

@ -1,11 +1,14 @@
#include <math.h> #ifndef RANDTEST_H
#define RANDTEST_H
class EntropyVal; #include "util.h"
#define RT_MONTEN 6 /* Bytes used as Monte Carlo #define RT_MONTEN 6 /* Bytes used as Monte Carlo
co-ordinates. This should be no more co-ordinates. This should be no more
bits than the mantissa of your "double" bits than the mantissa of your "double"
floating point type. */ floating point type. */
class EntropyVal;
class RandTest { class RandTest {
public: public:
@ -17,12 +20,14 @@ class RandTest {
private: private:
friend class EntropyVal; friend class EntropyVal;
long ccount[256]; /* Bins to count occurrences of values */ int64 ccount[256]; /* Bins to count occurrences of values */
long totalc; /* Total bytes counted */ int64 totalc; /* Total bytes counted */
int mp; int mp;
int sccfirst; int sccfirst;
unsigned int monte[RT_MONTEN]; unsigned int monte[RT_MONTEN];
long inmont, mcount; int64 inmont, mcount;
double cexp, montex, montey, montepi, double cexp, montex, montey, montepi,
sccu0, scclast, scct1, scct2, scct3; sccu0, scclast, scct1, scct2, scct3;
}; };
#endif

View file

@ -103,6 +103,7 @@ SERIAL_VAL(HASH_VAL, 15)
SERIAL_VAL(MD5_VAL, 16) SERIAL_VAL(MD5_VAL, 16)
SERIAL_VAL(SHA1_VAL, 17) SERIAL_VAL(SHA1_VAL, 17)
SERIAL_VAL(SHA256_VAL, 18) SERIAL_VAL(SHA256_VAL, 18)
SERIAL_VAL(ENTROPY_VAL, 19)
#define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR) #define SERIAL_EXPR(name, val) SERIAL_CONST(name, val, EXPR)
SERIAL_EXPR(EXPR, 1) SERIAL_EXPR(EXPR, 1)

View file

@ -878,11 +878,6 @@ function identify_data%(data: string, return_mime: bool%): string
return new StringVal(descr); return new StringVal(descr);
%} %}
%%{
#include <RandTest.h>
static map<BroString, RandTest*> entropy_states;
%%}
## Performs an entropy test on the given data. ## Performs an entropy test on the given data.
## See http://www.fourmilab.ch/random. ## See http://www.fourmilab.ch/random.
## ##
@ -927,13 +922,11 @@ function find_entropy%(data: string%): entropy_test_result
%{ %{
double montepi, scc, ent, mean, chisq; double montepi, scc, ent, mean, chisq;
montepi = scc = ent = mean = chisq = 0.0; 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); 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(0, new Val(ent, TYPE_DOUBLE));
ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE)); ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE));
ent_result->Assign(2, new Val(mean, 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; 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. ## Initializes data structures for incremental entropy calculation.
## ##
## index: An arbitrary unique value per distinct computation. ## Returns: An opaque handle to be used in subsequent operations.
##
## Returns: True on success.
## ##
## .. bro:see:: find_entropy entropy_test_add entropy_test_finish ## .. 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); return new EntropyVal();
int status = 0;
if ( entropy_states.count(*s) < 1 )
{
entropy_states[*s] = new RandTest();
status = 1;
}
delete s;
return new Val(status, TYPE_BOOL);
%} %}
## Adds data to an incremental entropy calculation. Before using this function, ## Adds data to an incremental entropy calculation.
## one needs to invoke :bro:id:`entropy_test_init`. ##
## handle: The opaque handle representing the entropy calculation state.
## ##
## data: The data to add to the entropy calculation. ## data: The data to add to the entropy calculation.
## ##
## index: An arbitrary unique value that identifies a particular entropy
## computation.
##
## Returns: True on success. ## Returns: True on success.
## ##
## .. bro:see:: find_entropy entropy_test_add entropy_test_finish ## .. 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); bool status = static_cast<EntropyVal*>(handle)->Feed(data->Bytes(),
int status = 0; data->Len());
if ( entropy_states.count(*s) > 0 )
{
entropy_states[*s]->add((char*) data->Bytes(), data->Len());
status = 1;
}
delete s;
return new Val(status, TYPE_BOOL); return new Val(status, TYPE_BOOL);
%} %}
## Finishes an incremental entropy calculation. Before using this function, ## 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`. ## add data to it via :bro:id:`entropy_test_add`.
## ##
## index: An arbitrary unique value that identifies a particular entropy ## handle: The opaque handle representing the entropy calculation state.
## computation.
## ##
## Returns: The result of the entropy test. See :bro:id:`find_entropy` for a ## Returns: The result of the entropy test. See :bro:id:`find_entropy` for a
## description of the individual components. ## description of the individual components.
## ##
## .. bro:see:: find_entropy entropy_test_init entropy_test_add ## .. 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; double montepi, scc, ent, mean, chisq;
montepi = scc = ent = mean = chisq = 0.0; montepi = scc = ent = mean = chisq = 0.0;
static_cast<EntropyVal*>(handle)->Get(&ent, &chisq, &mean, &montepi, &scc);
RecordVal* ent_result = new RecordVal(entropy_test_result); 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(0, new Val(ent, TYPE_DOUBLE));
ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE)); ent_result->Assign(1, new Val(chisq, TYPE_DOUBLE));
ent_result->Assign(2, new Val(mean, TYPE_DOUBLE)); ent_result->Assign(2, new Val(mean, TYPE_DOUBLE));
ent_result->Assign(3, new Val(montepi, TYPE_DOUBLE)); ent_result->Assign(3, new Val(montepi, TYPE_DOUBLE));
ent_result->Assign(4, new Val(scc, TYPE_DOUBLE)); ent_result->Assign(4, new Val(scc, TYPE_DOUBLE));
delete s;
return ent_result; return ent_result;
%} %}

View file

@ -5,20 +5,14 @@
event bro_init() event bro_init()
{ {
local a = "dh3Hie02uh^s#Sdf9L3frd243h$d78r2G4cM6*Q05d(7rh46f!0|4-f"; 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); exit(1);
print entropy_test_finish(handle);
if ( entropy_test_add(1, a) != T )
exit(1);
print entropy_test_finish(1);
local b = "0011000aaabbbbcccc000011111000000000aaaabbbbcccc0000000"; local b = "0011000aaabbbbcccc000011111000000000aaaabbbbcccc0000000";
if ( entropy_test_init(2) != T ) handle = entropy_test_init();
if ( ! entropy_test_add(handle, b) )
exit(1); exit(1);
print entropy_test_finish(handle);
if ( entropy_test_add(2, b) != T )
exit(1);
print entropy_test_finish(2);
} }