From 5865bf38501fe892c29302916e022dbb855c94fa Mon Sep 17 00:00:00 2001 From: Jon Siwek Date: Fri, 11 Nov 2011 13:48:11 -0600 Subject: [PATCH] Add decode_base64_custom BiF to allow alternate base64 alphabets. Addresses #670 --- src/Base64.cc | 69 +++++++++++++++---- src/Base64.h | 10 ++- src/bro.bif | 12 ++++ testing/btest/Baseline/bifs.decode_base64/out | 6 ++ testing/btest/bifs/decode_base64.bro | 14 ++++ 5 files changed, 97 insertions(+), 14 deletions(-) create mode 100644 testing/btest/Baseline/bifs.decode_base64/out create mode 100644 testing/btest/bifs/decode_base64.bro diff --git a/src/Base64.cc b/src/Base64.cc index 9008837f35..080732eab2 100644 --- a/src/Base64.cc +++ b/src/Base64.cc @@ -1,14 +1,27 @@ #include "config.h" #include "Base64.h" -static int base64_table[256]; +int Base64Decoder::default_base64_table[256]; +const string Base64Decoder::default_alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static void init_base64_table() +int* Base64Decoder::InitBase64Table(const string& alphabet) { - static int table_initialized = 0; + static bool default_table_initialized = false; - if ( ++table_initialized > 1 ) - return; + if ( alphabet == default_alphabet && default_table_initialized ) + return default_base64_table; + + int* base64_table = 0; + + if ( alphabet == default_alphabet ) + { + base64_table = default_base64_table; + default_table_initialized = true; + } + else + { + base64_table = new int[256]; + } int i; for ( i = 0; i < 256; ++i ) @@ -16,28 +29,44 @@ static void init_base64_table() for ( i = 0; i < 26; ++i ) { - base64_table['A' + i] = i; - base64_table['a' + i] = i + 26; + base64_table[int(alphabet[0 + i])] = i; + base64_table[int(alphabet[26 + i])] = i + 26; } for ( i = 0; i < 10; ++i ) - base64_table['0' + i] = i + 52; + base64_table[int(alphabet[52 + i])] = i + 52; // Casts to avoid compiler warnings. - base64_table[int('+')] = 62; - base64_table[int('/')] = 63; + base64_table[int(alphabet[62])] = 62; + base64_table[int(alphabet[63])] = 63; base64_table[int('=')] = 0; + + return base64_table; } Base64Decoder::Base64Decoder(Analyzer* arg_analyzer) { - init_base64_table(); + base64_table = InitBase64Table(default_alphabet); base64_group_next = 0; base64_padding = base64_after_padding = 0; errored = 0; analyzer = arg_analyzer; } +Base64Decoder::Base64Decoder(Analyzer* arg_analyzer, const string& alphabet) + { + base64_table = InitBase64Table(alphabet); + base64_group_next = 0; + base64_padding = base64_after_padding = 0; + errored = 0; + analyzer = arg_analyzer; + } + +Base64Decoder::~Base64Decoder() + { + if ( base64_table != default_base64_table ) delete base64_table; + } + int Base64Decoder::Decode(int len, const char* data, int* pblen, char** pbuf) { int blen; @@ -142,13 +171,21 @@ int Base64Decoder::Done(int* pblen, char** pbuf) return 0; } -BroString* decode_base64(const BroString* s) + +BroString* decode_base64(const BroString* s, const BroString* a) { + if (a->Len() != 64) + { + reporter->Error("base64 decoding alphabet is not 64 characters: %s", + a->CheckString()); + return 0; + } + int buf_len = int((s->Len() + 3) / 4) * 3 + 1; int rlen2, rlen = buf_len; char* rbuf2, *rbuf = new char[rlen]; - Base64Decoder dec(0); + Base64Decoder dec(0, a->CheckString()); if ( dec.Decode(s->Len(), (const char*) s->Bytes(), &rlen, &rbuf) == -1 ) goto err; @@ -166,3 +203,9 @@ err: delete [] rbuf; return 0; } + +BroString* decode_base64(const BroString* s) + { + BroString a(Base64Decoder::default_alphabet); + return decode_base64(s, &a); + } diff --git a/src/Base64.h b/src/Base64.h index 7f351a2c2b..518ae469cd 100644 --- a/src/Base64.h +++ b/src/Base64.h @@ -17,7 +17,8 @@ public: // when the decoder is called by the built-in function // decode_base64(). Base64Decoder(Analyzer* analyzer); - ~Base64Decoder() { } + Base64Decoder(Analyzer* analyzer, const string& alphabet); + ~Base64Decoder(); // A note on Decode(): // @@ -47,6 +48,11 @@ public: reporter->Error("%s", msg); } + static int* InitBase64Table(const string& alphabet); + + static const string default_alphabet; + static int default_base64_table[256]; + protected: char error_msg[256]; @@ -57,8 +63,10 @@ protected: int base64_after_padding; int errored; // if true, we encountered an error - skip further processing Analyzer* analyzer; + int* base64_table; }; +BroString* decode_base64(const BroString* s, const BroString* a); BroString* decode_base64(const BroString* s); #endif /* base64_h */ diff --git a/src/bro.bif b/src/bro.bif index 3350de2867..e1d510f279 100644 --- a/src/bro.bif +++ b/src/bro.bif @@ -1860,6 +1860,18 @@ function decode_base64%(s: string%): string } %} +function decode_base64_custom%(s: string, a: string%): string + %{ + BroString* t = decode_base64(s->AsString(), a->AsString()); + if ( t ) + return new StringVal(t); + else + { + reporter->Error("error in decoding string %s", s->CheckString()); + return new StringVal(""); + } + %} + %%{ #include "DCE_RPC.h" diff --git a/testing/btest/Baseline/bifs.decode_base64/out b/testing/btest/Baseline/bifs.decode_base64/out new file mode 100644 index 0000000000..af0d32fbb8 --- /dev/null +++ b/testing/btest/Baseline/bifs.decode_base64/out @@ -0,0 +1,6 @@ +bro +bro +bro +bro +bro +bro diff --git a/testing/btest/bifs/decode_base64.bro b/testing/btest/bifs/decode_base64.bro new file mode 100644 index 0000000000..d4cbd2f37d --- /dev/null +++ b/testing/btest/bifs/decode_base64.bro @@ -0,0 +1,14 @@ +# @TEST-EXEC: bro -b %INPUT >out +# @TEST-EXEC: btest-diff out + +global default_alphabet: string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + +global my_alphabet: string = "!#$%&/(),-.:;<>@[]^ `_{|}~abcdefghijklmnopqrstuvwxyz0123456789+?"; + +print decode_base64("YnJv"); +print decode_base64_custom("YnJv", default_alphabet); +print decode_base64_custom("}n-v", my_alphabet); + +print decode_base64("YnJv"); +print decode_base64_custom("YnJv", default_alphabet); +print decode_base64_custom("}n-v", my_alphabet);