summaryrefslogtreecommitdiffstats
path: root/net/quic/crypto
diff options
context:
space:
mode:
Diffstat (limited to 'net/quic/crypto')
-rw-r--r--net/quic/crypto/crypto_framer.cc156
-rw-r--r--net/quic/crypto/crypto_framer.h106
-rw-r--r--net/quic/crypto/crypto_framer_test.cc316
-rw-r--r--net/quic/crypto/crypto_protocol.cc12
-rw-r--r--net/quic/crypto/crypto_protocol.h45
-rw-r--r--net/quic/crypto/null_decrypter.cc35
-rw-r--r--net/quic/crypto/null_decrypter.h28
-rw-r--r--net/quic/crypto/null_decrypter_test.cc77
-rw-r--r--net/quic/crypto/null_encrypter.cc37
-rw-r--r--net/quic/crypto/null_encrypter.h30
-rw-r--r--net/quic/crypto/null_encrypter_test.cc56
-rw-r--r--net/quic/crypto/quic_decrypter.cc21
-rw-r--r--net/quic/crypto/quic_decrypter.h28
-rw-r--r--net/quic/crypto/quic_encrypter.cc21
-rw-r--r--net/quic/crypto/quic_encrypter.h38
15 files changed, 1006 insertions, 0 deletions
diff --git a/net/quic/crypto/crypto_framer.cc b/net/quic/crypto/crypto_framer.cc
new file mode 100644
index 0000000..806b336
--- /dev/null
+++ b/net/quic/crypto/crypto_framer.cc
@@ -0,0 +1,156 @@
+// 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 {
+
+CryptoFramer::CryptoFramer()
+ : visitor_(NULL) {
+ 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() < sizeof(uint32)) {
+ break;
+ }
+ reader.ReadUInt32(&message_tag_);
+ state_ = STATE_READING_NUM_ENTRIES;
+ case STATE_READING_NUM_ENTRIES:
+ if (reader.BytesRemaining() < sizeof(uint16)) {
+ 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_ * sizeof(uint32)) {
+ 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_ * sizeof(uint16)) {
+ 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 left over data
+ buffer_ = reader.PeekRemainingPayload().as_string();
+ return true;
+}
+
+bool CryptoFramer::ConstructHandshakeMessage(
+ const CryptoHandshakeMessage& message,
+ QuicData** packet) {
+ if (message.tag_value_map.size() > kMaxEntries) {
+ return false;
+ }
+ 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 false;
+ }
+ ++it;
+ }
+ if (message.tag_value_map.size() % 2 == 1) {
+ len += sizeof(uint16); // padding
+ }
+
+ QuicDataWriter writer(len);
+ CHECK(writer.WriteUInt32(message.tag));
+ CHECK(writer.WriteUInt16(message.tag_value_map.size()));
+ // Tags
+ for (it = message.tag_value_map.begin();
+ it != message.tag_value_map.end(); ++it) {
+ CHECK(writer.WriteUInt32(it->first));
+ }
+ // Lengths
+ for (it = message.tag_value_map.begin();
+ it != message.tag_value_map.end(); ++it) {
+ CHECK(writer.WriteUInt16(it->second.length()));
+ }
+ // Possible padding
+ if (message.tag_value_map.size() % 2 == 1) {
+ CHECK(writer.WriteUInt16(0xABAB));
+ }
+ // Values
+ for (it = message.tag_value_map.begin();
+ it != message.tag_value_map.end(); ++it) {
+ CHECK(writer.WriteBytes(it->second.data(), it->second.length()));
+ }
+ *packet = new QuicData(writer.take(), len, true);
+ return 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/net/quic/crypto/crypto_framer.h b/net/quic/crypto/crypto_framer.h
new file mode 100644
index 0000000..e52b264
--- /dev/null
+++ b/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 likely 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 delievered in order. Returns
+ // false if there was an error, and true otherwise.
+ bool ProcessInput(base::StringPiece input);
+
+ // Serializes |message| into |packet|. Returns false if there was an
+ // error, and true otherwise.
+ bool ConstructHandshakeMessage(const CryptoHandshakeMessage& message,
+ QuicData** packet);
+
+ private:
+ // Clears per-message state. Does not clear the visitor.
+ void Clear();
+
+ void set_error(QuicErrorCode error) {
+ error_ = error;
+ }
+
+ enum CryptoFramerState {
+ STATE_READING_TAG,
+ STATE_READING_NUM_ENTRIES,
+ STATE_READING_KEY_TAGS,
+ STATE_READING_LENGTHS,
+ STATE_READING_VALUES
+ };
+
+ // Visitor to send 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.
+ std::vector<CryptoTag> tags_;
+ // Length of the data associated with each tag in the message currently
+ // being parsed.
+ std::map<CryptoTag, size_t> tag_length_map_;
+ // Length of the 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/net/quic/crypto/crypto_framer_test.cc b/net/quic/crypto/crypto_framer_test.cc
new file mode 100644
index 0000000..8a32f26
--- /dev/null
+++ b/net/quic/crypto/crypto_framer_test.cc
@@ -0,0 +1,316 @@
+// 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* f) {
+ LOG(INFO) << "CryptoFramer Error: " << f->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_;
+
+ vector<CryptoTag> 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 entires
+ 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;
+ QuicData* data;
+ EXPECT_TRUE(framer.ConstructHandshakeMessage(message, &data));
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+
+ delete data;
+}
+
+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 entires
+ 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;
+ QuicData* data;
+ EXPECT_TRUE(framer.ConstructHandshakeMessage(message, &data));
+
+ test::CompareCharArraysWithHexError("constructed packet",
+ data->data(), data->length(),
+ AsChars(packet), arraysize(packet));
+
+ delete data;
+}
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageTooManyEntries) {
+ CryptoHandshakeMessage message;
+ message.tag = 0xFFAA7733;
+ for (uint32 key = 1; key <= kMaxEntries + 1; key++) {
+ message.tag_value_map[key] = "abcdef";
+ }
+
+ CryptoFramer framer;
+ QuicData* data = NULL;
+ EXPECT_FALSE(framer.ConstructHandshakeMessage(message, &data));
+ delete data;
+}
+
+
+TEST(CryptoFramerTest, ConstructHandshakeMessageInvalidLength) {
+ CryptoHandshakeMessage message;
+ message.tag = 0xFFAA7733;
+ message.tag_value_map[0x12345678] = "";
+
+ CryptoFramer framer;
+ QuicData* data = NULL;
+ EXPECT_FALSE(framer.ConstructHandshakeMessage(message, &data));
+ delete data;
+}
+
+TEST(CryptoFramerTest, EmptyPacket) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+}
+
+TEST(CryptoFramerTest, ProcessInput) {
+ test::TestCryptoVisitor visitor;
+ CryptoFramer framer;
+ framer.set_visitor(&visitor);
+
+ unsigned char input[] = {
+ // tag
+ 0x33, 0x77, 0xAA, 0xFF,
+ // num entires
+ 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 entires
+ 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 entires
+ 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 entires
+ 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 entires
+ 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/net/quic/crypto/crypto_protocol.cc b/net/quic/crypto/crypto_protocol.cc
new file mode 100644
index 0000000..ba87906
--- /dev/null
+++ b/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/net/quic/crypto/crypto_protocol.h b/net/quic/crypto/crypto_protocol.h
new file mode 100644
index 0000000..a9c7083
--- /dev/null
+++ b/net/quic/crypto/crypto_protocol.h
@@ -0,0 +1,45 @@
+// 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 "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;
+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/net/quic/crypto/null_decrypter.cc b/net/quic/crypto/null_decrypter.cc
new file mode 100644
index 0000000..072c684
--- /dev/null
+++ b/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/net/quic/crypto/null_decrypter.h b/net/quic/crypto/null_decrypter.h
new file mode 100644
index 0000000..5495092
--- /dev/null
+++ b/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/net/quic/crypto/null_decrypter_test.cc b/net/quic/crypto/null_decrypter_test.cc
new file mode 100644
index 0000000..6c914d7
--- /dev/null
+++ b/net/quic/crypto/null_decrypter_test.cc
@@ -0,0 +1,77 @@
+// 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
+ 0x07, 0x2d, 0x42, 0xf0,
+ 0xbe, 0x69, 0x12, 0x3d,
+ 0x20, 0x80, 0x5f, 0x9a,
+ 0x84, 0x9d, 0xd6, 0x0a,
+ /* TODO(rch): replace this when uint128 multiplication is implemented.
+ 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/net/quic/crypto/null_encrypter.cc b/net/quic/crypto/null_encrypter.cc
new file mode 100644
index 0000000..fda844b
--- /dev/null
+++ b/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/net/quic/crypto/null_encrypter.h b/net/quic/crypto/null_encrypter.h
new file mode 100644
index 0000000..e73423d
--- /dev/null
+++ b/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/net/quic/crypto/null_encrypter_test.cc b/net/quic/crypto/null_encrypter_test.cc
new file mode 100644
index 0000000..a71ee34
--- /dev/null
+++ b/net/quic/crypto/null_encrypter_test.cc
@@ -0,0 +1,56 @@
+// 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
+ 0x07, 0x2d, 0x42, 0xf0,
+ 0xbe, 0x69, 0x12, 0x3d,
+ 0x20, 0x80, 0x5f, 0x9a,
+ 0x84, 0x9d, 0xd6, 0x0a,
+ /* TODO(rch): use this when uint128 multiplication is implemented.
+ 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/net/quic/crypto/quic_decrypter.cc b/net/quic/crypto/quic_decrypter.cc
new file mode 100644
index 0000000..997a311
--- /dev/null
+++ b/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/net/quic/crypto/quic_decrypter.h b/net/quic/crypto/quic_decrypter.h
new file mode 100644
index 0000000..e5c5635
--- /dev/null
+++ b/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/net/quic/crypto/quic_encrypter.cc b/net/quic/crypto/quic_encrypter.cc
new file mode 100644
index 0000000..cc13013
--- /dev/null
+++ b/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/net/quic/crypto/quic_encrypter.h b/net/quic/crypto/quic_encrypter.h
new file mode 100644
index 0000000..f077c1f
--- /dev/null
+++ b/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_