Initial import of Cobalt 2.8885 2016-07-27
diff --git a/src/net/quic/crypto/crypto_framer.cc b/src/net/quic/crypto/crypto_framer.cc
new file mode 100644
index 0000000..31c26cf
--- /dev/null
+++ b/src/net/quic/crypto/crypto_framer.cc
@@ -0,0 +1,183 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/crypto_framer.h"
+
+#include "net/quic/quic_data_reader.h"
+#include "net/quic/quic_data_writer.h"
+#include "net/quic/quic_protocol.h"
+
+using base::StringPiece;
+
+namespace net {
+
+namespace {
+
+const size_t kCryptoTagSize = sizeof(uint32);
+const size_t kNumEntriesSize = sizeof(uint16);
+const size_t kValueLenSize = sizeof(uint16);
+
+}  // namespace
+
+CryptoFramer::CryptoFramer()
+    : visitor_(NULL),
+      message_tag_(0),
+      num_entries_(0),
+      values_len_(0) {
+  Clear();
+}
+
+CryptoFramer::~CryptoFramer() {}
+
+bool CryptoFramer::ProcessInput(StringPiece input) {
+  DCHECK_EQ(QUIC_NO_ERROR, error_);
+  if (error_ != QUIC_NO_ERROR) {
+    return false;
+  }
+  // Add this data to the buffer.
+  buffer_.append(input.data(), input.length());
+  QuicDataReader reader(buffer_.data(), buffer_.length());
+
+  switch (state_) {
+    case STATE_READING_TAG:
+      if (reader.BytesRemaining() < kCryptoTagSize) {
+        break;
+      }
+      reader.ReadUInt32(&message_tag_);
+      state_ = STATE_READING_NUM_ENTRIES;
+    case STATE_READING_NUM_ENTRIES:
+      if (reader.BytesRemaining() < kNumEntriesSize) {
+        break;
+      }
+      reader.ReadUInt16(&num_entries_);
+      if (num_entries_ > kMaxEntries) {
+        error_ = QUIC_CRYPTO_TOO_MANY_ENTRIES;
+        return false;
+      }
+      state_ = STATE_READING_KEY_TAGS;
+    case STATE_READING_KEY_TAGS:
+      if (reader.BytesRemaining() < num_entries_ * kCryptoTagSize) {
+        break;
+      }
+      for (int i = 0; i < num_entries_; ++i) {
+        CryptoTag tag;
+        reader.ReadUInt32(&tag);
+        if (i > 0 && tag <= tags_.back()) {
+          error_ = QUIC_CRYPTO_TAGS_OUT_OF_ORDER;
+          return false;
+        }
+        tags_.push_back(tag);
+      }
+      state_ = STATE_READING_LENGTHS;
+    case STATE_READING_LENGTHS:
+      if (reader.BytesRemaining() < num_entries_ * kValueLenSize) {
+        break;
+      }
+      values_len_ = 0;
+      for (int i = 0; i < num_entries_; ++i) {
+        uint16 len;
+        reader.ReadUInt16(&len);
+        tag_length_map_[tags_[i]] = len;
+        values_len_ += len;
+        if (len == 0 && i != num_entries_ - 1) {
+          error_ = QUIC_CRYPTO_INVALID_VALUE_LENGTH;
+          return false;
+        }
+      }
+      state_ = STATE_READING_VALUES;
+    case STATE_READING_VALUES:
+      if (reader.BytesRemaining() < values_len_) {
+        break;
+      }
+      for (int i = 0; i < num_entries_; ++i) {
+        StringPiece value;
+        reader.ReadStringPiece(&value, tag_length_map_[tags_[i]]);
+        tag_value_map_[tags_[i]] = value;
+      }
+      CryptoHandshakeMessage message;
+      message.tag = message_tag_;
+      message.tag_value_map.swap(tag_value_map_);
+      visitor_->OnHandshakeMessage(message);
+      Clear();
+      state_ = STATE_READING_TAG;
+      break;
+  }
+  // Save any remaining data.
+  buffer_ = reader.PeekRemainingPayload().as_string();
+  return true;
+}
+
+QuicData* CryptoFramer::ConstructHandshakeMessage(
+    const CryptoHandshakeMessage& message) {
+  if (message.tag_value_map.size() > kMaxEntries) {
+    return NULL;
+  }
+  size_t len = sizeof(uint32);  // message tag
+  len += sizeof(uint16);  // number of map entries
+  CryptoTagValueMap::const_iterator it = message.tag_value_map.begin();
+  while (it != message.tag_value_map.end()) {
+    len += sizeof(uint32);  // tag
+    len += sizeof(uint16);  // value len
+    len += it->second.length(); // value
+    if (it->second.length() == 0) {
+      return NULL;
+    }
+    ++it;
+  }
+  if (message.tag_value_map.size() % 2 == 1) {
+    len += sizeof(uint16);  // padding
+  }
+
+  QuicDataWriter writer(len);
+  if (!writer.WriteUInt32(message.tag)) {
+    DCHECK(false) << "Failed to write message tag.";
+    return NULL;
+  }
+  if (!writer.WriteUInt16(message.tag_value_map.size())) {
+    DCHECK(false) << "Failed to write size.";
+    return NULL;
+  }
+  // Tags
+  for (it = message.tag_value_map.begin();
+       it != message.tag_value_map.end(); ++it) {
+    if (!writer.WriteUInt32(it->first)) {
+      DCHECK(false) << "Failed to write tag.";
+      return NULL;
+    }
+  }
+  // Lengths
+  for (it = message.tag_value_map.begin();
+       it != message.tag_value_map.end(); ++it) {
+    if (!writer.WriteUInt16(it->second.length())) {
+      DCHECK(false) << "Failed to write length.";
+      return NULL;
+    }
+  }
+  // Possible padding
+  if (message.tag_value_map.size() % 2 == 1) {
+    if (!writer.WriteUInt16(0xABAB)) {
+      DCHECK(false) << "Failed to write padding.";
+      return NULL;
+    }
+  }
+  // Values
+  for (it = message.tag_value_map.begin();
+       it != message.tag_value_map.end(); ++it) {
+    if (!writer.WriteBytes(it->second.data(), it->second.length())) {
+      DCHECK(false) << "Failed to write value.";
+      return NULL;
+    }
+  }
+  return new QuicData(writer.take(), len, true);
+}
+
+void CryptoFramer::Clear() {
+  tag_value_map_.clear();
+  tag_length_map_.clear();
+  tags_.clear();
+  error_ = QUIC_NO_ERROR;
+  state_ = STATE_READING_TAG;
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/crypto_framer.h b/src/net/quic/crypto/crypto_framer.h
new file mode 100644
index 0000000..cf61a9e
--- /dev/null
+++ b/src/net/quic/crypto/crypto_framer.h
@@ -0,0 +1,106 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
+#define NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/string_piece.h"
+#include "net/base/net_export.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class CryptoFramer;
+class QuicDataReader;
+class QuicData;
+
+class NET_EXPORT_PRIVATE CryptoFramerVisitorInterface {
+ public:
+  virtual ~CryptoFramerVisitorInterface() {}
+
+  // Called if an error is detected.
+  virtual void OnError(CryptoFramer* framer) = 0;
+
+  // Called when a complete handshake message has been parsed.
+  virtual void OnHandshakeMessage(
+      const CryptoHandshakeMessage& message) = 0;
+};
+
+// A class for framing the crypto message that are exchanged in a QUIC session.
+class NET_EXPORT_PRIVATE CryptoFramer {
+ public:
+  CryptoFramer();
+
+  virtual ~CryptoFramer();
+
+  // Set callbacks to be called from the framer.  A visitor must be set, or
+  // else the framer will crash.  It is acceptable for the visitor to do
+  // nothing.  If this is called multiple times, only the last visitor
+  // will be used.  |visitor| will be owned by the framer.
+  void set_visitor(CryptoFramerVisitorInterface* visitor) {
+    visitor_ = visitor;
+  }
+
+  QuicErrorCode error() const {
+    return error_;
+  }
+
+  // Processes input data, which must be delivered in order.  Returns
+  // false if there was an error, and true otherwise.
+  bool ProcessInput(base::StringPiece input);
+
+  // Returns a new QuicData owned by the caller that contains a serialized
+  // |message|, or NULL if there was an error.
+  QuicData* ConstructHandshakeMessage(const CryptoHandshakeMessage& message);
+
+ private:
+  // Clears per-message state.  Does not clear the visitor.
+  void Clear();
+
+  void set_error(QuicErrorCode error) {
+    error_ = error;
+  }
+
+  // Represents the current state of the framing state machine.
+  enum CryptoFramerState {
+    STATE_READING_TAG,
+    STATE_READING_NUM_ENTRIES,
+    STATE_READING_KEY_TAGS,
+    STATE_READING_LENGTHS,
+    STATE_READING_VALUES
+  };
+
+  // Visitor to invoke when messages are parsed.
+  CryptoFramerVisitorInterface* visitor_;
+  // Last error.
+  QuicErrorCode error_;
+  // Remaining unparsed data.
+  std::string buffer_;
+  // Current state of the parsing.
+  CryptoFramerState state_;
+  // Tag of the message currently being parsed.
+  CryptoTag message_tag_;
+  // Number of entires in the message currently being parsed.
+  uint16 num_entries_;
+  // Vector of tags in the message currently being parsed.
+  CryptoTagVector tags_;
+  // Length of the data associated with each tag in the message currently
+  // being parsed.
+  std::map<CryptoTag, size_t> tag_length_map_;
+  // Data associated with each tag in the message currently being parsed.
+  CryptoTagValueMap tag_value_map_;
+  // Cumulative length of all values in the message currently being parsed.
+  size_t values_len_;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_CRYPTO_FRAMER_H_
diff --git a/src/net/quic/crypto/crypto_framer_test.cc b/src/net/quic/crypto/crypto_framer_test.cc
new file mode 100644
index 0000000..eed175f
--- /dev/null
+++ b/src/net/quic/crypto/crypto_framer_test.cc
@@ -0,0 +1,303 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <map>
+#include <vector>
+
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "net/quic/crypto/crypto_framer.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+using std::map;
+using std::string;
+using std::vector;
+
+namespace net {
+
+namespace {
+
+char* AsChars(unsigned char* data) {
+  return reinterpret_cast<char*>(data);
+}
+
+}  // namespace
+
+namespace test {
+
+class TestCryptoVisitor : public ::net::CryptoFramerVisitorInterface {
+ public:
+  TestCryptoVisitor()
+      : error_count_(0) {
+  }
+
+  ~TestCryptoVisitor() {}
+
+  virtual void OnError(CryptoFramer* framer) {
+    LOG(ERROR) << "CryptoFramer Error: " << framer->error();
+    error_count_++;
+  }
+
+  virtual void OnHandshakeMessage(const CryptoHandshakeMessage& message) {
+    message_tags_.push_back(message.tag);
+    message_maps_.push_back(map<CryptoTag, string>());
+    CryptoTagValueMap::const_iterator it = message.tag_value_map.begin();
+    while (it != message.tag_value_map.end()) {
+      message_maps_.back()[it->first] = it->second.as_string();
+      ++it;
+    }
+  }
+
+  CryptoFramer framer_;
+
+  // Counters from the visitor callbacks.
+  int error_count_;
+
+  CryptoTagVector message_tags_;
+  vector<map<CryptoTag, string> > message_maps_;
+};
+
+}  // namespace test
+
+TEST(CryptoFramerTest, ConstructHandshakeMessage) {
+  CryptoHandshakeMessage message;
+  message.tag = 0xFFAA7733;
+  message.tag_value_map[0x12345678] = "abcdef";
+  message.tag_value_map[0x12345679] = "ghijk";
+  message.tag_value_map[0x1234567A] = "lmnopqr";
+
+  unsigned char packet[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0x03, 0x00,
+    // tag 1
+    0x78, 0x56, 0x34, 0x12,
+    // tag 2
+    0x79, 0x56, 0x34, 0x12,
+    // tag 3
+    0x7A, 0x56, 0x34, 0x12,
+    // len 1
+    0x06, 0x00,
+    // len 2
+    0x05, 0x00,
+    // len 3
+    0x07, 0x00,
+    // padding
+    0xAB, 0xAB,
+    // value 1
+    'a',  'b',  'c',  'd',
+    'e',  'f',
+    // value 2
+    'g',  'h',  'i',  'j',
+    'k',
+    // value 3
+    'l',  'm',  'n',  'o',
+    'p',  'q',  'r',
+  };
+
+  CryptoFramer framer;
+  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+  ASSERT_TRUE(data.get() != NULL);
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageWithTwoKeys) {
+  CryptoHandshakeMessage message;
+  message.tag = 0xFFAA7733;
+  message.tag_value_map[0x12345678] = "abcdef";
+  message.tag_value_map[0x12345679] = "ghijk";
+
+  unsigned char packet[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0x02, 0x00,
+    // tag 1
+    0x78, 0x56, 0x34, 0x12,
+    // tag 2
+    0x79, 0x56, 0x34, 0x12,
+    // len 1
+    0x06, 0x00,
+    // len 2
+    0x05, 0x00,
+    // value 1
+    'a',  'b',  'c',  'd',
+    'e',  'f',
+    // value 2
+    'g',  'h',  'i',  'j',
+    'k',
+  };
+
+  CryptoFramer framer;
+  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+  ASSERT_TRUE(data.get() != NULL);
+
+  test::CompareCharArraysWithHexError("constructed packet",
+                                      data->data(), data->length(),
+                                      AsChars(packet), arraysize(packet));
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) {
+  CryptoHandshakeMessage message;
+  message.tag = 0xFFAA7733;
+  for (uint32 key = 1; key <= kMaxEntries + 1; ++key) {
+    message.tag_value_map[key] = "abcdef";
+  }
+
+  CryptoFramer framer;
+  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+  EXPECT_TRUE(data.get() == NULL);
+}
+
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageInvalidLength) {
+  CryptoHandshakeMessage message;
+  message.tag = 0xFFAA7733;
+  message.tag_value_map[0x12345678] = "";
+
+  CryptoFramer framer;
+  scoped_ptr<QuicData> data(framer.ConstructHandshakeMessage(message));
+  EXPECT_TRUE(data.get() == NULL);
+}
+
+TEST(CryptoFramerTest, ProcessInput) {
+  test::TestCryptoVisitor visitor;
+  CryptoFramer framer;
+  framer.set_visitor(&visitor);
+
+  unsigned char input[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0x02, 0x00,
+    // tag 1
+    0x78, 0x56, 0x34, 0x12,
+    // tag 2
+    0x79, 0x56, 0x34, 0x12,
+    // len 1
+    0x06, 0x00,
+    // len 2
+    0x05, 0x00,
+    // value 1
+    'a',  'b',  'c',  'd',
+    'e',  'f',
+    // value 2
+    'g',  'h',  'i',  'j',
+    'k',
+  };
+
+  EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input),
+                                              arraysize(input))));
+  ASSERT_EQ(1u, visitor.message_tags_.size());
+  EXPECT_EQ(0xFFAA7733, visitor.message_tags_[0]);
+  EXPECT_EQ(2u, visitor.message_maps_[0].size());
+  EXPECT_EQ("abcdef",visitor.message_maps_[0][0x12345678]);
+  EXPECT_EQ("ghijk", visitor.message_maps_[0][0x12345679]);
+}
+
+TEST(CryptoFramerTest, ProcessInputIncrementally) {
+  test::TestCryptoVisitor visitor;
+  CryptoFramer framer;
+  framer.set_visitor(&visitor);
+
+  unsigned char input[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0x02, 0x00,
+    // tag 1
+    0x78, 0x56, 0x34, 0x12,
+    // tag 2
+    0x79, 0x56, 0x34, 0x12,
+    // len 1
+    0x06, 0x00,
+    // len 2
+    0x05, 0x00,
+    // value 1
+    'a',  'b',  'c',  'd',
+    'e',  'f',
+    // value 2
+    'g',  'h',  'i',  'j',
+    'k',
+  };
+
+  for (size_t i = 0; i < arraysize(input); i++) {
+    EXPECT_TRUE(framer.ProcessInput(StringPiece(AsChars(input)+ i, 1)));
+  }
+  ASSERT_EQ(1u, visitor.message_tags_.size());
+  EXPECT_EQ(0xFFAA7733, visitor.message_tags_[0]);
+  EXPECT_EQ(2u, visitor.message_maps_[0].size());
+  EXPECT_EQ("abcdef",visitor.message_maps_[0][0x12345678]);
+  EXPECT_EQ("ghijk", visitor.message_maps_[0][0x12345679]);
+}
+
+TEST(CryptoFramerTest, ProcessInputTagsOutOfOrder) {
+  test::TestCryptoVisitor visitor;
+  CryptoFramer framer;
+  framer.set_visitor(&visitor);
+
+  unsigned char input[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0x02, 0x00,
+    // tag 1
+    0x79, 0x56, 0x34, 0x12,
+    // tag 2
+    0x78, 0x56, 0x34, 0x12,
+  };
+
+  EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input),
+                                               arraysize(input))));
+  EXPECT_EQ(QUIC_CRYPTO_TAGS_OUT_OF_ORDER, framer.error());
+}
+
+TEST(CryptoFramerTest, ProcessInputTooManyEntries) {
+  test::TestCryptoVisitor visitor;
+  CryptoFramer framer;
+  framer.set_visitor(&visitor);
+
+  unsigned char input[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0xA0, 0x00,
+  };
+
+  EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input),
+                                               arraysize(input))));
+  EXPECT_EQ(QUIC_CRYPTO_TOO_MANY_ENTRIES, framer.error());
+}
+
+TEST(CryptoFramerTest, ProcessInputInvalidLength) {
+  test::TestCryptoVisitor visitor;
+  CryptoFramer framer;
+  framer.set_visitor(&visitor);
+
+  unsigned char input[] = {
+    // tag
+    0x33, 0x77, 0xAA, 0xFF,
+    // num entries
+    0x02, 0x00,
+    // tag 1
+    0x78, 0x56, 0x34, 0x12,
+    // tag 2
+    0x79, 0x56, 0x34, 0x12,
+    // len 1
+    0x00, 0x00,
+    // len 2
+    0x05, 0x00,
+  };
+
+  EXPECT_FALSE(framer.ProcessInput(StringPiece(AsChars(input),
+                                               arraysize(input))));
+  EXPECT_EQ(QUIC_CRYPTO_INVALID_VALUE_LENGTH, framer.error());
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/crypto_protocol.cc b/src/net/quic/crypto/crypto_protocol.cc
new file mode 100644
index 0000000..ba87906
--- /dev/null
+++ b/src/net/quic/crypto/crypto_protocol.cc
@@ -0,0 +1,12 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/crypto_protocol.h"
+
+namespace net {
+
+CryptoHandshakeMessage::CryptoHandshakeMessage() {}
+CryptoHandshakeMessage::~CryptoHandshakeMessage() {}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/crypto_protocol.h b/src/net/quic/crypto/crypto_protocol.h
new file mode 100644
index 0000000..7303c6b
--- /dev/null
+++ b/src/net/quic/crypto/crypto_protocol.h
@@ -0,0 +1,47 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
+#define NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
+
+#include <map>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/logging.h"
+#include "base/string_piece.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+typedef uint32 CryptoTag;
+typedef std::map<CryptoTag, base::StringPiece> CryptoTagValueMap;
+typedef std::vector<CryptoTag> CryptoTagVector;
+struct NET_EXPORT_PRIVATE CryptoHandshakeMessage {
+  CryptoHandshakeMessage();
+  ~CryptoHandshakeMessage();
+  CryptoTag tag;
+  CryptoTagValueMap tag_value_map;
+};
+
+// Crypto tags are written to the wire with a big-endian
+// representation of the name of the tag.  For example
+// the client hello tag (CHLO) will be written as the
+// following 4 bytes: 'C' 'H' 'L' 'O'.  Since it is
+// stored in memory as a little endian uint32, we need
+// to reverse the order of the bytes.
+#define MAKE_TAG(a, b, c, d) (d << 24) + (c << 16) + (b << 8) + a
+
+const CryptoTag kCHLO = MAKE_TAG('C', 'H', 'L', 'O');  // Client hello
+const CryptoTag kSHLO = MAKE_TAG('S', 'H', 'L', 'O');  // Server hello
+
+// AEAD algorithms
+const CryptoTag kNULL = MAKE_TAG('N', 'U', 'L', 'L');  // null algorithm
+const CryptoTag kAESH = MAKE_TAG('A', 'E', 'S', 'H');  // AES128 + SHA256
+
+const size_t kMaxEntries = 16;  // Max number of entries in a message.
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_CRYPTO_PROTOCOL_H_
diff --git a/src/net/quic/crypto/null_decrypter.cc b/src/net/quic/crypto/null_decrypter.cc
new file mode 100644
index 0000000..072c684
--- /dev/null
+++ b/src/net/quic/crypto/null_decrypter.cc
@@ -0,0 +1,35 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/null_decrypter.h"
+#include "net/quic/quic_utils.h"
+#include "net/quic/quic_data_reader.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+QuicData* NullDecrypter::Decrypt(StringPiece associated_data,
+                                 StringPiece ciphertext) {
+  QuicDataReader reader(ciphertext.data(), ciphertext.length());
+
+  uint128 hash;
+  if (!reader.ReadUInt128(&hash)) {
+    return NULL;
+  }
+
+  StringPiece plaintext = reader.ReadRemainingPayload();
+
+  // TODO(rch): avoid buffer copy here
+  string buffer = associated_data.as_string();
+  plaintext.AppendToString(&buffer);
+
+  if (hash != QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length())) {
+    return NULL;
+  }
+  return new QuicData(plaintext.data(), plaintext.length());
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/null_decrypter.h b/src/net/quic/crypto/null_decrypter.h
new file mode 100644
index 0000000..5495092
--- /dev/null
+++ b/src/net/quic/crypto/null_decrypter.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
+
+#include "base/compiler_specific.h"
+#include "net/base/net_export.h"
+#include "net/quic/crypto/quic_decrypter.h"
+
+namespace net {
+
+// A NullDecrypter is a QuicDecrypter used before a crypto negotiation
+// has occurred.  It does not actually decrypt the payload, but does
+// verify a hash (fnv128) over both the payload and associated data.
+class NET_EXPORT_PRIVATE NullDecrypter : public QuicDecrypter {
+ public:
+  virtual ~NullDecrypter() {}
+
+  // QuicDecrypter implementation
+  virtual QuicData* Decrypt(base::StringPiece associated_data,
+                            base::StringPiece ciphertext) OVERRIDE;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_NULL_DECRYPTER_H_
diff --git a/src/net/quic/crypto/null_decrypter_test.cc b/src/net/quic/crypto/null_decrypter_test.cc
new file mode 100644
index 0000000..ad73cea
--- /dev/null
+++ b/src/net/quic/crypto/null_decrypter_test.cc
@@ -0,0 +1,69 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/null_decrypter.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+namespace test {
+
+TEST(NullDecrypterTest, Decrypt) {
+  unsigned char expected[] = {
+    // fnv hash
+    0x47, 0x11, 0xea, 0x5f,
+    0xcf, 0x1d, 0x66, 0x5b,
+    0xba, 0xf0, 0xbc, 0xfd,
+    0x88, 0x79, 0xca, 0x37,
+    // payload
+    'g',  'o',  'o',  'd',
+    'b',  'y',  'e',  '!',
+  };
+  NullDecrypter decrypter;
+  scoped_ptr<QuicData> decrypted(
+      decrypter.Decrypt("hello world!",
+                        StringPiece(reinterpret_cast<const char*>(expected),
+                                    arraysize(expected))));
+  ASSERT_TRUE(decrypted.get());
+  EXPECT_EQ("goodbye!", decrypted->AsStringPiece());
+}
+
+TEST(NullDecrypterTest, BadHash) {
+  unsigned char expected[] = {
+    // fnv hash
+    0x46, 0x11, 0xea, 0x5f,
+    0xcf, 0x1d, 0x66, 0x5b,
+    0xba, 0xf0, 0xbc, 0xfd,
+    0x88, 0x79, 0xca, 0x37,
+    // payload
+    'g',  'o',  'o',  'd',
+    'b',  'y',  'e',  '!',
+  };
+  NullDecrypter decrypter;
+  scoped_ptr<QuicData> decrypted(
+      decrypter.Decrypt("hello world!",
+                        StringPiece(reinterpret_cast<const char*>(expected),
+                                    arraysize(expected))));
+  ASSERT_FALSE(decrypted.get());
+}
+
+TEST(NullDecrypterTest, ShortInput) {
+  unsigned char expected[] = {
+    // fnv hash (truncated)
+    0x46, 0x11, 0xea, 0x5f,
+    0xcf, 0x1d, 0x66, 0x5b,
+    0xba, 0xf0, 0xbc, 0xfd,
+    0x88, 0x79, 0xca,
+  };
+  NullDecrypter decrypter;
+  scoped_ptr<QuicData> decrypted(
+      decrypter.Decrypt("hello world!",
+                        StringPiece(reinterpret_cast<const char*>(expected),
+                                    arraysize(expected))));
+  ASSERT_FALSE(decrypted.get());
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/src/net/quic/crypto/null_encrypter.cc b/src/net/quic/crypto/null_encrypter.cc
new file mode 100644
index 0000000..fda844b
--- /dev/null
+++ b/src/net/quic/crypto/null_encrypter.cc
@@ -0,0 +1,37 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/null_encrypter.h"
+#include "net/quic/quic_data_writer.h"
+#include "net/quic/quic_utils.h"
+
+using base::StringPiece;
+using std::string;
+
+namespace net {
+
+const size_t kHashSize = 16;  // size of uint128 serialized
+
+QuicData* NullEncrypter::Encrypt(StringPiece associated_data,
+                                 StringPiece plaintext) {
+  // TODO(rch): avoid buffer copy here
+  string buffer = associated_data.as_string();
+  plaintext.AppendToString(&buffer);
+  uint128 hash = QuicUtils::FNV1a_128_Hash(buffer.data(), buffer.length());
+  QuicDataWriter writer(plaintext.length() + kHashSize);
+  writer.WriteUInt128(hash);
+  writer.WriteBytes(plaintext.data(), plaintext.length());
+  size_t len = writer.length();
+  return new QuicData(writer.take(), len, true);
+}
+
+size_t NullEncrypter::GetMaxPlaintextSize(size_t ciphertext_size) {
+  return ciphertext_size - kHashSize;
+}
+
+size_t NullEncrypter::GetCiphertextSize(size_t plaintext_size) {
+  return plaintext_size + kHashSize;
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/null_encrypter.h b/src/net/quic/crypto/null_encrypter.h
new file mode 100644
index 0000000..e73423d
--- /dev/null
+++ b/src/net/quic/crypto/null_encrypter.h
@@ -0,0 +1,30 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
+
+#include "base/compiler_specific.h"
+#include "net/base/net_export.h"
+#include "net/quic/crypto/quic_encrypter.h"
+
+namespace net {
+
+// A NullEncrypter is a QuicEncrypter used before a crypto negotiation
+// has occurred.  It does not actually encrypt the payload, but does
+// generate a MAC (fnv128) over both the payload and associated data.
+class NET_EXPORT_PRIVATE NullEncrypter : public QuicEncrypter {
+ public:
+  virtual ~NullEncrypter() {}
+
+  // QuicEncrypter implementation
+  virtual QuicData* Encrypt(base::StringPiece associated_data,
+                            base::StringPiece plaintext) OVERRIDE;
+  virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) OVERRIDE;
+  virtual size_t GetCiphertextSize(size_t plaintext_size) OVERRIDE;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_NULL_ENCRYPTER_H_
diff --git a/src/net/quic/crypto/null_encrypter_test.cc b/src/net/quic/crypto/null_encrypter_test.cc
new file mode 100644
index 0000000..9f2cec2
--- /dev/null
+++ b/src/net/quic/crypto/null_encrypter_test.cc
@@ -0,0 +1,48 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/null_encrypter.h"
+#include "net/quic/test_tools/quic_test_utils.h"
+
+using base::StringPiece;
+
+namespace net {
+namespace test {
+
+TEST(NullEncrypterTest, Encrypt) {
+  unsigned char expected[] = {
+    // fnv hash
+    0x47, 0x11, 0xea, 0x5f,
+    0xcf, 0x1d, 0x66, 0x5b,
+    0xba, 0xf0, 0xbc, 0xfd,
+    0x88, 0x79, 0xca, 0x37,
+    // payload
+    'g',  'o',  'o',  'd',
+    'b',  'y',  'e',  '!',
+  };
+  NullEncrypter encrypter;
+  scoped_ptr<QuicData> encrypted(encrypter.Encrypt("hello world!",
+                                                   "goodbye!"));
+  ASSERT_TRUE(encrypted.get());
+  test::CompareCharArraysWithHexError(
+      "encrypted data", encrypted->data(), encrypted->length(),
+      reinterpret_cast<const char*>(expected), arraysize(expected));
+}
+
+TEST(NullEncrypterTest, GetMaxPlaintextSize) {
+  NullEncrypter encrypter;
+  EXPECT_EQ(1000u, encrypter.GetMaxPlaintextSize(1016));
+  EXPECT_EQ(100u, encrypter.GetMaxPlaintextSize(116));
+  EXPECT_EQ(10u, encrypter.GetMaxPlaintextSize(26));
+}
+
+TEST(NullEncrypterTest, GetCiphertextSize) {
+  NullEncrypter encrypter;
+  EXPECT_EQ(1016u, encrypter.GetCiphertextSize(1000));
+  EXPECT_EQ(116u, encrypter.GetCiphertextSize(100));
+  EXPECT_EQ(26u, encrypter.GetCiphertextSize(10));
+}
+
+}  // namespace test
+}  // namespace net
diff --git a/src/net/quic/crypto/quic_decrypter.cc b/src/net/quic/crypto/quic_decrypter.cc
new file mode 100644
index 0000000..997a311
--- /dev/null
+++ b/src/net/quic/crypto/quic_decrypter.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/quic_decrypter.h"
+#include "net/quic/crypto/null_decrypter.h"
+
+namespace net {
+
+// static
+QuicDecrypter* QuicDecrypter::Create(CryptoTag algorithm) {
+  switch (algorithm) {
+    case kNULL:
+      return new NullDecrypter();
+    default:
+      LOG(FATAL) << "Unsupported algorithm: " << algorithm;
+      return NULL;
+  }
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/quic_decrypter.h b/src/net/quic/crypto/quic_decrypter.h
new file mode 100644
index 0000000..e5c5635
--- /dev/null
+++ b/src/net/quic/crypto/quic_decrypter.h
@@ -0,0 +1,28 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
+#define NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
+
+#include "net/base/net_export.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicDecrypter {
+ public:
+  virtual ~QuicDecrypter() {}
+
+  static QuicDecrypter* Create(CryptoTag algorithm);
+
+  // Returns a newly created QuicData object containing the decrypted
+  // |ciphertext| or NULL if there is an error.
+  virtual QuicData* Decrypt(base::StringPiece associated_data,
+                            base::StringPiece ciphertext) = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_QUIC_DECRYPTER_H_
diff --git a/src/net/quic/crypto/quic_encrypter.cc b/src/net/quic/crypto/quic_encrypter.cc
new file mode 100644
index 0000000..cc13013
--- /dev/null
+++ b/src/net/quic/crypto/quic_encrypter.cc
@@ -0,0 +1,21 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/quic_encrypter.h"
+#include "net/quic/crypto/null_encrypter.h"
+
+namespace net {
+
+// static
+QuicEncrypter* QuicEncrypter::Create(CryptoTag algorithm) {
+  switch (algorithm) {
+    case kNULL:
+      return new NullEncrypter();
+    default:
+      LOG(FATAL) << "Unsupported algorithm: " << algorithm;
+      return NULL;
+  }
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/quic_encrypter.h b/src/net/quic/crypto/quic_encrypter.h
new file mode 100644
index 0000000..f077c1f
--- /dev/null
+++ b/src/net/quic/crypto/quic_encrypter.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
+#define NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
+
+#include "net/base/net_export.h"
+#include "net/quic/crypto/crypto_protocol.h"
+#include "net/quic/quic_protocol.h"
+
+namespace net {
+
+class NET_EXPORT_PRIVATE QuicEncrypter {
+ public:
+  virtual ~QuicEncrypter() {}
+
+  static QuicEncrypter* Create(CryptoTag algorithm);
+
+  // Returns a newly created QuicData object containing the encrypted
+  // |plaintext| as well as a MAC over both |plaintext| and |associated_data|,
+  // or NULL if there is an error.
+  virtual QuicData* Encrypt(base::StringPiece associated_data,
+                            base::StringPiece plaintext) = 0;
+
+  // Returns the maximum length of plaintext that can be encrypted
+  // to ciphertext no larger than |ciphertext_size|.
+  virtual size_t GetMaxPlaintextSize(size_t ciphertext_size) = 0;
+
+  // Returns the length of the ciphertext that would be generated by encrypting
+  // to plaintext of size |plaintext_size|.
+  virtual size_t GetCiphertextSize(size_t plaintext_size) = 0;
+
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_QUIC_ENCRYPTER_H_
diff --git a/src/net/quic/crypto/quic_random.cc b/src/net/quic/crypto/quic_random.cc
new file mode 100644
index 0000000..579ebec
--- /dev/null
+++ b/src/net/quic/crypto/quic_random.cc
@@ -0,0 +1,60 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/quic_random.h"
+
+#include "base/logging.h"
+#include "base/memory/singleton.h"
+#include "crypto/random.h"
+
+namespace net {
+
+namespace {
+
+class DefaultRandom : public QuicRandom {
+ public:
+  static DefaultRandom* GetInstance();
+
+  // QuicRandom implementation
+  virtual void RandBytes(void* data, size_t len);
+  virtual uint64 RandUint64();
+  virtual void Reseed(const void* additional_entropy, size_t entropy_len);
+
+ private:
+  DefaultRandom();
+  virtual ~DefaultRandom() {}
+
+  friend struct DefaultSingletonTraits<DefaultRandom>;
+  DISALLOW_COPY_AND_ASSIGN(DefaultRandom);
+};
+
+DefaultRandom* DefaultRandom::GetInstance() {
+  return Singleton<DefaultRandom>::get();
+}
+
+void DefaultRandom::RandBytes(void* data, size_t len) {
+  crypto::RandBytes(data, len);
+}
+
+uint64 DefaultRandom::RandUint64() {
+  uint64 value;
+  RandBytes(&value, sizeof(value));
+  return value;
+}
+
+void DefaultRandom::Reseed(const void* additional_entropy, size_t entropy_len) {
+  // No such function exists in crypto/random.h.
+}
+
+DefaultRandom::DefaultRandom() {
+}
+
+}  // namespace
+
+// static
+QuicRandom* QuicRandom::GetInstance() {
+  return DefaultRandom::GetInstance();
+}
+
+}  // namespace net
diff --git a/src/net/quic/crypto/quic_random.h b/src/net/quic/crypto/quic_random.h
new file mode 100644
index 0000000..ac69b85
--- /dev/null
+++ b/src/net/quic/crypto/quic_random.h
@@ -0,0 +1,38 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef NET_QUIC_CRYPTO_QUIC_RANDOM_H_
+#define NET_QUIC_CRYPTO_QUIC_RANDOM_H_
+
+#include <stddef.h>
+
+#include "base/basictypes.h"
+#include "net/base/net_export.h"
+
+namespace net {
+
+// The interface for a random number generator.
+class NET_EXPORT_PRIVATE QuicRandom {
+ public:
+  virtual ~QuicRandom() {}
+
+  // Returns the default random number generator, which is cryptographically
+  // secure and thread-safe.
+  static QuicRandom* GetInstance();
+
+  // Generates |len| random bytes in the |data| buffer.
+  virtual void RandBytes(void* data, size_t len) = 0;
+
+  // Returns a random number in the range [0, kuint64max].
+  virtual uint64 RandUint64() = 0;
+
+  // Reseeds the random number generator with additional entropy input.
+  // NOTE: the constructor of a QuicRandom object is responsible for seeding
+  // itself with enough entropy input.
+  virtual void Reseed(const void* additional_entropy, size_t entropy_len) = 0;
+};
+
+}  // namespace net
+
+#endif  // NET_QUIC_CRYPTO_QUIC_RANDOM_H_
diff --git a/src/net/quic/crypto/quic_random_test.cc b/src/net/quic/crypto/quic_random_test.cc
new file mode 100644
index 0000000..425089a
--- /dev/null
+++ b/src/net/quic/crypto/quic_random_test.cc
@@ -0,0 +1,40 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "net/quic/crypto/quic_random.h"
+
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace net {
+namespace test {
+
+TEST(QuicRandomTest, RandBytes) {
+  unsigned char buf1[16];
+  unsigned char buf2[16];
+  memset(buf1, 0xaf, sizeof(buf1));
+  memset(buf2, 0xaf, sizeof(buf2));
+  ASSERT_TRUE(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+
+  QuicRandom* rng = QuicRandom::GetInstance();
+  rng->RandBytes(buf1, sizeof(buf1));
+  EXPECT_FALSE(memcmp(buf1, buf2, sizeof(buf1)) == 0);
+}
+
+TEST(QuicRandomTest, RandUint64) {
+  QuicRandom* rng = QuicRandom::GetInstance();
+  uint64 value1 = rng->RandUint64();
+  uint64 value2 = rng->RandUint64();
+  EXPECT_NE(value1, value2);
+}
+
+TEST(QuicRandomTest, Reseed) {
+  char buf[1024];
+  memset(buf, 0xaf, sizeof(buf));
+
+  QuicRandom* rng = QuicRandom::GetInstance();
+  rng->Reseed(buf, sizeof(buf));
+}
+
+}  // namespace test
+}  // namespace net