noise.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. // Copyright 2020 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "device/fido/cable/noise.h"
  5. #include <string.h>
  6. #include "base/check_op.h"
  7. #include "base/sys_byteorder.h"
  8. #include "crypto/aead.h"
  9. #include "crypto/sha2.h"
  10. #include "device/fido/fido_constants.h"
  11. #include "third_party/boringssl/src/include/openssl/digest.h"
  12. #include "third_party/boringssl/src/include/openssl/ec.h"
  13. #include "third_party/boringssl/src/include/openssl/hkdf.h"
  14. #include "third_party/boringssl/src/include/openssl/obj.h"
  15. #include "third_party/boringssl/src/include/openssl/sha.h"
  16. namespace {
  17. // HKDF2 implements the functions with the same name from Noise[1],
  18. // specialized to the case where |num_outputs| is two.
  19. //
  20. // [1] https://www.noiseprotocol.org/noise.html#hash-functions
  21. std::tuple<std::array<uint8_t, 32>, std::array<uint8_t, 32>> HKDF2(
  22. base::span<const uint8_t, 32> ck,
  23. base::span<const uint8_t> ikm) {
  24. uint8_t output[32 * 2];
  25. HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(), ck.data(),
  26. ck.size(), /*info=*/nullptr, 0);
  27. std::array<uint8_t, 32> a, b;
  28. memcpy(a.data(), &output[0], 32);
  29. memcpy(b.data(), &output[32], 32);
  30. return std::make_tuple(a, b);
  31. }
  32. } // namespace
  33. namespace device {
  34. Noise::Noise() = default;
  35. Noise::~Noise() = default;
  36. void Noise::Init(Noise::HandshakeType type) {
  37. // See https://www.noiseprotocol.org/noise.html#the-handshakestate-object
  38. static const char kKNProtocolName[] = "Noise_KNpsk0_P256_AESGCM_SHA256";
  39. static const char kNKProtocolName[] = "Noise_NKpsk0_P256_AESGCM_SHA256";
  40. static_assert(sizeof(kNKProtocolName) == sizeof(kKNProtocolName),
  41. "protocol names are different lengths");
  42. static_assert(sizeof(kKNProtocolName) == crypto::kSHA256Length,
  43. "name may need padding if not HASHLEN bytes long");
  44. static_assert(
  45. std::tuple_size<decltype(chaining_key_)>::value == crypto::kSHA256Length,
  46. "chaining_key_ is wrong size");
  47. static_assert(std::tuple_size<decltype(h_)>::value == crypto::kSHA256Length,
  48. "h_ is wrong size");
  49. switch (type) {
  50. case HandshakeType::kNKpsk0:
  51. memcpy(chaining_key_.data(), kNKProtocolName, sizeof(kNKProtocolName));
  52. break;
  53. case HandshakeType::kKNpsk0:
  54. memcpy(chaining_key_.data(), kKNProtocolName, sizeof(kKNProtocolName));
  55. break;
  56. }
  57. h_ = chaining_key_;
  58. }
  59. void Noise::MixHash(base::span<const uint8_t> in) {
  60. // See https://www.noiseprotocol.org/noise.html#the-symmetricstate-object
  61. SHA256_CTX ctx;
  62. SHA256_Init(&ctx);
  63. SHA256_Update(&ctx, h_.data(), h_.size());
  64. SHA256_Update(&ctx, in.data(), in.size());
  65. SHA256_Final(h_.data(), &ctx);
  66. }
  67. void Noise::MixKey(base::span<const uint8_t> ikm) {
  68. // See https://www.noiseprotocol.org/noise.html#the-symmetricstate-object
  69. std::array<uint8_t, 32> temp_k;
  70. std::tie(chaining_key_, temp_k) = HKDF2(chaining_key_, ikm);
  71. InitializeKey(temp_k);
  72. }
  73. void Noise::MixKeyAndHash(base::span<const uint8_t> ikm) {
  74. // See https://www.noiseprotocol.org/noise.html#the-symmetricstate-object
  75. uint8_t output[32 * 3];
  76. HKDF(output, sizeof(output), EVP_sha256(), ikm.data(), ikm.size(),
  77. chaining_key_.data(), chaining_key_.size(), /*info=*/nullptr, 0);
  78. DCHECK_EQ(chaining_key_.size(), 32u);
  79. memcpy(chaining_key_.data(), output, 32);
  80. MixHash(base::span<const uint8_t>(&output[32], 32));
  81. InitializeKey(base::span<const uint8_t, 32>(&output[64], 32));
  82. }
  83. std::vector<uint8_t> Noise::EncryptAndHash(
  84. base::span<const uint8_t> plaintext) {
  85. uint8_t nonce[12] = {0};
  86. const uint32_t counter = base::ByteSwap(symmetric_nonce_);
  87. memcpy(nonce, &counter, sizeof(counter));
  88. symmetric_nonce_++;
  89. crypto::Aead aead(crypto::Aead::AES_256_GCM);
  90. aead.Init(symmetric_key_);
  91. std::vector<uint8_t> ciphertext = aead.Seal(plaintext, nonce, h_);
  92. MixHash(ciphertext);
  93. return ciphertext;
  94. }
  95. absl::optional<std::vector<uint8_t>> Noise::DecryptAndHash(
  96. base::span<const uint8_t> ciphertext) {
  97. uint8_t nonce[12] = {0};
  98. const uint32_t counter = base::ByteSwap(symmetric_nonce_);
  99. memcpy(nonce, &counter, sizeof(counter));
  100. symmetric_nonce_++;
  101. crypto::Aead aead(crypto::Aead::AES_256_GCM);
  102. aead.Init(symmetric_key_);
  103. auto plaintext = aead.Open(ciphertext, nonce, h_);
  104. if (plaintext) {
  105. MixHash(ciphertext);
  106. }
  107. return plaintext;
  108. }
  109. std::array<uint8_t, 32> Noise::handshake_hash() const {
  110. return h_;
  111. }
  112. void Noise::MixHashPoint(const EC_POINT* point) {
  113. uint8_t x962[kP256X962Length];
  114. bssl::UniquePtr<EC_GROUP> p256(
  115. EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  116. CHECK_EQ(sizeof(x962),
  117. EC_POINT_point2oct(p256.get(), point, POINT_CONVERSION_UNCOMPRESSED,
  118. x962, sizeof(x962), /*ctx=*/nullptr));
  119. MixHash(x962);
  120. }
  121. std::tuple<std::array<uint8_t, 32>, std::array<uint8_t, 32>>
  122. Noise::traffic_keys() const {
  123. return HKDF2(chaining_key_, base::span<const uint8_t>());
  124. }
  125. void Noise::InitializeKey(base::span<const uint8_t, 32> key) {
  126. // See https://www.noiseprotocol.org/noise.html#the-cipherstate-object
  127. DCHECK_EQ(symmetric_key_.size(), key.size());
  128. memcpy(symmetric_key_.data(), key.data(), symmetric_key_.size());
  129. symmetric_nonce_ = 0;
  130. }
  131. } // namespace device