fast_pair_encryption.cc 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. // Copyright 2021 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 <algorithm>
  5. #include <array>
  6. #include "ash/quick_pair/fast_pair_handshake/fast_pair_encryption.h"
  7. #include "ash/quick_pair/common/logging.h"
  8. #include "ash/quick_pair/fast_pair_handshake/fast_pair_key_pair.h"
  9. #include "ash/services/quick_pair/public/cpp/fast_pair_message_type.h"
  10. #include "base/check.h"
  11. #include "third_party/abseil-cpp/absl/types/optional.h"
  12. #include "third_party/boringssl/src/include/openssl/aes.h"
  13. #include "third_party/boringssl/src/include/openssl/base.h"
  14. #include "third_party/boringssl/src/include/openssl/ec.h"
  15. #include "third_party/boringssl/src/include/openssl/ec_key.h"
  16. #include "third_party/boringssl/src/include/openssl/ecdh.h"
  17. #include "third_party/boringssl/src/include/openssl/nid.h"
  18. #include "third_party/boringssl/src/include/openssl/sha.h"
  19. namespace {
  20. using ash::quick_pair::fast_pair_encryption::kBlockByteSize;
  21. // Converts the public anti-spoofing key into an EC_Point.
  22. bssl::UniquePtr<EC_POINT> GetEcPointFromPublicAntiSpoofingKey(
  23. const bssl::UniquePtr<EC_GROUP>& ec_group,
  24. const std::string& decoded_public_anti_spoofing) {
  25. std::array<uint8_t, kPublicKeyByteSize + 1> buffer;
  26. buffer[0] = POINT_CONVERSION_UNCOMPRESSED;
  27. std::copy(decoded_public_anti_spoofing.begin(),
  28. decoded_public_anti_spoofing.end(), buffer.begin() + 1);
  29. bssl::UniquePtr<EC_POINT> new_ec_point(EC_POINT_new(ec_group.get()));
  30. if (!EC_POINT_oct2point(ec_group.get(), new_ec_point.get(), buffer.data(),
  31. buffer.size(), nullptr)) {
  32. return nullptr;
  33. }
  34. return new_ec_point;
  35. }
  36. // Key derivation function to be used in hashing the generated secret key.
  37. void* KDF(const void* in, size_t inlen, void* out, size_t* outlen) {
  38. // Set this to 16 since that's the amount of bytes we want to use
  39. // for the key, even though more will be written by SHA256 below.
  40. *outlen = kPrivateKeyByteSize;
  41. return SHA256(static_cast<const uint8_t*>(in), inlen,
  42. static_cast<uint8_t*>(out));
  43. }
  44. } // namespace
  45. namespace ash {
  46. namespace quick_pair {
  47. namespace fast_pair_encryption {
  48. absl::optional<KeyPair> GenerateKeysWithEcdhKeyAgreement(
  49. const std::string& decoded_public_anti_spoofing) {
  50. if (decoded_public_anti_spoofing.size() != kPublicKeyByteSize) {
  51. QP_LOG(WARNING) << "Expected " << kPublicKeyByteSize
  52. << " byte value for anti-spoofing key. Got:"
  53. << decoded_public_anti_spoofing.size();
  54. return absl::nullopt;
  55. }
  56. // Generate the secp256r1 key-pair.
  57. bssl::UniquePtr<EC_GROUP> ec_group(
  58. EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
  59. bssl::UniquePtr<EC_KEY> ec_key(
  60. EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
  61. if (!EC_KEY_generate_key(ec_key.get())) {
  62. QP_LOG(WARNING) << __func__ << ": Failed to generate ec key";
  63. return absl::nullopt;
  64. }
  65. // The ultimate goal here is to get a 64-byte public key. We accomplish this
  66. // by converting the generated public key into the uncompressed X9.62 format,
  67. // which is 0x04 followed by padded x and y coordinates.
  68. std::array<uint8_t, kPublicKeyByteSize + 1> uncompressed_private_key;
  69. int point_bytes_written = EC_POINT_point2oct(
  70. ec_group.get(), EC_KEY_get0_public_key(ec_key.get()),
  71. POINT_CONVERSION_UNCOMPRESSED, uncompressed_private_key.data(),
  72. uncompressed_private_key.size(), nullptr);
  73. if (point_bytes_written != uncompressed_private_key.size()) {
  74. QP_LOG(WARNING) << __func__
  75. << ": EC_POINT_point2oct failed to convert public key to "
  76. "uncompressed x9.62 format.";
  77. return absl::nullopt;
  78. }
  79. bssl::UniquePtr<EC_POINT> public_anti_spoofing_point =
  80. GetEcPointFromPublicAntiSpoofingKey(ec_group,
  81. decoded_public_anti_spoofing);
  82. if (!public_anti_spoofing_point) {
  83. QP_LOG(WARNING)
  84. << __func__
  85. << ": Failed to convert Public Anti-Spoofing key to EC_POINT";
  86. return absl::nullopt;
  87. }
  88. uint8_t secret[SHA256_DIGEST_LENGTH];
  89. int computed_key_size =
  90. ECDH_compute_key(secret, SHA256_DIGEST_LENGTH,
  91. public_anti_spoofing_point.get(), ec_key.get(), &KDF);
  92. if (computed_key_size != kPrivateKeyByteSize) {
  93. QP_LOG(WARNING) << __func__ << ": ECDH_compute_key failed.";
  94. return absl::nullopt;
  95. }
  96. // Take first 16 bytes from secret as the private key.
  97. std::array<uint8_t, kPrivateKeyByteSize> private_key;
  98. std::copy(secret, secret + kPrivateKeyByteSize, std::begin(private_key));
  99. // Ignore the first byte since it is 0x04, from the above uncompressed X9 .62
  100. // format.
  101. std::array<uint8_t, kPublicKeyByteSize> public_key;
  102. std::copy(uncompressed_private_key.begin() + 1,
  103. uncompressed_private_key.end(), public_key.begin());
  104. return KeyPair(private_key, public_key);
  105. }
  106. const std::array<uint8_t, kBlockByteSize> EncryptBytes(
  107. const std::array<uint8_t, kBlockByteSize>& aes_key_bytes,
  108. const std::array<uint8_t, kBlockByteSize>& bytes_to_encrypt) {
  109. AES_KEY aes_key;
  110. int aes_key_was_set = AES_set_encrypt_key(aes_key_bytes.data(),
  111. aes_key_bytes.size() * 8, &aes_key);
  112. DCHECK(aes_key_was_set == 0) << "Invalid AES key size.";
  113. std::array<uint8_t, kBlockByteSize> encrypted_bytes;
  114. AES_encrypt(bytes_to_encrypt.data(), encrypted_bytes.data(), &aes_key);
  115. return encrypted_bytes;
  116. }
  117. } // namespace fast_pair_encryption
  118. } // namespace quick_pair
  119. } // namespace ash