From f8c2222774a3f89f717af8e19bda25f226fef1bc Mon Sep 17 00:00:00 2001 From: Ian Gulliver Date: Sat, 7 Feb 2015 10:35:29 -0800 Subject: [PATCH] Successful decrypt of client handshake! --- crypto.cc | 53 ++++++++++++++++++++++++++++++++++++++++++++++++----- crypto.h | 1 + tlv.cc | 48 +++++++++++++++++++++++++++++++++++++----------- tlv.h | 10 +++++++--- 4 files changed, 93 insertions(+), 19 deletions(-) diff --git a/crypto.cc b/crypto.cc index 477478a..931a1cb 100644 --- a/crypto.cc +++ b/crypto.cc @@ -45,6 +45,9 @@ void CryptoBase::DerivePublicKey(const std::string& secret_key, std::string* pub } void CryptoBase::EncodeEncryptAppend(const std::string& secret_key, const std::string& public_key, const TLVNode& input, TLVNode* container) { + assert(secret_key.length() == crypto_box_SECRETKEYBYTES); + assert(public_key.length() == crypto_box_PUBLICKEYBYTES); + std::string encoded; input.Encode(&encoded); @@ -56,13 +59,38 @@ void CryptoBase::EncodeEncryptAppend(const std::string& secret_key, const std::s unsigned char output[encrypted_bytes]; assert(!crypto_box_easy(output, (const unsigned char*)encoded.data(), encoded.length(), nonce, (const unsigned char*)public_key.data(), (const unsigned char*)secret_key.data())); - TLVNode encrypted(TLV_TYPE_ENCRYPTED); - encrypted.AppendChild(TLVNode(TLV_TYPE_NONCE, std::string((char*)nonce, crypto_box_NONCEBYTES))); - encrypted.AppendChild(TLVNode(TLV_TYPE_ENCRYPTED_BLOB, std::string((char*)output, encrypted_bytes))); + auto encrypted = new TLVNode(TLV_TYPE_ENCRYPTED); + encrypted->AppendChild(new TLVNode(TLV_TYPE_NONCE, std::string((char*)nonce, crypto_box_NONCEBYTES))); + encrypted->AppendChild(new TLVNode(TLV_TYPE_ENCRYPTED_BLOB, std::string((char*)output, encrypted_bytes))); container->AppendChild(encrypted); } +TLVNode* CryptoBase::DecryptDecode(const std::string& secret_key, const std::string& public_key, const TLVNode& input) { + assert(secret_key.length() == crypto_box_SECRETKEYBYTES); + assert(public_key.length() == crypto_box_PUBLICKEYBYTES); + assert(input.GetType() == TLV_TYPE_ENCRYPTED); + + auto nonce = input.FindChild(TLV_TYPE_NONCE); + if (!nonce || nonce->GetValue().length() != crypto_box_NONCEBYTES) { + return nullptr; + } + auto encrypted = input.FindChild(TLV_TYPE_ENCRYPTED_BLOB); + if (!encrypted || encrypted->GetValue().length() < crypto_box_MACBYTES) { + return nullptr; + } + + size_t decrypted_bytes = encrypted->GetValue().length() - crypto_box_MACBYTES; + + unsigned char output[decrypted_bytes]; + if (crypto_box_open_easy(output, (const unsigned char*)encrypted->GetValue().data(), encrypted->GetValue().length(), (const unsigned char*)nonce->GetValue().data(), (const unsigned char*)public_key.data(), (const unsigned char*)secret_key.data())) { + std::cerr << "Decryption failure" << std::endl; + return nullptr; + } + + return TLVNode::Decode(std::string((char*)output, decrypted_bytes)); +} + CryptoPubServer::CryptoPubServer(const std::string& secret_key) : secret_key_(secret_key), @@ -132,6 +160,21 @@ void CryptoPubServerConnection::OnReadable() { return; } std::cerr << "successful decode" << std::endl; + auto client_public_key = decoded->FindChild(TLV_TYPE_PUBLIC_KEY); + if (!client_public_key || client_public_key->GetValue().length() != crypto_box_PUBLICKEYBYTES) { + std::cerr << "Wanted " << crypto_box_PUBLICKEYBYTES << ", got " << client_public_key->GetValue().length() << " bytes" << std::endl; + return; + } + auto encrypted = decoded->FindChild(TLV_TYPE_ENCRYPTED); + if (!encrypted) { + return; + } + + std::unique_ptr decrypted(DecryptDecode(secret_key_, client_public_key->GetValue(), *encrypted)); + if (!decrypted.get()) { + return; + } + std::cerr << "successful decrypt" << std::endl; } void CryptoPubServerConnection::OnError_(struct bufferevent* bev, const short what, void* this__) { @@ -197,9 +240,9 @@ void CryptoPubClient::OnConnect() { GenKeyPair(&ephemeral_secret_key_, &ephemeral_public_key); TLVNode handshake(TLV_TYPE_CLIENT_HANDSHAKE); - handshake.AppendChild(TLVNode(TLV_TYPE_PUBLIC_KEY, public_key_)); + handshake.AppendChild(new TLVNode(TLV_TYPE_PUBLIC_KEY, public_key_)); TLVNode secure_handshake(TLV_TYPE_CLIENT_HANDSHAKE_SECURE); - secure_handshake.AppendChild(TLVNode(TLV_TYPE_PUBLIC_KEY, ephemeral_public_key)); + secure_handshake.AppendChild(new TLVNode(TLV_TYPE_PUBLIC_KEY, ephemeral_public_key)); EncodeEncryptAppend(secret_key_, server_public_key_, secure_handshake, &handshake); std::string out; diff --git a/crypto.h b/crypto.h index 03e2078..cdd23f5 100644 --- a/crypto.h +++ b/crypto.h @@ -14,6 +14,7 @@ class CryptoBase { static void GenKeyPair(std::string* secret_key, std::string* public_key); static void DerivePublicKey(const std::string& secret_key, std::string* public_key); static void EncodeEncryptAppend(const std::string& secret_key, const std::string& public_key, const TLVNode& input, TLVNode* container); + TLVNode *DecryptDecode(const std::string& secret_key, const std::string& public_key, const TLVNode& input); }; class CryptoPubServerConnection; diff --git a/tlv.cc b/tlv.cc index 2402679..108b407 100644 --- a/tlv.cc +++ b/tlv.cc @@ -15,6 +15,12 @@ TLVNode::TLVNode(const uint16_t type, const std::string value) : type_(type), value_(value) {} +TLVNode::~TLVNode() { + for (auto child : children_) { + delete child; + } +} + void TLVNode::Encode(std::string *output) const { assert(value_.length() <= UINT16_MAX); struct header header = { @@ -26,7 +32,7 @@ void TLVNode::Encode(std::string *output) const { if (IsContainer()) { for (auto child : children_) { - child.Encode(output); + child->Encode(output); } size_t total_child_length = output->length() - header_start - sizeof(header); assert(total_child_length <= UINT16_MAX); @@ -39,12 +45,12 @@ void TLVNode::Encode(std::string *output) const { TLVNode* TLVNode::Decode(const std::string& input) { if (input.length() < sizeof(struct header)) { - return NULL; + return nullptr; } auto header = (struct header*)input.data(); std::cerr << "[type=" << htons(header->type) << ", value_length=" << htons(header->value_length) << "]" << std::endl; if (input.length() < sizeof(*header) + htons(header->value_length)) { - return NULL; + return nullptr; } if (htons(header->type) & 0x8000) { @@ -54,29 +60,49 @@ TLVNode* TLVNode::Decode(const std::string& input) { size_t cursor = sizeof(*header); while (cursor < input.length()) { auto next_header = (struct header*)(input.data() + cursor); - if (cursor + sizeof(*next_header) + htons(next_header->value_length) > input.length()) { - return NULL; + size_t sub_length = sizeof(*next_header) + htons(next_header->value_length); + if (cursor + sub_length > input.length()) { + return nullptr; } - std::unique_ptr child(Decode(input.substr(cursor))); + std::unique_ptr child(Decode(input.substr(cursor, sub_length))); if (!child.get()) { - return NULL; + return nullptr; } - container->AppendChild(*child); - cursor += sizeof(*next_header) + htons(next_header->value_length); + container->AppendChild(child.release()); + cursor += sub_length; } return container.release(); } else { // Scalar - return new TLVNode(htons(header->type), input.substr(sizeof(*header))); + return new TLVNode(htons(header->type), input.substr(sizeof(*header), htons(header->value_length))); } } -void TLVNode::AppendChild(const TLVNode& child) { +void TLVNode::AppendChild(TLVNode* child) { assert(this->IsContainer()); children_.push_back(child); } +TLVNode* TLVNode::FindChild(const uint16_t type) const { + assert(this->IsContainer()); + for (auto child : children_) { + if (child->GetType() == type) { + return child; + } + } + return nullptr; +} + bool TLVNode::IsContainer() const { return type_ & 0x8000; } + +uint16_t TLVNode::GetType() const { + return type_; +} + +const std::string& TLVNode::GetValue() const { + assert(!this->IsContainer()); + return value_; +} diff --git a/tlv.h b/tlv.h index f366914..d22a449 100644 --- a/tlv.h +++ b/tlv.h @@ -7,16 +7,20 @@ class TLVNode { public: TLVNode(const uint16_t type); TLVNode(const uint16_t type, const std::string value); + ~TLVNode(); static TLVNode* Decode(const std::string& input); - void AppendChild(const TLVNode& child); + void AppendChild(TLVNode* child); - void Encode(std::string *output) const; + TLVNode* FindChild(const uint16_t type) const; + void Encode(std::string* output) const; bool IsContainer() const; + uint16_t GetType() const; + const std::string& GetValue() const; private: const uint16_t type_; const std::string value_; - std::list children_; + std::list children_; };