Switch to compile-time sizes for various crypto methods/types.
This started with changing HkdfSha256() to a compile-time size, and the rest is the transitive closure of what I needed to touch. Compile-time sizes shift errors left: certain kinds of misuse become impossible. Bug: none Change-Id: I72ae216e90a898a092a342a907d8b9578bde7ed8 Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6098327 Code-Coverage: findit-for-me@appspot.gserviceaccount.com <findit-for-me@appspot.gserviceaccount.com> Reviewed-by: Jood Hajeer <jood@google.com> Reviewed-by: Will Harris <wfh@chromium.org> Reviewed-by: Adam Langley <agl@chromium.org> Reviewed-by: Ryan Hansberry <hansberry@chromium.org> Commit-Queue: Peter Kasting <pkasting@chromium.org> Reviewed-by: Fabio Tirelo <ftirelo@chromium.org> Auto-Submit: Peter Kasting <pkasting@chromium.org> Cr-Commit-Position: refs/heads/main@{#1398728}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
20b3b308ad
commit
2dd6f6078d
chrome
browser
nearby_sharing
certificates
BUILD.gncommon.cccommon.hconstants.ccconstants.hfake_nearby_share_certificate_manager.ccfake_nearby_share_certificate_manager.hnearby_share_certificate_manager.ccnearby_share_certificate_manager.hnearby_share_decrypted_public_certificate.ccnearby_share_decrypted_public_certificate.hnearby_share_decrypted_public_certificate_unittest.ccnearby_share_encrypted_metadata_key.ccnearby_share_encrypted_metadata_key.hnearby_share_private_certificate.ccnearby_share_private_certificate.htest_util.cctest_util.h
nearby_sharing_service_impl.ccnearby_sharing_service_impl_unittest.ccpaired_key_verification_runner.ccwebauthn
services
components
enterprise
obfuscation
os_crypt
async
trusted_vault
webauthn
core
browser
crypto
device/fido/cable
@ -8,7 +8,6 @@ source_set("certificates") {
|
||||
sources = [
|
||||
"common.cc",
|
||||
"common.h",
|
||||
"constants.cc",
|
||||
"constants.h",
|
||||
"nearby_share_certificate_manager.cc",
|
||||
"nearby_share_certificate_manager.h",
|
||||
|
@ -4,12 +4,13 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/common.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "crypto/encryptor.h"
|
||||
#include "crypto/hkdf.h"
|
||||
#include "crypto/random.h"
|
||||
#include "crypto/sha2.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
|
||||
@ -39,22 +40,10 @@ bool IsNearbyShareCertificateWithinValidityPeriod(
|
||||
use_public_certificate_tolerance);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DeriveNearbyShareKey(base::span<const uint8_t> key,
|
||||
size_t new_num_bytes) {
|
||||
return crypto::HkdfSha256(key,
|
||||
/*salt=*/base::span<const uint8_t>(),
|
||||
/*info=*/base::span<const uint8_t>(),
|
||||
new_num_bytes);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> ComputeAuthenticationTokenHash(
|
||||
base::span<const uint8_t> authentication_token,
|
||||
base::span<const uint8_t> secret_key) {
|
||||
return crypto::HkdfSha256(authentication_token, secret_key,
|
||||
/*info=*/base::span<const uint8_t>(),
|
||||
kNearbyShareNumBytesAuthenticationTokenHash);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> GenerateRandomBytes(size_t num_bytes) {
|
||||
return crypto::RandBytesAsVector(num_bytes);
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
ComputeAuthenticationTokenHash(base::span<const uint8_t> authentication_token,
|
||||
base::span<const uint8_t> secret_key) {
|
||||
return crypto::HkdfSha256<kNearbyShareNumBytesAuthenticationTokenHash>(
|
||||
authentication_token, secret_key,
|
||||
/*info=*/base::span<const uint8_t>());
|
||||
}
|
||||
|
@ -5,11 +5,15 @@
|
||||
#ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_COMMON_H_
|
||||
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_COMMON_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "crypto/hkdf.h"
|
||||
#include "crypto/random.h"
|
||||
|
||||
// Returns true if the |current_time| exceeds |not_after| by more than the
|
||||
// public certificate clock-skew tolerance if applicable.
|
||||
@ -30,16 +34,24 @@ bool IsNearbyShareCertificateWithinValidityPeriod(
|
||||
// |secret_key|. A trivial info parameter is used, and the output length is
|
||||
// fixed to be kNearbyShareNumBytesAuthenticationTokenHash to conform with the
|
||||
// GmsCore implementation.
|
||||
std::vector<uint8_t> ComputeAuthenticationTokenHash(
|
||||
base::span<const uint8_t> authentication_token,
|
||||
base::span<const uint8_t> secret_key);
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
ComputeAuthenticationTokenHash(base::span<const uint8_t> authentication_token,
|
||||
base::span<const uint8_t> secret_key);
|
||||
|
||||
// Uses HKDF to generate a new key of length |new_num_bytes| from |key|. To
|
||||
// Uses HKDF to generate a new key of length |NewNumBytes| from |key|. To
|
||||
// conform with the GmsCore implementation, trivial salt and info are used.
|
||||
std::vector<uint8_t> DeriveNearbyShareKey(base::span<const uint8_t> key,
|
||||
size_t new_num_bytes);
|
||||
template <size_t NewNumBytes>
|
||||
std::array<uint8_t, NewNumBytes> DeriveNearbyShareKey(
|
||||
base::span<const uint8_t> key) {
|
||||
return crypto::HkdfSha256<NewNumBytes>(key, /*salt=*/{}, /*info=*/{});
|
||||
}
|
||||
|
||||
// Generates a random byte array with size |num_bytes|.
|
||||
std::vector<uint8_t> GenerateRandomBytes(size_t num_bytes);
|
||||
template <size_t NumBytes>
|
||||
std::array<uint8_t, NumBytes> GenerateRandomBytes() {
|
||||
std::array<uint8_t, NumBytes> bytes;
|
||||
crypto::RandBytes(bytes);
|
||||
return bytes;
|
||||
}
|
||||
|
||||
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_COMMON_H_
|
||||
|
@ -1,29 +0,0 @@
|
||||
// Copyright 2020 The Chromium Authors
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
|
||||
const base::TimeDelta kNearbyShareCertificateValidityPeriod = base::Days(3);
|
||||
const base::TimeDelta kNearbyShareMaxPrivateCertificateValidityBoundOffset =
|
||||
base::Hours(2);
|
||||
const base::TimeDelta
|
||||
kNearbySharePublicCertificateValidityBoundOffsetTolerance =
|
||||
base::Minutes(30);
|
||||
const size_t kNearbyShareNumPrivateCertificates = 3;
|
||||
const size_t kNearbyShareNumBytesAuthenticationTokenHash = 6;
|
||||
const size_t kNearbyShareNumBytesAesGcmKey = 32;
|
||||
const size_t kNearbyShareNumBytesAesGcmIv = 12;
|
||||
const size_t kNearbyShareNumBytesAesCtrIv = 16;
|
||||
const size_t kNearbyShareNumBytesSecretKey = 32;
|
||||
const size_t kNearbyShareNumBytesMetadataEncryptionKey = 14;
|
||||
const size_t kNearbyShareNumBytesMetadataEncryptionKeySalt = 2;
|
||||
const size_t kNearbyShareNumBytesMetadataEncryptionKeyTag = 32;
|
||||
const size_t kNearbyShareNumBytesCertificateId = 32;
|
||||
const size_t kNearbyShareMaxNumMetadataEncryptionKeySalts = 32768;
|
||||
const size_t kNearbyShareMaxNumMetadataEncryptionKeySaltGenerationRetries = 128;
|
||||
const char kNearbyShareSenderVerificationPrefix = 0x01;
|
||||
const char kNearbyShareReceiverVerificationPrefix = 0x02;
|
||||
const size_t kNearbyShareCertificateStorageMaxNumInitializeAttempts = 3;
|
||||
const base::TimeDelta kNearbySharePublicCertificateDownloadPeriod =
|
||||
base::Hours(12);
|
@ -8,55 +8,62 @@
|
||||
#include "base/time/time.h"
|
||||
|
||||
// The number of days a certificate is valid.
|
||||
extern const base::TimeDelta kNearbyShareCertificateValidityPeriod;
|
||||
inline constexpr base::TimeDelta kNearbyShareCertificateValidityPeriod =
|
||||
base::Days(3);
|
||||
|
||||
// The maximum offset for obfuscating a private certificate's not before/after
|
||||
// timestamps when converting to a public certificate.
|
||||
extern const base::TimeDelta
|
||||
kNearbyShareMaxPrivateCertificateValidityBoundOffset;
|
||||
inline constexpr base::TimeDelta
|
||||
kNearbyShareMaxPrivateCertificateValidityBoundOffset = base::Hours(2);
|
||||
|
||||
// To account for clock skew between the local device and remote devices, public
|
||||
// certificates will be considered valid if the current time is within the
|
||||
// bounds [not-before - tolerance, not-after + tolerance).
|
||||
extern const base::TimeDelta
|
||||
kNearbySharePublicCertificateValidityBoundOffsetTolerance;
|
||||
inline constexpr base::TimeDelta
|
||||
kNearbySharePublicCertificateValidityBoundOffsetTolerance =
|
||||
base::Minutes(30);
|
||||
|
||||
// The number of private certificates for a given visibility to be stored and
|
||||
// rotated on the local device.
|
||||
extern const size_t kNearbyShareNumPrivateCertificates;
|
||||
inline constexpr size_t kNearbyShareNumPrivateCertificates = 3;
|
||||
|
||||
// The number of bytes comprising the hash of the authentication token using the
|
||||
// secret key.
|
||||
extern const size_t kNearbyShareNumBytesAuthenticationTokenHash;
|
||||
inline constexpr size_t kNearbyShareNumBytesAuthenticationTokenHash = 6;
|
||||
|
||||
// Length of key in bytes required by AES-GCM encryption.
|
||||
extern const size_t kNearbyShareNumBytesAesGcmKey;
|
||||
inline constexpr size_t kNearbyShareNumBytesAesGcmKey = 32;
|
||||
|
||||
// Length of salt in bytes required by AES-GCM encryption.
|
||||
extern const size_t kNearbyShareNumBytesAesGcmIv;
|
||||
inline constexpr size_t kNearbyShareNumBytesAesGcmIv = 12;
|
||||
|
||||
// Length of salt in bytes required by AES-CTR encryption.
|
||||
extern const size_t kNearbyShareNumBytesAesCtrIv;
|
||||
inline constexpr size_t kNearbyShareNumBytesAesCtrIv = 16;
|
||||
|
||||
// The number of bytes of the AES secret key used to encrypt/decrypt the
|
||||
// metadata encryption key.
|
||||
extern const size_t kNearbyShareNumBytesSecretKey;
|
||||
inline constexpr size_t kNearbyShareNumBytesSecretKey = 32;
|
||||
|
||||
// The number of the bytes of the AES key used to encryption personal info
|
||||
// metadata, for example, name and picture data. These bytes are broadcast in an
|
||||
// advertisement to other devices, thus the smaller byte size.
|
||||
extern const size_t kNearbyShareNumBytesMetadataEncryptionKey;
|
||||
inline constexpr size_t kNearbyShareNumBytesMetadataEncryptionKey = 14;
|
||||
|
||||
// The number of bytes for the salt used for encryption of the metadata
|
||||
// encryption key. These bytes are broadcast in the advertisement to other
|
||||
// devices.
|
||||
extern const size_t kNearbyShareNumBytesMetadataEncryptionKeySalt;
|
||||
inline constexpr size_t kNearbyShareNumBytesMetadataEncryptionKeySalt = 2;
|
||||
|
||||
// The number of bytes used for the hash of the metadata encryption key.
|
||||
extern const size_t kNearbyShareNumBytesMetadataEncryptionKeyTag;
|
||||
inline constexpr size_t kNearbyShareNumBytesMetadataEncryptionKeyTag = 32;
|
||||
|
||||
// The number of bytes in a certificate's identifier.
|
||||
extern const size_t kNearbyShareNumBytesCertificateId;
|
||||
inline constexpr size_t kNearbyShareNumBytesCertificateId = 32;
|
||||
|
||||
// The size of the random byte array used for the encryption frame's signed data
|
||||
// if a valid signature cannot be generated. This size is consistent with the
|
||||
// GmsCore implementation.
|
||||
inline constexpr size_t kNearbyShareNumBytesRandomSignature = 72;
|
||||
|
||||
// Half of the possible 2-byte salt values.
|
||||
//
|
||||
@ -72,25 +79,27 @@ extern const size_t kNearbyShareNumBytesCertificateId;
|
||||
// device that avoids salts that you’ve seen in the past is statistically likely
|
||||
// to be the device you’re tracking. Therefore, we only use half of the
|
||||
// available 2-byte salts.
|
||||
extern const size_t kNearbyShareMaxNumMetadataEncryptionKeySalts;
|
||||
inline constexpr size_t kNearbyShareMaxNumMetadataEncryptionKeySalts = 32768;
|
||||
|
||||
// The max number of retries allowed to generate a salt. This is a sanity check
|
||||
// that will never be hit.
|
||||
extern const size_t
|
||||
kNearbyShareMaxNumMetadataEncryptionKeySaltGenerationRetries;
|
||||
inline constexpr size_t
|
||||
kNearbyShareMaxNumMetadataEncryptionKeySaltGenerationRetries = 128;
|
||||
|
||||
// The prefix prepended to the UKEY2 authentication token by the sender before
|
||||
// signing.
|
||||
extern const char kNearbyShareSenderVerificationPrefix;
|
||||
inline constexpr char kNearbyShareSenderVerificationPrefix = 0x01;
|
||||
|
||||
// The prefix prepended to the UKEY2 authentication token by the receiver before
|
||||
// signing.
|
||||
extern const char kNearbyShareReceiverVerificationPrefix;
|
||||
inline constexpr char kNearbyShareReceiverVerificationPrefix = 0x02;
|
||||
|
||||
// The maximum number of attempts to initialize LevelDB in Certificate Storage.
|
||||
extern const size_t kNearbyShareCertificateStorageMaxNumInitializeAttempts;
|
||||
inline constexpr size_t kNearbyShareCertificateStorageMaxNumInitializeAttempts =
|
||||
3;
|
||||
|
||||
// The frequency with which to download public certificates.
|
||||
extern const base::TimeDelta kNearbySharePublicCertificateDownloadPeriod;
|
||||
inline constexpr base::TimeDelta kNearbySharePublicCertificateDownloadPeriod =
|
||||
base::Hours(12);
|
||||
|
||||
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_CONSTANTS_H_
|
||||
|
@ -77,7 +77,7 @@ std::optional<NearbySharePrivateCertificate>
|
||||
FakeNearbyShareCertificateManager::GetValidPrivateCertificate(
|
||||
nearby_share::mojom::Visibility visibility) const {
|
||||
auto cert = GetNearbyShareTestPrivateCertificate(visibility);
|
||||
cert.next_salts_for_testing() = base::queue<std::vector<uint8_t>>();
|
||||
cert.next_salts_for_testing() = {};
|
||||
cert.next_salts_for_testing().push(next_salt_);
|
||||
return cert;
|
||||
}
|
||||
|
@ -8,8 +8,10 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/memory/raw_ptr.h"
|
||||
#include "base/time/clock.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager_impl.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
|
||||
@ -89,7 +91,11 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager {
|
||||
using NearbyShareCertificateManager::NotifyPrivateCertificatesChanged;
|
||||
using NearbyShareCertificateManager::NotifyPublicCertificatesDownloaded;
|
||||
|
||||
void set_next_salt(const std::vector<uint8_t>& salt) { next_salt_ = salt; }
|
||||
void set_next_salt(
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>
|
||||
salt) {
|
||||
base::span(next_salt_).copy_from(salt);
|
||||
}
|
||||
|
||||
size_t num_get_private_certificates_as_public_certificates_calls() {
|
||||
return num_get_private_certificates_as_public_certificates_calls_;
|
||||
@ -117,7 +123,7 @@ class FakeNearbyShareCertificateManager : public NearbyShareCertificateManager {
|
||||
size_t num_download_public_certificates_calls_ = 0;
|
||||
std::vector<GetDecryptedPublicCertificateCall>
|
||||
get_decrypted_public_certificate_calls_;
|
||||
std::vector<uint8_t> next_salt_;
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt> next_salt_;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_FAKE_NEARBY_SHARE_CERTIFICATE_MANAGER_H_
|
||||
|
@ -4,6 +4,10 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_certificate_manager.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
|
||||
NearbyShareCertificateManager::NearbyShareCertificateManager() = default;
|
||||
|
||||
NearbyShareCertificateManager::~NearbyShareCertificateManager() = default;
|
||||
@ -63,7 +67,7 @@ NearbyShareCertificateManager::SignWithPrivateCertificate(
|
||||
return cert->Sign(payload);
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8_t>>
|
||||
std::optional<std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>>
|
||||
NearbyShareCertificateManager::HashAuthenticationTokenWithPrivateCertificate(
|
||||
nearby_share::mojom::Visibility visibility,
|
||||
base::span<const uint8_t> authentication_token) const {
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_H_
|
||||
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_CERTIFICATE_MANAGER_H_
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
@ -12,6 +13,7 @@
|
||||
#include "base/functional/callback.h"
|
||||
#include "base/observer_list.h"
|
||||
#include "base/observer_list_types.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
|
||||
@ -75,7 +77,8 @@ class NearbyShareCertificateManager {
|
||||
// Creates a hash of the |authentication_token| using the currently valid
|
||||
// private certificate. Returns std::nullopt if there is no valid private
|
||||
// certificate with |visibility|.
|
||||
std::optional<std::vector<uint8_t>>
|
||||
std::optional<
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>>
|
||||
HashAuthenticationTokenWithPrivateCertificate(
|
||||
nearby_share::mojom::Visibility visibility,
|
||||
base::span<const uint8_t> authentication_token) const;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/common.h"
|
||||
@ -38,12 +39,11 @@ std::optional<std::vector<uint8_t>> DecryptMetadataKey(
|
||||
const NearbyShareEncryptedMetadataKey& encrypted_metadata_key,
|
||||
const crypto::SymmetricKey* secret_key) {
|
||||
auto key = base::as_byte_span(secret_key->key());
|
||||
auto counter = DeriveNearbyShareKey(encrypted_metadata_key.salt(),
|
||||
crypto::aes_ctr::kCounterSize);
|
||||
auto counter = DeriveNearbyShareKey<crypto::aes_ctr::kCounterSize>(
|
||||
encrypted_metadata_key.salt());
|
||||
|
||||
return crypto::aes_ctr::Decrypt(
|
||||
key, base::span<const uint8_t, crypto::aes_ctr::kCounterSize>(counter),
|
||||
base::as_byte_span(encrypted_metadata_key.encrypted_key()));
|
||||
key, counter, base::as_byte_span(encrypted_metadata_key.encrypted_key()));
|
||||
}
|
||||
|
||||
// Attempts to decrypt |encrypted_metadata| with |metadata_encryption_key|,
|
||||
@ -55,16 +55,16 @@ std::optional<std::vector<uint8_t>> DecryptMetadataPayload(
|
||||
const crypto::SymmetricKey* secret_key) {
|
||||
// Init() keeps a reference to the input key, so that reference must outlive
|
||||
// the lifetime of |aead|.
|
||||
std::vector<uint8_t> derived_key = DeriveNearbyShareKey(
|
||||
metadata_encryption_key, kNearbyShareNumBytesAesGcmKey);
|
||||
auto derived_key = DeriveNearbyShareKey<kNearbyShareNumBytesAesGcmKey>(
|
||||
metadata_encryption_key);
|
||||
|
||||
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
|
||||
aead.Init(derived_key);
|
||||
|
||||
return aead.Open(encrypted_metadata,
|
||||
/*nonce=*/
|
||||
DeriveNearbyShareKey(base::as_byte_span(secret_key->key()),
|
||||
kNearbyShareNumBytesAesGcmIv),
|
||||
DeriveNearbyShareKey<kNearbyShareNumBytesAesGcmIv>(
|
||||
base::as_byte_span(secret_key->key())),
|
||||
/*additional_data=*/base::span<const uint8_t>());
|
||||
}
|
||||
|
||||
@ -221,7 +221,7 @@ bool NearbyShareDecryptedPublicCertificate::VerifySignature(
|
||||
return verifier.VerifyFinal();
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
NearbyShareDecryptedPublicCertificate::HashAuthenticationToken(
|
||||
base::span<const uint8_t> authentication_token) const {
|
||||
return ComputeAuthenticationTokenHash(authentication_token,
|
||||
|
@ -5,12 +5,14 @@
|
||||
#ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_DECRYPTED_PUBLIC_CERTIFICATE_H_
|
||||
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_DECRYPTED_PUBLIC_CERTIFICATE_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
|
||||
#include "crypto/symmetric_key.h"
|
||||
#include "third_party/nearby/sharing/proto/encrypted_metadata.pb.h"
|
||||
@ -60,8 +62,8 @@ class NearbyShareDecryptedPublicCertificate {
|
||||
// Creates a hash of the |authentication_token|, using |secret_key_|. The use
|
||||
// of HKDF and the output vector size is part of the Nearby Share protocol and
|
||||
// conforms with the GmsCore implementation.
|
||||
std::vector<uint8_t> HashAuthenticationToken(
|
||||
base::span<const uint8_t> authentication_token) const;
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
HashAuthenticationToken(base::span<const uint8_t> authentication_token) const;
|
||||
|
||||
private:
|
||||
NearbyShareDecryptedPublicCertificate(
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
@ -51,10 +52,8 @@ TEST(NearbyShareDecryptedPublicCertificateTest, Decrypt_IncorrectKeyFailure) {
|
||||
EXPECT_FALSE(NearbyShareDecryptedPublicCertificate::DecryptPublicCertificate(
|
||||
GetNearbyShareTestPublicCertificate(kTestPublicCertificateVisibility),
|
||||
NearbyShareEncryptedMetadataKey(
|
||||
std::vector<uint8_t>(kNearbyShareNumBytesMetadataEncryptionKeySalt,
|
||||
0x00),
|
||||
std::vector<uint8_t>(kNearbyShareNumBytesMetadataEncryptionKey,
|
||||
0x00))));
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>(),
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>())));
|
||||
}
|
||||
|
||||
TEST(NearbyShareDecryptedPublicCertificateTest,
|
||||
|
@ -4,17 +4,22 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
|
||||
NearbyShareEncryptedMetadataKey::NearbyShareEncryptedMetadataKey(
|
||||
std::vector<uint8_t> salt,
|
||||
std::vector<uint8_t> encrypted_key)
|
||||
: salt_(std::move(salt)), encrypted_key_(std::move(encrypted_key)) {
|
||||
DCHECK_EQ(kNearbyShareNumBytesMetadataEncryptionKeySalt, salt_.size());
|
||||
DCHECK_EQ(kNearbyShareNumBytesMetadataEncryptionKey, encrypted_key_.size());
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>
|
||||
salt,
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
encrypted_key) {
|
||||
base::span(salt_).copy_from(salt);
|
||||
base::span(encrypted_key_).copy_from(encrypted_key);
|
||||
}
|
||||
|
||||
NearbyShareEncryptedMetadataKey::NearbyShareEncryptedMetadataKey(
|
||||
|
@ -5,15 +5,22 @@
|
||||
#ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_ENCRYPTED_METADATA_KEY_H_
|
||||
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_ENCRYPTED_METADATA_KEY_H_
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
|
||||
// Holds the encrypted symmetric key--the key used to encrypt user/device
|
||||
// metatdata--as well as the salt used to encrypt the key.
|
||||
struct NearbyShareEncryptedMetadataKey {
|
||||
public:
|
||||
NearbyShareEncryptedMetadataKey(std::vector<uint8_t> salt,
|
||||
std::vector<uint8_t> encrypted_key);
|
||||
NearbyShareEncryptedMetadataKey(
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>
|
||||
salt,
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
encrypted_key);
|
||||
NearbyShareEncryptedMetadataKey(const NearbyShareEncryptedMetadataKey&);
|
||||
NearbyShareEncryptedMetadataKey& operator=(
|
||||
const NearbyShareEncryptedMetadataKey&);
|
||||
@ -21,12 +28,18 @@ struct NearbyShareEncryptedMetadataKey {
|
||||
NearbyShareEncryptedMetadataKey& operator=(NearbyShareEncryptedMetadataKey&&);
|
||||
~NearbyShareEncryptedMetadataKey();
|
||||
|
||||
const std::vector<uint8_t>& salt() const { return salt_; }
|
||||
const std::vector<uint8_t>& encrypted_key() const { return encrypted_key_; }
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>
|
||||
salt() const {
|
||||
return salt_;
|
||||
}
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
encrypted_key() const {
|
||||
return encrypted_key_;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<uint8_t> salt_;
|
||||
std::vector<uint8_t> encrypted_key_;
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt> salt_;
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey> encrypted_key_;
|
||||
};
|
||||
|
||||
#endif // CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_ENCRYPTED_METADATA_KEY_H_
|
||||
|
@ -4,12 +4,18 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/base64url.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "base/json/values_util.h"
|
||||
#include "base/rand_util.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
@ -71,7 +77,7 @@ std::optional<std::vector<uint8_t>> CreateMetadataEncryptionKeyTag(
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string EncodeString(const std::string& unencoded_string) {
|
||||
std::string EncodeString(std::string_view unencoded_string) {
|
||||
std::string encoded_string;
|
||||
base::Base64UrlEncode(unencoded_string,
|
||||
base::Base64UrlEncodePolicy::INCLUDE_PADDING,
|
||||
@ -94,8 +100,8 @@ std::optional<std::string> DecodeString(const std::string* encoded_string) {
|
||||
return decoded_string;
|
||||
}
|
||||
|
||||
std::string BytesToEncodedString(const std::vector<uint8_t>& bytes) {
|
||||
return EncodeString(std::string(bytes.begin(), bytes.end()));
|
||||
std::string BytesToEncodedString(base::span<const uint8_t> bytes) {
|
||||
return EncodeString(base::as_string_view(bytes));
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8_t>> EncodedStringToBytes(
|
||||
@ -106,23 +112,29 @@ std::optional<std::vector<uint8_t>> EncodedStringToBytes(
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
std::string SaltsToString(const std::set<std::vector<uint8_t>>& salts) {
|
||||
std::string SaltsToString(
|
||||
const std::set<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>&
|
||||
salts) {
|
||||
std::string str;
|
||||
str.reserve(salts.size() * 2 * kNearbyShareNumBytesMetadataEncryptionKeySalt);
|
||||
for (const std::vector<uint8_t>& salt : salts) {
|
||||
for (const auto& salt : salts) {
|
||||
str += base::HexEncode(salt);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
std::set<std::vector<uint8_t>> StringToSalts(const std::string& str) {
|
||||
const size_t chars_per_salt =
|
||||
2 * kNearbyShareNumBytesMetadataEncryptionKeySalt;
|
||||
DCHECK(str.size() % chars_per_salt == 0);
|
||||
std::set<std::vector<uint8_t>> salts;
|
||||
for (size_t i = 0; i < str.size(); i += chars_per_salt) {
|
||||
std::vector<uint8_t> salt;
|
||||
base::HexStringToBytes(std::string_view(&str[i], chars_per_salt), &salt);
|
||||
std::set<std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
StringToSalts(const std::string& str) {
|
||||
DCHECK(str.size() % (2 * kNearbyShareNumBytesMetadataEncryptionKeySalt) == 0);
|
||||
std::vector<uint8_t> salt_bytes;
|
||||
base::HexStringToBytes(str, &salt_bytes);
|
||||
std::set<std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
salts;
|
||||
for (base::span salt_span(salt_bytes); !salt_span.empty();) {
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt> salt;
|
||||
base::span(salt).copy_from(
|
||||
salt_span.take_first<kNearbyShareNumBytesMetadataEncryptionKeySalt>());
|
||||
salts.insert(std::move(salt));
|
||||
}
|
||||
return salts;
|
||||
@ -167,7 +179,7 @@ NearbySharePrivateCertificate::NearbySharePrivateCertificate(
|
||||
crypto::SymmetricKey::Algorithm::AES,
|
||||
/*key_size_in_bits=*/8 * kNearbyShareNumBytesSecretKey)),
|
||||
metadata_encryption_key_(
|
||||
GenerateRandomBytes(kNearbyShareNumBytesMetadataEncryptionKey)),
|
||||
GenerateRandomBytes<kNearbyShareNumBytesMetadataEncryptionKey>()),
|
||||
id_(CreateCertificateIdFromSecretKey(*secret_key_)),
|
||||
unencrypted_metadata_(std::move(unencrypted_metadata)) {
|
||||
DCHECK_NE(visibility, nearby_share::mojom::Visibility::kNoOne);
|
||||
@ -179,20 +191,22 @@ NearbySharePrivateCertificate::NearbySharePrivateCertificate(
|
||||
base::Time not_after,
|
||||
std::unique_ptr<crypto::ECPrivateKey> key_pair,
|
||||
std::unique_ptr<crypto::SymmetricKey> secret_key,
|
||||
std::vector<uint8_t> metadata_encryption_key,
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
metadata_encryption_key,
|
||||
std::vector<uint8_t> id,
|
||||
nearby::sharing::proto::EncryptedMetadata unencrypted_metadata,
|
||||
std::set<std::vector<uint8_t>> consumed_salts)
|
||||
std::set<std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
consumed_salts)
|
||||
: visibility_(visibility),
|
||||
not_before_(not_before),
|
||||
not_after_(not_after),
|
||||
key_pair_(std::move(key_pair)),
|
||||
secret_key_(std::move(secret_key)),
|
||||
metadata_encryption_key_(std::move(metadata_encryption_key)),
|
||||
id_(std::move(id)),
|
||||
unencrypted_metadata_(std::move(unencrypted_metadata)),
|
||||
consumed_salts_(std::move(consumed_salts)) {
|
||||
DCHECK_NE(visibility, nearby_share::mojom::Visibility::kNoOne);
|
||||
base::span(metadata_encryption_key_).copy_from(metadata_encryption_key);
|
||||
}
|
||||
|
||||
NearbySharePrivateCertificate::NearbySharePrivateCertificate(
|
||||
@ -230,7 +244,9 @@ NearbySharePrivateCertificate::~NearbySharePrivateCertificate() = default;
|
||||
|
||||
std::optional<NearbyShareEncryptedMetadataKey>
|
||||
NearbySharePrivateCertificate::EncryptMetadataKey() {
|
||||
std::optional<std::vector<uint8_t>> salt = GenerateUnusedSalt();
|
||||
std::optional<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
salt = GenerateUnusedSalt();
|
||||
if (!salt) {
|
||||
CD_LOG(ERROR, Feature::NS)
|
||||
<< "Encryption failed: Salt generation unsuccessful.";
|
||||
@ -238,17 +254,14 @@ NearbySharePrivateCertificate::EncryptMetadataKey() {
|
||||
}
|
||||
|
||||
auto key = base::as_byte_span(secret_key_->key());
|
||||
auto counter = DeriveNearbyShareKey(*salt, crypto::aes_ctr::kCounterSize);
|
||||
|
||||
DCHECK_EQ(kNearbyShareNumBytesMetadataEncryptionKey,
|
||||
metadata_encryption_key_.size());
|
||||
|
||||
return NearbyShareEncryptedMetadataKey(
|
||||
*salt,
|
||||
crypto::aes_ctr::Encrypt(
|
||||
key,
|
||||
base::span<const uint8_t, crypto::aes_ctr::kCounterSize>(counter),
|
||||
metadata_encryption_key_));
|
||||
auto counter = DeriveNearbyShareKey<crypto::aes_ctr::kCounterSize>(*salt);
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
metadata_encryption_key;
|
||||
base::span(metadata_encryption_key)
|
||||
.copy_from(
|
||||
crypto::aes_ctr::Encrypt(key, counter, metadata_encryption_key_));
|
||||
return NearbyShareEncryptedMetadataKey(std::move(*salt),
|
||||
std::move(metadata_encryption_key));
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8_t>> NearbySharePrivateCertificate::Sign(
|
||||
@ -265,7 +278,8 @@ std::optional<std::vector<uint8_t>> NearbySharePrivateCertificate::Sign(
|
||||
return signature;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> NearbySharePrivateCertificate::HashAuthenticationToken(
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
NearbySharePrivateCertificate::HashAuthenticationToken(
|
||||
base::span<const uint8_t> authentication_token) const {
|
||||
return ComputeAuthenticationTokenHash(authentication_token,
|
||||
base::as_byte_span(secret_key_->key()));
|
||||
@ -401,7 +415,9 @@ NearbySharePrivateCertificate::FromDictionary(const base::Value::Dict& dict) {
|
||||
if (!bytes_opt)
|
||||
return std::nullopt;
|
||||
|
||||
std::vector<uint8_t> metadata_encryption_key = *bytes_opt;
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
metadata_encryption_key;
|
||||
base::span(metadata_encryption_key).copy_from(*bytes_opt);
|
||||
|
||||
bytes_opt = EncodedStringToBytes(dict.FindString(kId));
|
||||
if (!bytes_opt)
|
||||
@ -421,7 +437,8 @@ NearbySharePrivateCertificate::FromDictionary(const base::Value::Dict& dict) {
|
||||
if (!str_ptr)
|
||||
return std::nullopt;
|
||||
|
||||
std::set<std::vector<uint8_t>> consumed_salts = StringToSalts(*str_ptr);
|
||||
std::set<std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
consumed_salts = StringToSalts(*str_ptr);
|
||||
|
||||
return NearbySharePrivateCertificate(
|
||||
visibility, not_before, not_after, std::move(key_pair),
|
||||
@ -429,7 +446,8 @@ NearbySharePrivateCertificate::FromDictionary(const base::Value::Dict& dict) {
|
||||
std::move(unencrypted_metadata), std::move(consumed_salts));
|
||||
}
|
||||
|
||||
std::optional<std::vector<uint8_t>>
|
||||
std::optional<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
NearbySharePrivateCertificate::GenerateUnusedSalt() {
|
||||
if (consumed_salts_.size() >= kNearbyShareMaxNumMetadataEncryptionKeySalts) {
|
||||
CD_LOG(ERROR, Feature::NS) << "All salts exhausted for certificate.";
|
||||
@ -439,14 +457,14 @@ NearbySharePrivateCertificate::GenerateUnusedSalt() {
|
||||
for (size_t attempt = 0;
|
||||
attempt < kNearbyShareMaxNumMetadataEncryptionKeySaltGenerationRetries;
|
||||
++attempt) {
|
||||
std::vector<uint8_t> salt;
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt> salt;
|
||||
if (next_salts_for_testing_.empty()) {
|
||||
salt = GenerateRandomBytes(2u);
|
||||
salt =
|
||||
GenerateRandomBytes<kNearbyShareNumBytesMetadataEncryptionKeySalt>();
|
||||
} else {
|
||||
salt = next_salts_for_testing_.front();
|
||||
next_salts_for_testing_.pop();
|
||||
}
|
||||
DCHECK_EQ(2u, salt.size());
|
||||
|
||||
if (!base::Contains(consumed_salts_, salt)) {
|
||||
consumed_salts_.insert(salt);
|
||||
@ -464,8 +482,8 @@ std::optional<std::vector<uint8_t>>
|
||||
NearbySharePrivateCertificate::EncryptMetadata() const {
|
||||
// Init() keeps a reference to the input key, so that reference must outlive
|
||||
// the lifetime of |aead|.
|
||||
std::vector<uint8_t> derived_key = DeriveNearbyShareKey(
|
||||
metadata_encryption_key_, kNearbyShareNumBytesAesGcmKey);
|
||||
auto derived_key = DeriveNearbyShareKey<kNearbyShareNumBytesAesGcmKey>(
|
||||
metadata_encryption_key_);
|
||||
|
||||
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
|
||||
aead.Init(derived_key);
|
||||
@ -476,7 +494,7 @@ NearbySharePrivateCertificate::EncryptMetadata() const {
|
||||
|
||||
return aead.Seal(metadata_array,
|
||||
/*nonce=*/
|
||||
DeriveNearbyShareKey(base::as_byte_span(secret_key_->key()),
|
||||
kNearbyShareNumBytesAesGcmIv),
|
||||
DeriveNearbyShareKey<kNearbyShareNumBytesAesGcmIv>(
|
||||
base::as_byte_span(secret_key_->key())),
|
||||
/*additional_data=*/base::span<const uint8_t>());
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_PRIVATE_CERTIFICATE_H_
|
||||
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_NEARBY_SHARE_PRIVATE_CERTIFICATE_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <set>
|
||||
@ -15,6 +16,7 @@
|
||||
#include "base/gtest_prod_util.h"
|
||||
#include "base/time/time.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
|
||||
#include "chromeos/ash/services/nearby/public/mojom/nearby_share_settings.mojom.h"
|
||||
#include "third_party/nearby/sharing/proto/encrypted_metadata.pb.h"
|
||||
@ -53,10 +55,13 @@ class NearbySharePrivateCertificate {
|
||||
base::Time not_after,
|
||||
std::unique_ptr<crypto::ECPrivateKey> key_pair,
|
||||
std::unique_ptr<crypto::SymmetricKey> secret_key,
|
||||
std::vector<uint8_t> metadata_encryption_key,
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
metadata_encryption_key,
|
||||
std::vector<uint8_t> id,
|
||||
nearby::sharing::proto::EncryptedMetadata unencrypted_metadata,
|
||||
std::set<std::vector<uint8_t>> consumed_salts);
|
||||
std::set<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
consumed_salts);
|
||||
|
||||
NearbySharePrivateCertificate(const NearbySharePrivateCertificate& other);
|
||||
NearbySharePrivateCertificate& operator=(
|
||||
@ -91,8 +96,8 @@ class NearbySharePrivateCertificate {
|
||||
// Creates a hash of the |authentication_token|, using |secret_key_|. The use
|
||||
// of HKDF and the output vector size is part of the Nearby Share protocol and
|
||||
// conforms with the GmsCore implementation.
|
||||
std::vector<uint8_t> HashAuthenticationToken(
|
||||
base::span<const uint8_t> authentication_token) const;
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
HashAuthenticationToken(base::span<const uint8_t> authentication_token) const;
|
||||
|
||||
// Converts this private certificate to a public certificate proto that can be
|
||||
// shared with select contacts. Returns std::nullopt if the conversion was
|
||||
@ -105,7 +110,9 @@ class NearbySharePrivateCertificate {
|
||||
base::Value::Dict ToDictionary() const;
|
||||
|
||||
// For testing only.
|
||||
base::queue<std::vector<uint8_t>>& next_salts_for_testing() {
|
||||
base::queue<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>&
|
||||
next_salts_for_testing() {
|
||||
return next_salts_for_testing_;
|
||||
}
|
||||
std::optional<base::TimeDelta>& offset_for_testing() {
|
||||
@ -118,7 +125,9 @@ class NearbySharePrivateCertificate {
|
||||
// maximum number of salts have been exhausted or if an unconsumed salt cannot
|
||||
// be found in a fixed number of attempts, though this is highly improbably.
|
||||
// Note: This function is not thread safe.
|
||||
std::optional<std::vector<uint8_t>> GenerateUnusedSalt();
|
||||
std::optional<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
GenerateUnusedSalt();
|
||||
|
||||
// Encrypts |unencrypted_metadata_| with the |metadata_encryption_key_|, using
|
||||
// the |secret_key_| as salt.
|
||||
@ -147,7 +156,8 @@ class NearbySharePrivateCertificate {
|
||||
|
||||
// A 14-byte symmetric key used to encrypt |unencrypted_metadata_|. Not
|
||||
// included in public certificate.
|
||||
std::vector<uint8_t> metadata_encryption_key_;
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
metadata_encryption_key_;
|
||||
|
||||
// An ID for the certificate, generated from the secret key.
|
||||
std::vector<uint8_t> id_;
|
||||
@ -157,10 +167,13 @@ class NearbySharePrivateCertificate {
|
||||
nearby::sharing::proto::EncryptedMetadata unencrypted_metadata_;
|
||||
|
||||
// The set of 2-byte salts already used to encrypt the metadata key.
|
||||
std::set<std::vector<uint8_t>> consumed_salts_;
|
||||
std::set<std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
consumed_salts_;
|
||||
|
||||
// For testing only.
|
||||
base::queue<std::vector<uint8_t>> next_salts_for_testing_;
|
||||
base::queue<
|
||||
std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>>
|
||||
next_salts_for_testing_;
|
||||
std::optional<base::TimeDelta> offset_for_testing_;
|
||||
|
||||
FRIEND_TEST_ALL_PREFIXES(NearbySharePrivateCertificateTest, ToFromDictionary);
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/certificates/test_util.h"
|
||||
|
||||
#include <array>
|
||||
#include <set>
|
||||
|
||||
#include "base/no_destructor.h"
|
||||
@ -67,21 +68,11 @@ const uint8_t kTestCertificateId[] = {
|
||||
0x05, 0xf8, 0x0d, 0x63, 0x59, 0x18, 0xf9, 0x1b, 0xc2, 0x2b, 0x14,
|
||||
0xd7, 0xed, 0x05, 0x71, 0x4d, 0x58, 0xf9, 0x67, 0x02, 0xdd};
|
||||
|
||||
const uint8_t kTestMetadataEncryptionKey[] = {0x60, 0x1e, 0xc3, 0x13, 0x77,
|
||||
0x57, 0x89, 0xa5, 0xb7, 0xa7,
|
||||
0xf5, 0x04, 0xbb, 0xf3};
|
||||
|
||||
const uint8_t kTestMetadataEncryptionKeyTag[] = {
|
||||
0x51, 0x9b, 0x16, 0xd8, 0x91, 0xb4, 0x0d, 0x81, 0x11, 0x21, 0xe3,
|
||||
0x70, 0x42, 0x80, 0x8f, 0x87, 0x23, 0x6a, 0x84, 0x9b, 0xcd, 0xac,
|
||||
0xbc, 0xe3, 0x54, 0xd7, 0xff, 0x53, 0xdf, 0x5d, 0x8a, 0xda};
|
||||
|
||||
const uint8_t kTestSalt[] = {0xf0, 0xf1};
|
||||
|
||||
const uint8_t kTestEncryptedMetadataKey[] = {0x52, 0x0e, 0x7e, 0x6b, 0x8e,
|
||||
0xb5, 0x40, 0xe8, 0xe2, 0xbd,
|
||||
0xa0, 0xee, 0x9d, 0x7b};
|
||||
|
||||
// TODO fix
|
||||
const uint8_t kTestEncryptedMetadata[] = {
|
||||
0x4d, 0x59, 0x5d, 0xb6, 0xac, 0x70, 0x00, 0x8f, 0x32, 0x9d, 0x0d,
|
||||
@ -95,32 +86,6 @@ const uint8_t kTestEncryptedMetadata[] = {
|
||||
// Plaintext "sample" (from RFC 6979 A.2.5).
|
||||
const uint8_t kTestPayloadToSign[] = {0x73, 0x61, 0x6d, 0x70, 0x6c, 0x65};
|
||||
|
||||
// One possible signature (from RFC 6979 A.2.5).
|
||||
const uint8_t kTestSampleSignature[] = {
|
||||
0x30,
|
||||
0x46, // length of remaining data
|
||||
0x02,
|
||||
0x21, // length of r
|
||||
// begin r (note 0x00 padding since leading bit of 0xEF is 1)
|
||||
0x00, 0xEF, 0xD4, 0x8B, 0x2A, 0xAC, 0xB6, 0xA8, 0xFD, 0x11, 0x40, 0xDD,
|
||||
0x9C, 0xD4, 0x5E, 0x81, 0xD6, 0x9D, 0x2C, 0x87, 0x7B, 0x56, 0xAA, 0xF9,
|
||||
0x91, 0xC3, 0x4D, 0x0E, 0xA8, 0x4E, 0xAF, 0x37, 0x16,
|
||||
// end r
|
||||
0x02,
|
||||
0x21, // length of s
|
||||
// begin s (note 0x00 padding since leading bit of 0xF7 is 1)
|
||||
0x00, 0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41, 0xD4, 0x36, 0xC7,
|
||||
0xA1, 0xB6, 0xE2, 0x9F, 0x65, 0xF3, 0xE9, 0x00, 0xDB, 0xB9, 0xAF, 0xF4,
|
||||
0x06, 0x4D, 0xC4, 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8
|
||||
// end s
|
||||
};
|
||||
|
||||
// The result of HKDF of kTestPayloadToSign, using kTestSecretKey as salt. A
|
||||
// trivial info parameter is used, and the output length is fixed to be
|
||||
// kNearbyShareNumBytesAuthenticationTokenHash.
|
||||
const uint8_t kTestPayloadHashUsingSecretKey[] = {0xE2, 0xCB, 0x90,
|
||||
0x58, 0xDE, 0x3A};
|
||||
|
||||
const int64_t kTestNotBeforeMillis = 1881702000000;
|
||||
|
||||
const int64_t kTestValidityOffsetMillis = 1800000; // 30 minutes
|
||||
@ -157,11 +122,13 @@ const std::vector<uint8_t>& GetNearbyShareTestCertificateId() {
|
||||
return *id;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestMetadataEncryptionKey() {
|
||||
static const base::NoDestructor<std::vector<uint8_t>> metadata_encryption_key(
|
||||
kTestMetadataEncryptionKey,
|
||||
kTestMetadataEncryptionKey + kNearbyShareNumBytesMetadataEncryptionKey);
|
||||
return *metadata_encryption_key;
|
||||
const std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>&
|
||||
GetNearbyShareTestMetadataEncryptionKey() {
|
||||
static constexpr std::array<uint8_t,
|
||||
kNearbyShareNumBytesMetadataEncryptionKey>
|
||||
kMetadataEncryptionKey = {0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89,
|
||||
0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3};
|
||||
return kMetadataEncryptionKey;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestMetadataEncryptionKeyTag() {
|
||||
@ -171,10 +138,12 @@ const std::vector<uint8_t>& GetNearbyShareTestMetadataEncryptionKeyTag() {
|
||||
return *tag;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestSalt() {
|
||||
static const base::NoDestructor<std::vector<uint8_t>> salt(
|
||||
std::begin(kTestSalt), std::end(kTestSalt));
|
||||
return *salt;
|
||||
const std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>&
|
||||
GetNearbyShareTestSalt() {
|
||||
static constexpr std::array<uint8_t,
|
||||
kNearbyShareNumBytesMetadataEncryptionKeySalt>
|
||||
kTestSalt = {0xf0, 0xf1};
|
||||
return kTestSalt;
|
||||
}
|
||||
|
||||
const NearbyShareEncryptedMetadataKey&
|
||||
@ -182,8 +151,8 @@ GetNearbyShareTestEncryptedMetadataKey() {
|
||||
static const base::NoDestructor<NearbyShareEncryptedMetadataKey>
|
||||
encrypted_metadata_key(
|
||||
GetNearbyShareTestSalt(),
|
||||
std::vector<uint8_t>(std::begin(kTestEncryptedMetadataKey),
|
||||
std::end(kTestEncryptedMetadataKey)));
|
||||
std::to_array<uint8_t>({0x52, 0x0e, 0x7e, 0x6b, 0x8e, 0xb5, 0x40,
|
||||
0xe8, 0xe2, 0xbd, 0xa0, 0xee, 0x9d, 0x7b}));
|
||||
return *encrypted_metadata_key;
|
||||
}
|
||||
|
||||
@ -228,17 +197,40 @@ const std::vector<uint8_t>& GetNearbyShareTestPayloadToSign() {
|
||||
return *payload;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestSampleSignature() {
|
||||
static const base::NoDestructor<std::vector<uint8_t>> signature(
|
||||
std::begin(kTestSampleSignature), std::end(kTestSampleSignature));
|
||||
return *signature;
|
||||
const std::array<uint8_t, kNearbyShareNumBytesRandomSignature>&
|
||||
GetNearbyShareTestSampleSignature() {
|
||||
// One possible signature (from RFC 6979 A.2.5).
|
||||
static constexpr std::array<uint8_t, kNearbyShareNumBytesRandomSignature>
|
||||
kSignature = {
|
||||
0x30,
|
||||
0x46, // length of remaining data
|
||||
0x02,
|
||||
0x21, // length of r
|
||||
// begin r (note 0x00 padding since leading bit of 0xEF is 1)
|
||||
0x00, 0xEF, 0xD4, 0x8B, 0x2A, 0xAC, 0xB6, 0xA8, 0xFD, 0x11, 0x40,
|
||||
0xDD, 0x9C, 0xD4, 0x5E, 0x81, 0xD6, 0x9D, 0x2C, 0x87, 0x7B, 0x56,
|
||||
0xAA, 0xF9, 0x91, 0xC3, 0x4D, 0x0E, 0xA8, 0x4E, 0xAF, 0x37, 0x16,
|
||||
// end r
|
||||
0x02,
|
||||
0x21, // length of s
|
||||
// begin s (note 0x00 padding since leading bit of 0xF7 is 1)
|
||||
0x00, 0xF7, 0xCB, 0x1C, 0x94, 0x2D, 0x65, 0x7C, 0x41, 0xD4, 0x36,
|
||||
0xC7, 0xA1, 0xB6, 0xE2, 0x9F, 0x65, 0xF3, 0xE9, 0x00, 0xDB, 0xB9,
|
||||
0xAF, 0xF4, 0x06, 0x4D, 0xC4, 0xAB, 0x2F, 0x84, 0x3A, 0xCD, 0xA8
|
||||
// end s
|
||||
};
|
||||
return kSignature;
|
||||
}
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestPayloadHashUsingSecretKey() {
|
||||
static const base::NoDestructor<std::vector<uint8_t>> hash(
|
||||
std::begin(kTestPayloadHashUsingSecretKey),
|
||||
std::end(kTestPayloadHashUsingSecretKey));
|
||||
return *hash;
|
||||
const std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>&
|
||||
GetNearbyShareTestPayloadHashUsingSecretKey() {
|
||||
// The result of HKDF of kTestPayloadToSign, using kTestSecretKey as salt. A
|
||||
// trivial info parameter is used, and the output length is fixed to be
|
||||
// kNearbyShareNumBytesAuthenticationTokenHash.
|
||||
static constexpr std::array<uint8_t,
|
||||
kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
kHash = {0xE2, 0xCB, 0x90, 0x58, 0xDE, 0x3A};
|
||||
return kHash;
|
||||
}
|
||||
|
||||
NearbySharePrivateCertificate GetNearbyShareTestPrivateCertificate(
|
||||
@ -250,7 +242,7 @@ NearbySharePrivateCertificate GetNearbyShareTestPrivateCertificate(
|
||||
GetNearbyShareTestP256KeyPair(), GetNearbyShareTestSecretKey(),
|
||||
GetNearbyShareTestMetadataEncryptionKey(),
|
||||
GetNearbyShareTestCertificateId(), GetNearbyShareTestMetadata(),
|
||||
/*consumed_salts=*/std::set<std::vector<uint8_t>>());
|
||||
/*consumed_salts=*/{});
|
||||
cert.next_salts_for_testing().push(GetNearbyShareTestSalt());
|
||||
return cert;
|
||||
}
|
||||
|
@ -5,10 +5,12 @@
|
||||
#ifndef CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_TEST_UTIL_H_
|
||||
#define CHROME_BROWSER_NEARBY_SHARING_CERTIFICATES_TEST_UTIL_H_
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "base/time/time.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/constants.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_decrypted_public_certificate.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_encrypted_metadata_key.h"
|
||||
#include "chrome/browser/nearby_sharing/certificates/nearby_share_private_certificate.h"
|
||||
@ -30,9 +32,11 @@ const std::vector<uint8_t>& GetNearbyShareTestP256PublicKey();
|
||||
std::unique_ptr<crypto::SymmetricKey> GetNearbyShareTestSecretKey();
|
||||
const std::vector<uint8_t>& GetNearbyShareTestCertificateId();
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestMetadataEncryptionKey();
|
||||
const std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>&
|
||||
GetNearbyShareTestMetadataEncryptionKey();
|
||||
const std::vector<uint8_t>& GetNearbyShareTestMetadataEncryptionKeyTag();
|
||||
const std::vector<uint8_t>& GetNearbyShareTestSalt();
|
||||
const std::array<uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>&
|
||||
GetNearbyShareTestSalt();
|
||||
const NearbyShareEncryptedMetadataKey& GetNearbyShareTestEncryptedMetadataKey();
|
||||
|
||||
base::Time GetNearbyShareTestNotBefore();
|
||||
@ -42,8 +46,10 @@ const nearby::sharing::proto::EncryptedMetadata& GetNearbyShareTestMetadata();
|
||||
const std::vector<uint8_t>& GetNearbyShareTestEncryptedMetadata();
|
||||
|
||||
const std::vector<uint8_t>& GetNearbyShareTestPayloadToSign();
|
||||
const std::vector<uint8_t>& GetNearbyShareTestSampleSignature();
|
||||
const std::vector<uint8_t>& GetNearbyShareTestPayloadHashUsingSecretKey();
|
||||
const std::array<uint8_t, kNearbyShareNumBytesRandomSignature>&
|
||||
GetNearbyShareTestSampleSignature();
|
||||
const std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>&
|
||||
GetNearbyShareTestPayloadHashUsingSecretKey();
|
||||
|
||||
NearbySharePrivateCertificate GetNearbyShareTestPrivateCertificate(
|
||||
nearby_share::mojom::Visibility visibility,
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/nearby_sharing_service_impl.h"
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "ash/public/cpp/new_window_delegate.h"
|
||||
@ -296,6 +297,15 @@ bool isVisibleForAdvertising(nearby_share::mojom::Visibility visibility) {
|
||||
visibility == nearby_share::mojom::Visibility::kYourDevices;
|
||||
}
|
||||
|
||||
NearbyShareEncryptedMetadataKey AdvertisementToKey(
|
||||
const sharing::mojom::AdvertisementPtr& advertisement) {
|
||||
return NearbyShareEncryptedMetadataKey(
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKeySalt>(
|
||||
advertisement->salt),
|
||||
base::span<const uint8_t, kNearbyShareNumBytesMetadataEncryptionKey>(
|
||||
advertisement->encrypted_metadata_key));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
NearbySharingServiceImpl::NearbySharingServiceImpl(
|
||||
@ -1584,16 +1594,22 @@ bool NearbySharingServiceImpl::IsVisibleInBackground(
|
||||
const std::optional<std::vector<uint8_t>>
|
||||
NearbySharingServiceImpl::CreateEndpointInfo(
|
||||
const std::optional<std::string>& device_name) {
|
||||
std::vector<uint8_t> salt;
|
||||
std::vector<uint8_t> encrypted_key;
|
||||
std::array<uint8_t, sharing::Advertisement::kSaltSize> salt;
|
||||
salt = GenerateRandomBytes<sharing::Advertisement::kSaltSize>();
|
||||
std::array<uint8_t,
|
||||
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_key;
|
||||
encrypted_key = GenerateRandomBytes<
|
||||
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize>();
|
||||
|
||||
nearby_share::mojom::Visibility visibility = settings_.GetVisibility();
|
||||
if (isVisibleForAdvertising(visibility)) {
|
||||
std::optional<NearbyShareEncryptedMetadataKey> encrypted_metadata_key =
|
||||
certificate_manager_->EncryptPrivateCertificateMetadataKey(visibility);
|
||||
if (encrypted_metadata_key) {
|
||||
salt = encrypted_metadata_key->salt();
|
||||
encrypted_key = encrypted_metadata_key->encrypted_key();
|
||||
base::span(salt).copy_from(encrypted_metadata_key->salt());
|
||||
base::span(encrypted_key)
|
||||
.copy_from(encrypted_metadata_key->encrypted_key());
|
||||
} else {
|
||||
CD_LOG(WARNING, Feature::NS)
|
||||
<< __func__ << ": Failed to encrypt private certificate metadata key "
|
||||
@ -1601,24 +1617,14 @@ NearbySharingServiceImpl::CreateEndpointInfo(
|
||||
}
|
||||
}
|
||||
|
||||
if (salt.empty() || encrypted_key.empty()) {
|
||||
// Generate random metadata key.
|
||||
salt = GenerateRandomBytes(sharing::Advertisement::kSaltSize);
|
||||
encrypted_key = GenerateRandomBytes(
|
||||
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize);
|
||||
}
|
||||
|
||||
nearby_share::mojom::ShareTargetType device_type =
|
||||
nearby_share::mojom::ShareTargetType::kLaptop;
|
||||
|
||||
std::unique_ptr<sharing::Advertisement> advertisement =
|
||||
sharing::Advertisement::NewInstance(
|
||||
std::move(salt), std::move(encrypted_key), device_type, device_name);
|
||||
if (advertisement) {
|
||||
return advertisement->ToEndpointInfo();
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
sharing::Advertisement::NewInstance(salt, encrypted_key, device_type,
|
||||
device_name);
|
||||
return advertisement ? std::make_optional(advertisement->ToEndpointInfo())
|
||||
: std::nullopt;
|
||||
}
|
||||
|
||||
void NearbySharingServiceImpl::GetBluetoothAdapter() {
|
||||
@ -1822,8 +1828,8 @@ void NearbySharingServiceImpl::OnOutgoingAdvertisementDecoded(
|
||||
|
||||
// Once we get the advertisement, the first thing to do is decrypt the
|
||||
// certificate.
|
||||
NearbyShareEncryptedMetadataKey encrypted_metadata_key(
|
||||
advertisement->salt, advertisement->encrypted_metadata_key);
|
||||
NearbyShareEncryptedMetadataKey encrypted_metadata_key =
|
||||
AdvertisementToKey(advertisement);
|
||||
GetCertificateManager()->GetDecryptedPublicCertificate(
|
||||
std::move(encrypted_metadata_key),
|
||||
base::BindOnce(&NearbySharingServiceImpl::OnOutgoingDecryptedCertificate,
|
||||
@ -3324,8 +3330,8 @@ void NearbySharingServiceImpl::OnIncomingAdvertisementDecoded(
|
||||
transfer_profiler_->OnIncomingEndpointDecoded(endpoint_id,
|
||||
IsInHighVisibility());
|
||||
|
||||
NearbyShareEncryptedMetadataKey encrypted_metadata_key(
|
||||
advertisement->salt, advertisement->encrypted_metadata_key);
|
||||
NearbyShareEncryptedMetadataKey encrypted_metadata_key =
|
||||
AdvertisementToKey(advertisement);
|
||||
GetCertificateManager()->GetDecryptedPublicCertificate(
|
||||
std::move(encrypted_metadata_key),
|
||||
base::BindOnce(&NearbySharingServiceImpl::OnIncomingDecryptedCertificate,
|
||||
|
@ -4,9 +4,11 @@
|
||||
|
||||
#include "chrome/browser/nearby_sharing/nearby_sharing_service_impl.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/barrier_closure.h"
|
||||
#include "base/containers/span.h"
|
||||
@ -848,10 +850,16 @@ class NearbySharingServiceImplTestBase : public testing::Test {
|
||||
device_name = kDeviceName;
|
||||
}
|
||||
|
||||
auto encrypted_metadata_key =
|
||||
GetNearbyShareTestEncryptedMetadataKey();
|
||||
sharing::mojom::AdvertisementPtr advertisement =
|
||||
sharing::mojom::Advertisement::New(
|
||||
GetNearbyShareTestEncryptedMetadataKey().salt(),
|
||||
GetNearbyShareTestEncryptedMetadataKey().encrypted_key(),
|
||||
std::vector<uint8_t>(
|
||||
encrypted_metadata_key.salt().begin(),
|
||||
encrypted_metadata_key.salt().end()),
|
||||
std::vector<uint8_t>(
|
||||
encrypted_metadata_key.encrypted_key().begin(),
|
||||
encrypted_metadata_key.encrypted_key().end()),
|
||||
kDeviceType, device_name);
|
||||
std::move(callback).Run(std::move(advertisement));
|
||||
}));
|
||||
@ -4674,7 +4682,7 @@ TEST_P(NearbySharingServiceImplTest, ShutdownCallsObserversWithArcCallback) {
|
||||
}
|
||||
|
||||
TEST_P(NearbySharingServiceImplTest, RotateBackgroundAdvertisement_Periodic) {
|
||||
certificate_manager()->set_next_salt({0x00, 0x01});
|
||||
certificate_manager()->set_next_salt(std::to_array<uint8_t>({0x00, 0x01}));
|
||||
SetVisibility(nearby_share::mojom::Visibility::kAllContacts);
|
||||
NiceMock<MockTransferUpdateCallback> callback;
|
||||
NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
|
||||
@ -4684,7 +4692,7 @@ TEST_P(NearbySharingServiceImplTest, RotateBackgroundAdvertisement_Periodic) {
|
||||
auto endpoint_info_initial =
|
||||
fake_nearby_connections_manager_->advertising_endpoint_info();
|
||||
|
||||
certificate_manager()->set_next_salt({0x00, 0x02});
|
||||
certificate_manager()->set_next_salt(std::to_array<uint8_t>({0x00, 0x02}));
|
||||
task_environment_.FastForwardBy(base::Seconds(870));
|
||||
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
|
||||
auto endpoint_info_rotated =
|
||||
@ -4694,7 +4702,7 @@ TEST_P(NearbySharingServiceImplTest, RotateBackgroundAdvertisement_Periodic) {
|
||||
|
||||
TEST_P(NearbySharingServiceImplTest,
|
||||
RotateBackgroundAdvertisement_PrivateCertificatesChange) {
|
||||
certificate_manager()->set_next_salt({0x00, 0x01});
|
||||
certificate_manager()->set_next_salt(std::to_array<uint8_t>({0x00, 0x01}));
|
||||
SetVisibility(nearby_share::mojom::Visibility::kAllContacts);
|
||||
NiceMock<MockTransferUpdateCallback> callback;
|
||||
NearbySharingService::StatusCodes result = service_->RegisterReceiveSurface(
|
||||
@ -4704,7 +4712,7 @@ TEST_P(NearbySharingServiceImplTest,
|
||||
auto endpoint_info_initial =
|
||||
fake_nearby_connections_manager_->advertising_endpoint_info();
|
||||
|
||||
certificate_manager()->set_next_salt({0x00, 0x02});
|
||||
certificate_manager()->set_next_salt(std::to_array<uint8_t>({0x00, 0x02}));
|
||||
certificate_manager()->NotifyPrivateCertificatesChanged();
|
||||
EXPECT_TRUE(fake_nearby_connections_manager_->IsAdvertising());
|
||||
auto endpoint_info_rotated =
|
||||
@ -5265,11 +5273,14 @@ TEST_P(NearbySharingServiceImplTest, VisibilityReminderTimerIsTriggered) {
|
||||
}
|
||||
|
||||
TEST_P(NearbySharingServiceImplTest, CreateShareTarget) {
|
||||
auto encrypted_metadata_key = GetNearbyShareTestEncryptedMetadataKey();
|
||||
sharing::mojom::AdvertisementPtr advertisement =
|
||||
sharing::mojom::Advertisement::New(
|
||||
GetNearbyShareTestEncryptedMetadataKey().salt(),
|
||||
GetNearbyShareTestEncryptedMetadataKey().encrypted_key(), kDeviceType,
|
||||
kDeviceName);
|
||||
std::vector<uint8_t>(encrypted_metadata_key.salt().begin(),
|
||||
encrypted_metadata_key.salt().end()),
|
||||
std::vector<uint8_t>(encrypted_metadata_key.encrypted_key().begin(),
|
||||
encrypted_metadata_key.encrypted_key().end()),
|
||||
kDeviceType, kDeviceName);
|
||||
|
||||
// Flip |for_self_share| to true to ensure the resulting ShareTarget picks
|
||||
// this up.
|
||||
@ -5280,7 +5291,7 @@ TEST_P(NearbySharingServiceImplTest, CreateShareTarget) {
|
||||
|
||||
std::optional<NearbyShareDecryptedPublicCertificate> certificate =
|
||||
NearbyShareDecryptedPublicCertificate::DecryptPublicCertificate(
|
||||
certificate_proto, GetNearbyShareTestEncryptedMetadataKey());
|
||||
certificate_proto, encrypted_metadata_key);
|
||||
ASSERT_TRUE(certificate.has_value());
|
||||
ASSERT_EQ(certificate_proto.for_self_share(), certificate->for_self_share());
|
||||
|
||||
|
@ -17,11 +17,6 @@
|
||||
|
||||
namespace {
|
||||
|
||||
// The size of the random byte array used for the encryption frame's signed data
|
||||
// if a valid signature cannot be generated. This size is consistent with the
|
||||
// GmsCore implementation.
|
||||
const size_t kNearbyShareNumBytesRandomSignature = 72;
|
||||
|
||||
std::ostream& operator<<(
|
||||
std::ostream& out,
|
||||
const PairedKeyVerificationRunner::PairedKeyVerificationResult& obj) {
|
||||
@ -255,22 +250,6 @@ void PairedKeyVerificationRunner::SendCertificateInfo() {
|
||||
}
|
||||
|
||||
void PairedKeyVerificationRunner::SendPairedKeyEncryptionFrame() {
|
||||
std::optional<std::vector<uint8_t>> signature =
|
||||
certificate_manager_->SignWithPrivateCertificate(
|
||||
visibility_, PadPrefix(local_prefix_, raw_token_));
|
||||
if (!signature || signature->empty()) {
|
||||
signature = GenerateRandomBytes(kNearbyShareNumBytesRandomSignature);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> certificate_id_hash;
|
||||
if (certificate_) {
|
||||
certificate_id_hash = certificate_->HashAuthenticationToken(raw_token_);
|
||||
}
|
||||
if (certificate_id_hash.empty()) {
|
||||
certificate_id_hash =
|
||||
GenerateRandomBytes(kNearbyShareNumBytesAuthenticationTokenHash);
|
||||
}
|
||||
|
||||
nearby::sharing::service::proto::Frame frame;
|
||||
frame.set_version(nearby::sharing::service::proto::Frame::V1);
|
||||
nearby::sharing::service::proto::V1Frame* v1_frame = frame.mutable_v1();
|
||||
@ -278,9 +257,25 @@ void PairedKeyVerificationRunner::SendPairedKeyEncryptionFrame() {
|
||||
nearby::sharing::service::proto::V1Frame::PAIRED_KEY_ENCRYPTION);
|
||||
nearby::sharing::service::proto::PairedKeyEncryptionFrame* encryption_frame =
|
||||
v1_frame->mutable_paired_key_encryption();
|
||||
encryption_frame->set_signed_data(signature->data(), signature->size());
|
||||
encryption_frame->set_secret_id_hash(certificate_id_hash.data(),
|
||||
certificate_id_hash.size());
|
||||
if (std::optional<std::vector<uint8_t>> signature =
|
||||
certificate_manager_->SignWithPrivateCertificate(
|
||||
visibility_, PadPrefix(local_prefix_, raw_token_));
|
||||
signature && !signature->empty()) {
|
||||
encryption_frame->set_signed_data(signature->data(), signature->size());
|
||||
} else {
|
||||
auto random_bytes =
|
||||
GenerateRandomBytes<kNearbyShareNumBytesRandomSignature>();
|
||||
encryption_frame->set_signed_data(random_bytes.data(), random_bytes.size());
|
||||
}
|
||||
{
|
||||
std::array<uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>
|
||||
certificate_id_hash =
|
||||
certificate_ ? certificate_->HashAuthenticationToken(raw_token_)
|
||||
: GenerateRandomBytes<
|
||||
kNearbyShareNumBytesAuthenticationTokenHash>();
|
||||
encryption_frame->set_secret_id_hash(certificate_id_hash.data(),
|
||||
certificate_id_hash.size());
|
||||
}
|
||||
std::vector<uint8_t> data(frame.ByteSize());
|
||||
frame.SerializeToArray(data.data(), frame.ByteSize());
|
||||
|
||||
@ -290,10 +285,12 @@ void PairedKeyVerificationRunner::SendPairedKeyEncryptionFrame() {
|
||||
PairedKeyVerificationRunner::PairedKeyVerificationResult
|
||||
PairedKeyVerificationRunner::VerifyRemotePublicCertificate(
|
||||
const sharing::mojom::V1FramePtr& frame) {
|
||||
std::optional<std::vector<uint8_t>> hash =
|
||||
certificate_manager_->HashAuthenticationTokenWithPrivateCertificate(
|
||||
visibility_, raw_token_);
|
||||
if (hash && *hash == frame->get_paired_key_encryption()->secret_id_hash) {
|
||||
if (std::optional<std::array<
|
||||
uint8_t, kNearbyShareNumBytesAuthenticationTokenHash>> hash =
|
||||
certificate_manager_->HashAuthenticationTokenWithPrivateCertificate(
|
||||
visibility_, raw_token_);
|
||||
hash && std::ranges::equal(
|
||||
*hash, frame->get_paired_key_encryption()->secret_id_hash)) {
|
||||
CD_LOG(VERBOSE, Feature::NS)
|
||||
<< __func__ << ": Successfully verified remote public certificate.";
|
||||
return PairedKeyVerificationResult::kSuccess;
|
||||
|
@ -1005,9 +1005,9 @@ std::vector<uint8_t> EncryptWrappedPIN(
|
||||
0x3a, 0x63, 0x68, 0x72, 0x6f, 0x6d, 0x65, 0x3a, 0x47, 0x50, 0x4d,
|
||||
0x20, 0x50, 0x49, 0x4e, 0x20, 0x64, 0x61, 0x74, 0x61, 0x20, 0x77,
|
||||
0x72, 0x61, 0x70, 0x70, 0x69, 0x6e, 0x67, 0x20, 0x6b, 0x65, 0x79};
|
||||
const std::vector<uint8_t> derived_key = crypto::HkdfSha256(
|
||||
const std::array<uint8_t, 32> derived_key = crypto::HkdfSha256<32>(
|
||||
security_domain_secret, /*salt=*/base::span<const uint8_t>(),
|
||||
kKeyPurposePinDataKey, 32);
|
||||
kKeyPurposePinDataKey);
|
||||
crypto::Aead aead(crypto::Aead::AeadAlgorithm::AES_256_GCM);
|
||||
aead.Init(derived_key);
|
||||
uint8_t nonce[12];
|
||||
|
@ -2,10 +2,12 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "chrome/services/sharing/nearby/decoder/advertisement_decoder.h"
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/memory/ptr_util.h"
|
||||
#include "base/strings/string_util.h"
|
||||
@ -67,8 +69,7 @@ std::unique_ptr<sharing::Advertisement> AdvertisementDecoder::FromEndpointInfo(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto iter = endpoint_info.begin();
|
||||
uint8_t first_byte = *iter++;
|
||||
uint8_t first_byte = endpoint_info.take_first_elem();
|
||||
|
||||
int version = ParseVersion(first_byte);
|
||||
if (version < 0 || version > kMaxSupportedAdvertisementParsedVersionNumber) {
|
||||
@ -81,19 +82,24 @@ std::unique_ptr<sharing::Advertisement> AdvertisementDecoder::FromEndpointInfo(
|
||||
nearby_share::mojom::ShareTargetType device_type =
|
||||
ParseDeviceType(first_byte);
|
||||
|
||||
std::vector<uint8_t> salt(iter, iter + sharing::Advertisement::kSaltSize);
|
||||
iter += sharing::Advertisement::kSaltSize;
|
||||
std::array<uint8_t, sharing::Advertisement::kSaltSize> salt;
|
||||
base::span(salt).copy_from(
|
||||
endpoint_info.take_first<sharing::Advertisement::kSaltSize>());
|
||||
|
||||
std::vector<uint8_t> encrypted_metadata_key(
|
||||
iter, iter + sharing::Advertisement::kMetadataEncryptionKeyHashByteSize);
|
||||
iter += sharing::Advertisement::kMetadataEncryptionKeyHashByteSize;
|
||||
std::array<uint8_t,
|
||||
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key;
|
||||
base::span(encrypted_metadata_key)
|
||||
.copy_from(endpoint_info.take_first<
|
||||
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize>());
|
||||
|
||||
int device_name_length = 0;
|
||||
if (iter != endpoint_info.end())
|
||||
device_name_length = *iter++ & 0xff;
|
||||
size_t device_name_length = 0;
|
||||
if (!endpoint_info.empty()) {
|
||||
device_name_length = endpoint_info.take_first_elem();
|
||||
}
|
||||
|
||||
if (endpoint_info.end() - iter < device_name_length ||
|
||||
(device_name_length == 0 && has_device_name)) {
|
||||
if ((has_device_name && !device_name_length) ||
|
||||
endpoint_info.size() < device_name_length) {
|
||||
LOG(ERROR) << "Failed to parse advertisement because the device name did "
|
||||
"not match the expected length "
|
||||
<< device_name_length;
|
||||
@ -101,9 +107,9 @@ std::unique_ptr<sharing::Advertisement> AdvertisementDecoder::FromEndpointInfo(
|
||||
}
|
||||
|
||||
std::optional<std::string> optional_device_name;
|
||||
if (device_name_length > 0) {
|
||||
optional_device_name = std::string(iter, iter + device_name_length);
|
||||
iter += device_name_length;
|
||||
if (device_name_length) {
|
||||
optional_device_name = std::string(
|
||||
base::as_string_view(endpoint_info.first(device_name_length)));
|
||||
|
||||
if (!base::IsStringUTF8(*optional_device_name)) {
|
||||
LOG(ERROR) << "Failed to parse advertisement because the device name was "
|
||||
|
@ -19,14 +19,13 @@ namespace sharing {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kDeviceName[] = "deviceName";
|
||||
constexpr char kDeviceName[] = "deviceName";
|
||||
// Salt for advertisement.
|
||||
const std::vector<uint8_t> kSalt(Advertisement::kSaltSize, 0);
|
||||
constexpr std::array<uint8_t, Advertisement::kSaltSize> kSalt = {};
|
||||
// Key for encrypting personal info metadata.
|
||||
static const std::vector<uint8_t> kEncryptedMetadataKey(
|
||||
Advertisement::kMetadataEncryptionKeyHashByteSize,
|
||||
0);
|
||||
const nearby_share::mojom::ShareTargetType kDeviceType =
|
||||
constexpr std::array<uint8_t, Advertisement::kMetadataEncryptionKeyHashByteSize>
|
||||
kEncryptedMetadataKey = {};
|
||||
constexpr nearby_share::mojom::ShareTargetType kDeviceType =
|
||||
nearby_share::mojom::ShareTargetType::kPhone;
|
||||
|
||||
class AdvertisementDecoderTest : public testing::Test {
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include "base/functional/callback.h"
|
||||
#include "chrome/services/sharing/nearby/decoder/advertisement_decoder.h"
|
||||
@ -238,7 +239,10 @@ void NearbySharingDecoder::DecodeAdvertisement(
|
||||
}
|
||||
|
||||
std::move(callback).Run(mojom::Advertisement::New(
|
||||
advertisement->salt(), advertisement->encrypted_metadata_key(),
|
||||
std::vector<uint8_t>(advertisement->salt().begin(),
|
||||
advertisement->salt().end()),
|
||||
std::vector<uint8_t>(advertisement->encrypted_metadata_key().begin(),
|
||||
advertisement->encrypted_metadata_key().end()),
|
||||
advertisement->device_type(), advertisement->device_name()));
|
||||
}
|
||||
|
||||
|
@ -24,22 +24,22 @@ namespace sharing {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kDeviceName[] = "deviceName";
|
||||
constexpr char kDeviceName[] = "deviceName";
|
||||
// Salt for advertisement.
|
||||
const std::vector<uint8_t> kSalt(Advertisement::kSaltSize, 0);
|
||||
constexpr std::array<uint8_t, Advertisement::kSaltSize> kSalt = {};
|
||||
// Key for encrypting personal info metadata.
|
||||
static const std::vector<uint8_t> kEncryptedMetadataKey(
|
||||
Advertisement::kMetadataEncryptionKeyHashByteSize,
|
||||
0);
|
||||
const nearby_share::mojom::ShareTargetType kDeviceType =
|
||||
constexpr std::array<uint8_t, Advertisement::kMetadataEncryptionKeyHashByteSize>
|
||||
kEncryptedMetadataKey = {};
|
||||
constexpr nearby_share::mojom::ShareTargetType kDeviceType =
|
||||
nearby_share::mojom::ShareTargetType::kPhone;
|
||||
|
||||
void ExpectEquals(const Advertisement& self,
|
||||
const mojom::AdvertisementPtr& other) {
|
||||
EXPECT_EQ(self.device_type(), other->device_type);
|
||||
EXPECT_EQ(self.device_name(), other->device_name);
|
||||
EXPECT_EQ(self.salt(), other->salt);
|
||||
EXPECT_EQ(self.encrypted_metadata_key(), other->encrypted_metadata_key);
|
||||
EXPECT_EQ(self.salt(), base::span(other->salt));
|
||||
EXPECT_EQ(self.encrypted_metadata_key(),
|
||||
base::span(other->encrypted_metadata_key));
|
||||
}
|
||||
|
||||
void ExpectFrameContainsIntroduction(
|
||||
|
@ -43,26 +43,11 @@ namespace sharing {
|
||||
|
||||
// static
|
||||
std::unique_ptr<Advertisement> Advertisement::NewInstance(
|
||||
std::vector<uint8_t> salt,
|
||||
std::vector<uint8_t> encrypted_metadata_key,
|
||||
base::span<const uint8_t, kSaltSize> salt,
|
||||
base::span<const uint8_t, kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key,
|
||||
nearby_share::mojom::ShareTargetType device_type,
|
||||
std::optional<std::string> device_name) {
|
||||
if (salt.size() != sharing::Advertisement::kSaltSize) {
|
||||
LOG(ERROR) << "Failed to create advertisement because the salt did "
|
||||
"not match the expected length "
|
||||
<< salt.size();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (encrypted_metadata_key.size() !=
|
||||
sharing::Advertisement::kMetadataEncryptionKeyHashByteSize) {
|
||||
LOG(ERROR) << "Failed to create advertisement because the encrypted "
|
||||
"metadata key did "
|
||||
"not match the expected length "
|
||||
<< encrypted_metadata_key.size();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (device_name && device_name->size() > UINT8_MAX) {
|
||||
LOG(ERROR) << "Failed to create advertisement because device name "
|
||||
"was over UINT8_MAX: "
|
||||
@ -102,15 +87,18 @@ std::vector<uint8_t> Advertisement::ToEndpointInfo() {
|
||||
}
|
||||
|
||||
// private
|
||||
Advertisement::Advertisement(int version,
|
||||
std::vector<uint8_t> salt,
|
||||
std::vector<uint8_t> encrypted_metadata_key,
|
||||
nearby_share::mojom::ShareTargetType device_type,
|
||||
std::optional<std::string> device_name)
|
||||
Advertisement::Advertisement(
|
||||
int version,
|
||||
base::span<const uint8_t, kSaltSize> salt,
|
||||
base::span<const uint8_t, kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key,
|
||||
nearby_share::mojom::ShareTargetType device_type,
|
||||
std::optional<std::string> device_name)
|
||||
: version_(version),
|
||||
salt_(std::move(salt)),
|
||||
encrypted_metadata_key_(std::move(encrypted_metadata_key)),
|
||||
device_type_(device_type),
|
||||
device_name_(std::move(device_name)) {}
|
||||
device_name_(std::move(device_name)) {
|
||||
base::span(salt_).copy_from(salt);
|
||||
base::span(encrypted_metadata_key_).copy_from(encrypted_metadata_key);
|
||||
}
|
||||
|
||||
} // namespace sharing
|
||||
|
@ -7,11 +7,13 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
#include "chromeos/ash/services/nearby/public/mojom/nearby_share_target_types.mojom.h"
|
||||
|
||||
namespace sharing {
|
||||
@ -22,9 +24,13 @@ namespace sharing {
|
||||
// a missing device name indicates the advertisement is contacts-only.
|
||||
class Advertisement {
|
||||
public:
|
||||
static constexpr uint8_t kSaltSize = 2;
|
||||
static constexpr uint8_t kMetadataEncryptionKeyHashByteSize = 14;
|
||||
|
||||
static std::unique_ptr<Advertisement> NewInstance(
|
||||
std::vector<uint8_t> salt,
|
||||
std::vector<uint8_t> encrypted_metadata_key,
|
||||
base::span<const uint8_t, kSaltSize> salt,
|
||||
base::span<const uint8_t, kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key,
|
||||
nearby_share::mojom::ShareTargetType device_type,
|
||||
std::optional<std::string> device_name);
|
||||
|
||||
@ -36,8 +42,9 @@ class Advertisement {
|
||||
std::vector<uint8_t> ToEndpointInfo();
|
||||
|
||||
int version() const { return version_; }
|
||||
const std::vector<uint8_t>& salt() const { return salt_; }
|
||||
const std::vector<uint8_t>& encrypted_metadata_key() const {
|
||||
base::span<const uint8_t, kSaltSize> salt() const { return salt_; }
|
||||
base::span<const uint8_t, kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key() const {
|
||||
return encrypted_metadata_key_;
|
||||
}
|
||||
nearby_share::mojom::ShareTargetType device_type() const {
|
||||
@ -46,13 +53,11 @@ class Advertisement {
|
||||
const std::optional<std::string>& device_name() const { return device_name_; }
|
||||
bool HasDeviceName() const { return device_name_.has_value(); }
|
||||
|
||||
static const uint8_t kSaltSize = 2;
|
||||
static const uint8_t kMetadataEncryptionKeyHashByteSize = 14;
|
||||
|
||||
private:
|
||||
Advertisement(int version,
|
||||
std::vector<uint8_t> salt,
|
||||
std::vector<uint8_t> encrypted_metadata_key,
|
||||
base::span<const uint8_t, kSaltSize> salt,
|
||||
base::span<const uint8_t, kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key,
|
||||
nearby_share::mojom::ShareTargetType device_type,
|
||||
std::optional<std::string> device_name);
|
||||
|
||||
@ -62,13 +67,14 @@ class Advertisement {
|
||||
|
||||
// Random bytes that were used as salt during encryption of public certificate
|
||||
// metadata.
|
||||
std::vector<uint8_t> salt_;
|
||||
std::array<uint8_t, kSaltSize> salt_;
|
||||
|
||||
// An encrypted symmetric key that was used to encrypt public certificate
|
||||
// metadata, including an account identifier signifying the remote device.
|
||||
// The key can be decrypted using |salt| and the corresponding public
|
||||
// certificate's secret/authenticity key.
|
||||
std::vector<uint8_t> encrypted_metadata_key_;
|
||||
std::array<uint8_t, kMetadataEncryptionKeyHashByteSize>
|
||||
encrypted_metadata_key_;
|
||||
|
||||
// The type of device that the advertisement identifies.
|
||||
nearby_share::mojom::ShareTargetType device_type_;
|
||||
@ -79,4 +85,4 @@ class Advertisement {
|
||||
|
||||
} // namespace sharing
|
||||
|
||||
#endif // CHROME_SERVICES_SHARING_PUBLIC_CPP_ADVERTISEMENT_H_
|
||||
#endif // CHROME_SERVICES_SHARING_PUBLIC_CPP_ADVERTISEMENT_H_
|
||||
|
@ -2,12 +2,13 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "chrome/services/sharing/public/cpp/advertisement.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "chrome/services/sharing/public/cpp/advertisement.h"
|
||||
|
||||
#include "base/strings/strcat.h"
|
||||
#include "base/test/task_environment.h"
|
||||
@ -18,14 +19,13 @@ namespace sharing {
|
||||
|
||||
namespace {
|
||||
|
||||
const char kDeviceName[] = "deviceName";
|
||||
constexpr char kDeviceName[] = "deviceName";
|
||||
// Salt for advertisement.
|
||||
const std::vector<uint8_t> kSalt(Advertisement::kSaltSize, 0);
|
||||
constexpr std::array<uint8_t, Advertisement::kSaltSize> kSalt = {};
|
||||
// Key for encrypting personal info metadata.
|
||||
static const std::vector<uint8_t> kEncryptedMetadataKey(
|
||||
Advertisement::kMetadataEncryptionKeyHashByteSize,
|
||||
0);
|
||||
const nearby_share::mojom::ShareTargetType kDeviceType =
|
||||
constexpr std::array<uint8_t, Advertisement::kMetadataEncryptionKeyHashByteSize>
|
||||
kEncryptedMetadataKey = {};
|
||||
constexpr nearby_share::mojom::ShareTargetType kDeviceType =
|
||||
nearby_share::mojom::ShareTargetType::kPhone;
|
||||
|
||||
} // namespace
|
||||
@ -53,16 +53,4 @@ TEST(AdvertisementTest, CreateNewInstance) {
|
||||
EXPECT_EQ(kSalt, advertisement->salt());
|
||||
}
|
||||
|
||||
TEST(AdvertisementTest, CreateNewInstanceWithWrongSaltSize) {
|
||||
EXPECT_FALSE(sharing::Advertisement::NewInstance(
|
||||
/* salt= */ std::vector<uint8_t>(5, 5), kEncryptedMetadataKey,
|
||||
kDeviceType, kDeviceName));
|
||||
}
|
||||
|
||||
TEST(AdvertisementTest, CreateNewInstanceWithWrongAccountIdentifierSize) {
|
||||
EXPECT_FALSE(sharing::Advertisement::NewInstance(
|
||||
kSalt, /* encrypted_metadata_key= */ std::vector<uint8_t>(2, 1),
|
||||
kDeviceType, kDeviceName));
|
||||
}
|
||||
|
||||
} // namespace sharing
|
||||
|
@ -90,7 +90,7 @@ class COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) DownloadObfuscator {
|
||||
private:
|
||||
// Shared members.
|
||||
std::vector<uint8_t> nonce_prefix_;
|
||||
std::vector<uint8_t> derived_key_;
|
||||
std::array<uint8_t, kKeySize> derived_key_;
|
||||
uint32_t chunk_counter_ = 0;
|
||||
int64_t total_overhead_ = 0;
|
||||
std::unique_ptr<crypto::SecureHash> unobfuscated_hash_;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "components/enterprise/obfuscation/core/utils.h"
|
||||
|
||||
#include <array>
|
||||
#include <utility>
|
||||
|
||||
#include "base/containers/span.h"
|
||||
@ -20,8 +21,11 @@
|
||||
namespace enterprise_obfuscation {
|
||||
|
||||
HeaderData::HeaderData() = default;
|
||||
HeaderData::HeaderData(std::vector<uint8_t> key, std::vector<uint8_t> prefix)
|
||||
: derived_key(std::move(key)), nonce_prefix(std::move(prefix)) {}
|
||||
HeaderData::HeaderData(base::span<const uint8_t, kKeySize> key,
|
||||
std::vector<uint8_t> prefix)
|
||||
: nonce_prefix(std::move(prefix)) {
|
||||
base::span(derived_key).copy_from(key);
|
||||
}
|
||||
|
||||
HeaderData::HeaderData(const HeaderData& other) = default;
|
||||
HeaderData& HeaderData::operator=(const HeaderData& other) = default;
|
||||
@ -70,7 +74,7 @@ bool IsFileObfuscationEnabled() {
|
||||
}
|
||||
|
||||
base::expected<std::vector<uint8_t>, Error> CreateHeader(
|
||||
std::vector<uint8_t>* derived_key,
|
||||
std::array<uint8_t, kKeySize>* derived_key,
|
||||
std::vector<uint8_t>* nonce_prefix) {
|
||||
if (!IsFileObfuscationEnabled()) {
|
||||
return base::unexpected(Error::kDisabled);
|
||||
@ -90,8 +94,8 @@ base::expected<std::vector<uint8_t>, Error> CreateHeader(
|
||||
header.insert(header.end(), salt.begin(), salt.end());
|
||||
|
||||
// Generate file-specific key.
|
||||
*derived_key = crypto::HkdfSha256(GetSymmetricKey(), salt,
|
||||
base::span<uint8_t>(), kKeySize);
|
||||
*derived_key = crypto::HkdfSha256<kKeySize>(GetSymmetricKey(), salt,
|
||||
base::span<uint8_t>());
|
||||
|
||||
// Generate nonce prefix.
|
||||
*nonce_prefix = crypto::RandBytesAsVector(kNoncePrefixSize);
|
||||
@ -170,8 +174,8 @@ base::expected<HeaderData, Error> GetHeaderData(
|
||||
const auto& [salt, nonce_prefix] = header.split_at<kSaltSize>();
|
||||
|
||||
// Generate file-specific key.
|
||||
std::vector<uint8_t> derived_key =
|
||||
crypto::HkdfSha256(GetSymmetricKey(), salt, {}, kKeySize);
|
||||
std::array<uint8_t, kKeySize> derived_key =
|
||||
crypto::HkdfSha256<kKeySize>(GetSymmetricKey(), salt, {});
|
||||
|
||||
return base::ok(
|
||||
HeaderData(std::move(derived_key), base::ToVector(nonce_prefix)));
|
||||
|
@ -5,6 +5,7 @@
|
||||
#ifndef COMPONENTS_ENTERPRISE_OBFUSCATION_CORE_UTILS_H_
|
||||
#define COMPONENTS_ENTERPRISE_OBFUSCATION_CORE_UTILS_H_
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
|
||||
#include "base/component_export.h"
|
||||
@ -62,7 +63,7 @@ enum class Error {
|
||||
// The header structure is: size of header (1 byte) | salt | noncePrefix.
|
||||
COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION)
|
||||
base::expected<std::vector<uint8_t>, Error> CreateHeader(
|
||||
std::vector<uint8_t>* derived_key,
|
||||
std::array<uint8_t, kKeySize>* derived_key,
|
||||
std::vector<uint8_t>* nonce_prefix);
|
||||
|
||||
// Obfuscate data chunk using crypto::Aead
|
||||
@ -88,7 +89,8 @@ base::expected<size_t, Error> GetObfuscatedChunkSize(
|
||||
// header.
|
||||
struct COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) HeaderData {
|
||||
HeaderData();
|
||||
HeaderData(std::vector<uint8_t> key, std::vector<uint8_t> prefix);
|
||||
HeaderData(base::span<const uint8_t, kKeySize> key,
|
||||
std::vector<uint8_t> prefix);
|
||||
|
||||
HeaderData(const HeaderData& other);
|
||||
HeaderData& operator=(const HeaderData& other);
|
||||
@ -98,7 +100,7 @@ struct COMPONENT_EXPORT(ENTERPRISE_OBFUSCATION) HeaderData {
|
||||
|
||||
~HeaderData();
|
||||
|
||||
std::vector<uint8_t> derived_key;
|
||||
std::array<uint8_t, kKeySize> derived_key;
|
||||
std::vector<uint8_t> nonce_prefix;
|
||||
};
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace {
|
||||
// Helper function to divide data in chunks of random sizes.
|
||||
void ObfuscateTestDataInChunks(base::span<const uint8_t> test_data,
|
||||
std::vector<uint8_t>& obfuscated_content) {
|
||||
std::vector<uint8_t> derived_key;
|
||||
std::array<uint8_t, kKeySize> derived_key;
|
||||
std::vector<uint8_t> nonce_prefix;
|
||||
auto header = CreateHeader(&derived_key, &nonce_prefix);
|
||||
ASSERT_TRUE(header.has_value());
|
||||
@ -81,7 +81,7 @@ TEST_P(ObfuscationUtilsTest, ObfuscateAndDeobfuscateSingleDataChunk) {
|
||||
// Obfuscate the data chunk.
|
||||
std::vector<uint8_t> test_data = base::RandBytesAsVector(test_data_size());
|
||||
|
||||
std::vector<uint8_t> derived_key;
|
||||
std::array<uint8_t, kKeySize> derived_key;
|
||||
std::vector<uint8_t> nonce_prefix;
|
||||
auto header = CreateHeader(&derived_key, &nonce_prefix);
|
||||
constexpr uint32_t kInitialChunkCounter = 0;
|
||||
|
@ -215,9 +215,9 @@ void SecretPortalKeyProvider::ReceivedSecret() {
|
||||
return Finalize(InitStatus::kEmptySecret);
|
||||
}
|
||||
|
||||
auto hashed = crypto::HkdfSha256(
|
||||
auto hashed = crypto::HkdfSha256<Encryptor::Key::kAES256GCMKeySize>(
|
||||
base::span(secret_), base::as_byte_span(kSaltForHkdf),
|
||||
base::as_byte_span(kInfoForHkdf), Encryptor::Key::kAES256GCMKeySize);
|
||||
base::as_byte_span(kInfoForHkdf));
|
||||
secret_.clear();
|
||||
|
||||
Encryptor::Key derived_key(hashed, mojom::Algorithm::kAES256GCM);
|
||||
|
@ -5,6 +5,7 @@
|
||||
#include "components/trusted_vault/securebox.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
@ -115,7 +116,7 @@ bssl::UniquePtr<EC_KEY> GenerateECKey(
|
||||
// computes the EC-DH secret. Appends the |shared_secret|, and computes HKDF of
|
||||
// that. |public_key| and |private_key| might be null, but if either of them is
|
||||
// not null, other must be not null as well. |shared_secret| may be empty.
|
||||
std::vector<uint8_t> SecureBoxComputeSecret(
|
||||
std::array<uint8_t, kAES128KeyLength> SecureBoxComputeSecret(
|
||||
const EC_KEY* private_key,
|
||||
const EC_POINT* public_key,
|
||||
base::span<const uint8_t> shared_secret,
|
||||
@ -135,8 +136,8 @@ std::vector<uint8_t> SecureBoxComputeSecret(
|
||||
}
|
||||
|
||||
std::vector<uint8_t> key_material = ConcatBytes({dh_secret, shared_secret});
|
||||
return crypto::HkdfSha256(key_material, kHkdfSalt, StringToBytes(hkdf_info),
|
||||
kAES128KeyLength);
|
||||
return crypto::HkdfSha256<kAES128KeyLength>(key_material, kHkdfSalt,
|
||||
StringToBytes(hkdf_info));
|
||||
}
|
||||
|
||||
// This function implements AES-GCM, using AES-128, a 96-bit nonce, and 128-bit
|
||||
@ -248,7 +249,7 @@ std::vector<uint8_t> SecureBoxEncryptImpl(
|
||||
base::span<const uint8_t> payload,
|
||||
const crypto::OpenSSLErrStackTracer& err_tracer) {
|
||||
DCHECK_EQ(!!our_key_pair, !!their_public_key);
|
||||
std::vector<uint8_t> secret = SecureBoxComputeSecret(
|
||||
std::array<uint8_t, kAES128KeyLength> secret = SecureBoxComputeSecret(
|
||||
our_key_pair, their_public_key, shared_secret, err_tracer);
|
||||
|
||||
std::vector<uint8_t> nonce = crypto::RandBytesAsVector(kNonceLength);
|
||||
@ -298,7 +299,7 @@ std::optional<std::vector<uint8_t>> SecureBoxDecryptImpl(
|
||||
offset += kECPointLength;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> secret_key = SecureBoxComputeSecret(
|
||||
std::array<uint8_t, kAES128KeyLength> secret_key = SecureBoxComputeSecret(
|
||||
our_private_key, their_ec_public_key_point, shared_secret, err_tracer);
|
||||
|
||||
base::span<const uint8_t> nonce =
|
||||
|
@ -61,6 +61,8 @@ constexpr std::string_view kAadWebauthnCredentialSpecificsPrivateKey = "";
|
||||
// https://www.w3.org/TR/webauthn-2/#signature-counter
|
||||
constexpr uint8_t kSignatureCounter[4] = {0};
|
||||
|
||||
constexpr size_t kEncryptionSecretSize = 32;
|
||||
|
||||
struct PasskeyComparator {
|
||||
bool operator()(const sync_pb::WebauthnCredentialSpecifics& a,
|
||||
const sync_pb::WebauthnCredentialSpecifics& b) const {
|
||||
@ -88,15 +90,14 @@ bool EncryptAes256Gcm(base::span<const uint8_t> key,
|
||||
return aead.Seal(plaintext, nonce, aad, ciphertext);
|
||||
}
|
||||
|
||||
std::vector<uint8_t> DerivePasskeyEncryptionSecret(
|
||||
std::array<uint8_t, kEncryptionSecretSize> DerivePasskeyEncryptionSecret(
|
||||
base::span<const uint8_t> trusted_vault_key) {
|
||||
constexpr std::string_view kHkdfInfo =
|
||||
"KeychainApplicationKey:gmscore_module:com.google.android.gms.fido";
|
||||
constexpr size_t kEncryptionSecretSize = 32u;
|
||||
return crypto::HkdfSha256(trusted_vault_key,
|
||||
/*salt=*/base::span<const uint8_t>(),
|
||||
base::as_bytes(base::span(kHkdfInfo)),
|
||||
kEncryptionSecretSize);
|
||||
return crypto::HkdfSha256<kEncryptionSecretSize>(
|
||||
trusted_vault_key,
|
||||
/*salt=*/base::span<const uint8_t>(),
|
||||
base::as_bytes(base::span(kHkdfInfo)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -7,10 +7,9 @@
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "crypto/hmac.h"
|
||||
#include "third_party/boringssl/src/include/openssl/digest.h"
|
||||
#include "third_party/boringssl/src/include/openssl/hkdf.h"
|
||||
|
||||
@ -31,17 +30,4 @@ std::string HkdfSha256(std::string_view secret,
|
||||
return key;
|
||||
}
|
||||
|
||||
std::vector<uint8_t> HkdfSha256(base::span<const uint8_t> secret,
|
||||
base::span<const uint8_t> salt,
|
||||
base::span<const uint8_t> info,
|
||||
size_t derived_key_size) {
|
||||
std::vector<uint8_t> ret;
|
||||
ret.resize(derived_key_size);
|
||||
int result =
|
||||
::HKDF(ret.data(), derived_key_size, EVP_sha256(), secret.data(),
|
||||
secret.size(), salt.data(), salt.size(), info.data(), info.size());
|
||||
DCHECK(result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
@ -6,13 +6,17 @@
|
||||
#define CRYPTO_HKDF_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include "base/check.h"
|
||||
#include "base/containers/span.h"
|
||||
#include "crypto/crypto_export.h"
|
||||
#include "third_party/boringssl/src/include/openssl/digest.h"
|
||||
#include "third_party/boringssl/src/include/openssl/hkdf.h"
|
||||
|
||||
namespace crypto {
|
||||
|
||||
@ -22,11 +26,17 @@ std::string HkdfSha256(std::string_view secret,
|
||||
std::string_view info,
|
||||
size_t derived_key_size);
|
||||
|
||||
CRYPTO_EXPORT
|
||||
std::vector<uint8_t> HkdfSha256(base::span<const uint8_t> secret,
|
||||
base::span<const uint8_t> salt,
|
||||
base::span<const uint8_t> info,
|
||||
size_t derived_key_size);
|
||||
template <size_t KeySize>
|
||||
std::array<uint8_t, KeySize> HkdfSha256(base::span<const uint8_t> secret,
|
||||
base::span<const uint8_t> salt,
|
||||
base::span<const uint8_t> info) {
|
||||
std::array<uint8_t, KeySize> ret;
|
||||
int result =
|
||||
::HKDF(ret.data(), KeySize, EVP_sha256(), secret.data(), secret.size(),
|
||||
salt.data(), salt.size(), info.data(), info.size());
|
||||
DCHECK(result);
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // namespace crypto
|
||||
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
#include "device/fido/cable/fido_cable_handshake_handler.h"
|
||||
|
||||
#include <array>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
@ -163,24 +164,23 @@ bool FidoCableV1HandshakeHandler::ValidateAuthenticatorHandshakeMessage(
|
||||
}
|
||||
|
||||
cable_device_->SetV1EncryptionData(
|
||||
*base::as_byte_span(
|
||||
GetEncryptionKeyAfterSuccessfulHandshake(*sized_nonce_span))
|
||||
.to_fixed_extent<32>(),
|
||||
base::as_byte_span(
|
||||
GetEncryptionKeyAfterSuccessfulHandshake(*sized_nonce_span)),
|
||||
nonce_);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::vector<uint8_t>
|
||||
std::array<uint8_t, 32>
|
||||
FidoCableV1HandshakeHandler::GetEncryptionKeyAfterSuccessfulHandshake(
|
||||
base::span<const uint8_t, 16> authenticator_random_nonce) const {
|
||||
std::vector<uint8_t> nonce_message;
|
||||
fido_parsing_utils::Append(&nonce_message, nonce_);
|
||||
fido_parsing_utils::Append(&nonce_message, client_session_random_);
|
||||
fido_parsing_utils::Append(&nonce_message, authenticator_random_nonce);
|
||||
return crypto::HkdfSha256(session_pre_key_, crypto::SHA256Hash(nonce_message),
|
||||
kCableDeviceEncryptionKeyInfo,
|
||||
/*derived_key_length=*/32);
|
||||
return crypto::HkdfSha256<32>(session_pre_key_,
|
||||
crypto::SHA256Hash(nonce_message),
|
||||
kCableDeviceEncryptionKeyInfo);
|
||||
}
|
||||
|
||||
} // namespace device
|
||||
|
@ -64,7 +64,7 @@ class COMPONENT_EXPORT(DEVICE_FIDO) FidoCableV1HandshakeHandler
|
||||
FRIEND_TEST_ALL_PREFIXES(FidoCableHandshakeHandlerTest,
|
||||
HandshakeFailWithIncorrectAuthenticatorResponse);
|
||||
|
||||
std::vector<uint8_t> GetEncryptionKeyAfterSuccessfulHandshake(
|
||||
std::array<uint8_t, 32> GetEncryptionKeyAfterSuccessfulHandshake(
|
||||
base::span<const uint8_t, 16> authenticator_random_nonce) const;
|
||||
|
||||
const raw_ptr<FidoCableDevice> cable_device_;
|
||||
|
@ -125,15 +125,15 @@ constexpr char kIncorrectHandshakeKey[] = "INCORRECT_HANDSHAKE_KEY_12345678";
|
||||
// factors (i.e. authenticator session random, session pre key, and nonce) are
|
||||
// |kAuthenticatorSessionRandom|, |kTestSessionPreKey|, and |kTestNonce|,
|
||||
// respectively.
|
||||
std::vector<uint8_t> GetExpectedEncryptionKey(
|
||||
std::array<uint8_t, 32> GetExpectedEncryptionKey(
|
||||
base::span<const uint8_t> client_random_nonce) {
|
||||
std::vector<uint8_t> nonce_message =
|
||||
fido_parsing_utils::Materialize(kTestNonce);
|
||||
fido_parsing_utils::Append(&nonce_message, client_random_nonce);
|
||||
fido_parsing_utils::Append(&nonce_message, kAuthenticatorSessionRandom);
|
||||
return crypto::HkdfSha256(kTestSessionPreKey,
|
||||
crypto::SHA256Hash(nonce_message),
|
||||
kCableDeviceEncryptionKeyInfo, 32);
|
||||
return crypto::HkdfSha256<32>(kTestSessionPreKey,
|
||||
crypto::SHA256Hash(nonce_message),
|
||||
kCableDeviceEncryptionKeyInfo);
|
||||
}
|
||||
|
||||
// Given a hello message and handshake key from the authenticator, construct
|
||||
|
Reference in New Issue
Block a user