12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved.
22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file.
42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/quic/crypto/curve25519_key_exchange.h"
62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
75d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)#include "base/basictypes.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "crypto/curve25519.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "net/quic/crypto/quic_random.h"
112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using base::StringPiece;
132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using std::string;
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace net {
162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)Curve25519KeyExchange::Curve25519KeyExchange() {}
182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
19b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)Curve25519KeyExchange::~Curve25519KeyExchange() {}
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)Curve25519KeyExchange* Curve25519KeyExchange::New(
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StringPiece& private_key) {
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Curve25519KeyExchange* ka;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // We don't want to #include the NaCl headers in the public header file, so
262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // we use literals for the sizes of private_key_ and public_key_. Here we
272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // assert that those values are equal to the values from the NaCl header.
282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  COMPILE_ASSERT(
292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      sizeof(ka->private_key_) == crypto::curve25519::kScalarBytes,
302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      header_out_of_sync);
31b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  COMPILE_ASSERT(sizeof(ka->public_key_) == crypto::curve25519::kBytes,
32b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)                 header_out_of_sync);
332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (private_key.size() != crypto::curve25519::kScalarBytes) {
352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return NULL;
362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  ka = new Curve25519KeyExchange();
392a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  memcpy(ka->private_key_, private_key.data(),
402a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)         crypto::curve25519::kScalarBytes);
412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  crypto::curve25519::ScalarBaseMult(ka->private_key_, ka->public_key_);
422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return ka;
432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// static
462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)string Curve25519KeyExchange::NewPrivateKey(QuicRandom* rand) {
472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8 private_key[crypto::curve25519::kScalarBytes];
482a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  rand->RandBytes(private_key, sizeof(private_key));
492a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // This makes |private_key| a valid scalar, as specified on
512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  // http://cr.yp.to/ecdh.html
522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  private_key[0] &= 248;
532a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  private_key[31] &= 127;
542a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  private_key[31] |= 64;
552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return string(reinterpret_cast<char*>(private_key), sizeof(private_key));
562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
572a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
58b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)KeyExchange* Curve25519KeyExchange::NewKeyPair(QuicRandom* rand) const {
59b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  const string private_value = NewPrivateKey(rand);
60b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)  return Curve25519KeyExchange::New(private_value);
61b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)}
62b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)
632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)bool Curve25519KeyExchange::CalculateSharedKey(
642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    const StringPiece& peer_public_value,
652a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    string* out_result) const {
662a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  if (peer_public_value.size() != crypto::curve25519::kBytes) {
672a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    return false;
682a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  }
692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  uint8 result[crypto::curve25519::kBytes];
712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  crypto::curve25519::ScalarMult(
722a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      private_key_,
732a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      reinterpret_cast<const uint8*>(peer_public_value.data()),
742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      result);
752a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  out_result->assign(reinterpret_cast<char*>(result), sizeof(result));
762a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return true;
782a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
802a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)StringPiece Curve25519KeyExchange::public_value() const {
812a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  return StringPiece(reinterpret_cast<const char*>(public_key_),
822a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                     sizeof(public_key_));
832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
842a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
85b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles)QuicTag Curve25519KeyExchange::tag() const { return kC255; }
862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}  // namespace net
88