#
# patch "ChangeLog"
# from [f6962ae1e54db8ef7df9d8daf40c08415d3b60d7]
# to [a7d78e5b4cb7e07bdf3aba7a92ea4fc609a03316]
#
# patch "Makefile.am"
# from [8f57b338067b43d1d1ae5de118323a6c67f6be7d]
# to [f2cebcb5b9a6cf9ca254765464af8cccc11da225]
#
# patch "netcmd.cc"
# from [7308c12cecebbd725ddca9ebfa94bd9a6e1efdea]
# to [f1f30a4a9655a95d2007a309a0d4a618229dcdca]
#
# patch "netcmd.hh"
# from [db259c3bbd1fdc984b3cae3fb90128f7b0e461e5]
# to [f5565d11c6b2db20139d0aab07a5b8bfe37b3cd8]
#
# patch "netsync.cc"
# from [a216c4dc84981cff4cdf26cc45303c46a16054fd]
# to [c0daeb05b828a4e64c62379ceb8f2113c3f8b1ae]
#
# patch "transforms.hh"
# from [beb9c11a04e735f442928aea2e984834c8573c8d]
# to [9fb4f54ab766397cc5a40885457b2ddbabbb300f]
#
--- ChangeLog
+++ ChangeLog
@@ -1,3 +1,15 @@
+2005-06-26 Matt Johnston
+
+ * netcmd.cc (netcmd::read, netcmd::write): change to using a HMACs
+ chained by including the previous HMAC in the input data, rather
+ than altering the key each time.
+ * netcmd.cc ({read,write}_{data,delta}_cmd): use encode_gzip/decode_gzip
+ rather than raw xform.
+ * hmac.{cc,hh}: new chained_hmac abstraction
+ * Makefile.in: add them
+ * netsync.cc: each session keeps a chained_hmac for read/write
+ * transforms.hh: add a string variant for encode_gzip
+
2005-06-25 Nathaniel Smith
* netsync.cc: Tweak comment.
--- Makefile.am
+++ Makefile.am
@@ -40,6 +40,7 @@
selectors.cc selectors.hh \
annotate.cc annotate.hh \
restrictions.cc restrictions.hh \
+ hmac.cc hmac.hh \
\
cleanup.hh unit_tests.hh interner.hh \
cycle_detector.hh randomfile.hh adler32.hh quick_alloc.hh \
--- netcmd.cc
+++ netcmd.cc
@@ -7,10 +7,6 @@
#include
#include
-#include "cryptopp/gzip.h"
-#include "cryptopp/hmac.h"
-#include "cryptopp/sha.h"
-
#include "adler32.hh"
#include "constants.hh"
#include "netcmd.hh"
@@ -18,6 +14,7 @@
#include "numeric_vocab.hh"
#include "sanity.hh"
#include "transforms.hh"
+#include "hmac.hh"
using namespace std;
using namespace boost;
@@ -68,34 +65,19 @@
}
void
-netcmd::write(string & out, netsync_session_key const & key,
- netsync_hmac_value & hmac_val) const
+netcmd::write(string & out, chained_hmac & hmac) const
{
size_t oldlen = out.size();
out += static_cast(version);
out += static_cast(cmd_code);
insert_variable_length_string(payload, out);
- I(key().size() == CryptoPP::SHA::DIGESTSIZE);
- I(key().size() == hmac_val().size());
- byte keybuf[CryptoPP::SHA::DIGESTSIZE];
- for (size_t i = 0; i < sizeof(keybuf); i++)
- {
- keybuf[i] = key()[i] ^ hmac_val()[i];
- }
- CryptoPP::HMAC hmac(keybuf, sizeof(keybuf));
- char digest[CryptoPP::SHA::DIGESTSIZE];
- hmac.CalculateDigest(reinterpret_cast(digest),
- reinterpret_cast(out.data() + oldlen),
- out.size() - oldlen);
- string digest_str(digest, sizeof(digest));
- hmac_val = netsync_hmac_value(digest_str);
- out.append(digest_str);
+ string digest = hmac.process(out, oldlen);
+ out.append(digest);
}
bool
-netcmd::read(string & inbuf, netsync_session_key const & key,
- netsync_hmac_value & hmac_val)
+netcmd::read(string & inbuf, chained_hmac & hmac)
{
size_t pos = 0;
@@ -142,15 +124,19 @@
throw bad_decode(F("oversized payload of '%d' bytes") % payload_len);
// there might not be enough data yet in the input buffer
- if (inbuf.size() < pos + payload_len + CryptoPP::SHA::DIGESTSIZE)
+ if (inbuf.size() < pos + payload_len + constants::netsync_hmac_value_length_in_bytes)
{
- inbuf.reserve(pos + payload_len + CryptoPP::SHA::DIGESTSIZE + constants::bufsz);
+ inbuf.reserve(pos + payload_len + constants::netsync_hmac_value_length_in_bytes + constants::bufsz);
return false;
}
// out.payload = extract_substring(inbuf, pos, payload_len, "netcmd payload");
// Do this ourselves, so we can swap the strings instead of copying.
require_bytes(inbuf, pos, payload_len, "netcmd payload");
+
+ // grab it before the data gets munged
+ string digest = hmac.process(inbuf, 0, pos + payload_len);
+
payload = inbuf.substr(pos + payload_len);
inbuf.erase(pos + payload_len, inbuf.npos);
inbuf.swap(payload);
@@ -158,26 +144,13 @@
pos = 0;
// they might have given us bogus data
- string cmd_digest = extract_substring(inbuf, pos, CryptoPP::SHA::DIGESTSIZE,
+ string cmd_digest = extract_substring(inbuf, pos,
+ constants::netsync_hmac_value_length_in_bytes,
"netcmd HMAC");
inbuf.erase(0, pos);
- I(key().size() == CryptoPP::SHA::DIGESTSIZE);
- I(key().size() == hmac_val().size());
- byte keybuf[CryptoPP::SHA::DIGESTSIZE];
- for (size_t i = 0; i < sizeof(keybuf); i++)
- {
- keybuf[i] = key()[i] ^ hmac_val()[i];
- }
- CryptoPP::HMAC hmac(keybuf, sizeof(keybuf));
- char digest_buf[CryptoPP::SHA::DIGESTSIZE];
- hmac.CalculateDigest(reinterpret_cast(digest_buf),
- reinterpret_cast(payload.data()),
- payload.size());
- string digest(digest_buf, sizeof(digest_buf));
if (cmd_digest != digest)
throw bad_decode(F("bad HMAC %s vs. %s") % encode_hexenc(cmd_digest)
% encode_hexenc(digest));
- hmac_val = netsync_hmac_value(digest);
payload.erase(0, payload_pos);
return true;
@@ -445,7 +418,13 @@
extract_variable_length_string(payload, dat, pos,
"data netcmd, data payload");
if (compressed_p == 1)
- dat = xform(dat);
+ {
+ gzip zdat;
+ data tdat;
+ zdat.swap(dat);
+ decode_gzip(zdat, tdat);
+ tdat.swap(dat);
+ }
assert_end_of_buffer(payload, pos, "data netcmd payload");
}
@@ -460,8 +439,10 @@
payload += item();
if (dat.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
{
+ gzip zdat;
+ encode_gzip(dat, zdat);
string tmp;
- tmp = xform(dat);
+ zdat.swap(tmp);
payload += static_cast(1); // compressed flag
insert_variable_length_string(tmp, payload);
}
@@ -493,8 +474,14 @@
extract_variable_length_string(payload, tmp, pos,
"delta netcmd, delta payload");
if (compressed_p == 1)
- tmp = xform(tmp);
- del = delta(tmp);
+ {
+ gzip zdel(tmp);
+ decode_gzip(zdel, del);
+ }
+ else
+ {
+ del = tmp;
+ }
assert_end_of_buffer(payload, pos, "delta netcmd payload");
}
@@ -510,16 +497,19 @@
payload += base();
payload += ident();
- string tmp = del();
+ string tmp;
if (tmp.size() > constants::netcmd_minimum_bytes_to_bother_with_gzip)
{
payload += static_cast(1); // compressed flag
- tmp = xform(tmp);
+ gzip zdel;
+ encode_gzip(del, zdel);
+ tmp = zdel();
}
else
{
payload += static_cast(0); // compressed flag
+ tmp = del();
}
I(tmp.size() <= constants::netcmd_payload_limit);
insert_variable_length_string(tmp, payload);
--- netcmd.hh
+++ netcmd.hh
@@ -12,6 +12,7 @@
#include "merkle_tree.hh"
#include "numeric_vocab.hh"
#include "vocab.hh"
+#include "hmac.hh"
typedef enum
{
@@ -63,10 +64,9 @@
// basic cmd i/o (including checksums)
void write(std::string & out,
- netsync_session_key const & key,
- netsync_hmac_value & hmac_val) const;
+ chained_hmac & hmac) const;
bool read(std::string & inbuf,
- netsync_session_key const & key, netsync_hmac_value & hmac_val);
+ chained_hmac & hmac);
// i/o functions for each type of command payload
void read_error_cmd(std::string & errmsg) const;
--- netsync.cc
+++ netsync.cc
@@ -32,6 +32,7 @@
#include "xdelta.hh"
#include "epoch.hh"
#include "platform.hh"
+#include "hmac.hh"
#include "cryptopp/osrng.h"
@@ -271,8 +272,8 @@
id remote_peer_key_hash;
rsa_keypair_id remote_peer_key_name;
netsync_session_key session_key;
- netsync_hmac_value read_hmac;
- netsync_hmac_value write_hmac;
+ chained_hmac read_hmac;
+ chained_hmac write_hmac;
bool authenticated;
time_t last_io_time;
@@ -321,6 +322,8 @@
id mk_nonce();
void mark_recent_io();
+ void set_session_key(string const & key);
+
void setup_client_tickers();
bool done_all_refinements();
@@ -629,6 +632,14 @@
}
void
+session::set_session_key(string const & key)
+{
+ session_key = netsync_session_key(key);
+ read_hmac.set_key(session_key);
+ write_hmac.set_key(session_key);
+}
+
+void
session::setup_client_tickers()
{
byte_in_ticker.reset(new ticker("bytes in", ">", 1024, true));
@@ -777,7 +788,7 @@
session::write_netcmd_and_try_flush(netcmd const & cmd)
{
if (!encountered_error)
- cmd.write(outbuf, session_key, write_hmac);
+ cmd.write(outbuf, write_hmac);
else
L(F("dropping outgoing netcmd (because we're in error unwind mode)\n"));
// FIXME: this helps keep the protocol pipeline full but it seems to
@@ -1422,7 +1433,7 @@
nonce2(), hmac_key_encrypted);
cmd.write_anonymous_cmd(role, pattern, hmac_key_encrypted);
write_netcmd_and_try_flush(cmd);
- session_key = netsync_session_key(nonce2());
+ set_session_key(nonce2());
}
void
@@ -1440,7 +1451,7 @@
nonce2(), hmac_key_encrypted);
cmd.write_auth_cmd(role, pattern, client, nonce1, hmac_key_encrypted, signature);
write_netcmd_and_try_flush(cmd);
- session_key = netsync_session_key(nonce2());
+ set_session_key(nonce2());
}
void
@@ -2043,7 +2054,7 @@
load_priv_key(app, app.signing_key, our_priv);
string hmac_key;
decrypt_rsa(app.lua, app.signing_key, our_priv, hmac_key_encrypted, hmac_key);
- session_key = netsync_session_key(hmac_key);
+ set_session_key(hmac_key);
queue_confirm_cmd();
}
@@ -3182,7 +3193,7 @@
{
if (!armed)
{
- if (cmd.read(inbuf, session_key, read_hmac))
+ if (cmd.read(inbuf, read_hmac))
{
// inbuf.erase(0, cmd.encoded_size());
armed = true;
--- transforms.hh
+++ transforms.hh
@@ -73,7 +73,12 @@
void decode_gzip(gzip const & in, T & out)
{ out = xform(in()); }
+// string variant for netsync
+template
+void encode_gzip(std::string const & in, gzip & out)
+{ out = xform(in); }
+#endif
// both at once (this is relatively common)
template