chromium/chromeos/ash/services/device_sync/cryptauth_key_unittest.cc

// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chromeos/ash/services/device_sync/cryptauth_key.h"

#include "chromeos/ash/services/device_sync/value_string_encoding.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace ash::device_sync {

namespace {

const char kFakeHandle[] = "fake-handle";
const char kFakeSymmetricKey[] = "fake-symmetric-key";
const char kFakeSymmetricKeySha256HashBase64Url[] =
    "-lh4oqYTenQmzyIY8XJreGDJ95A4Sk41c15BQPKOmCY=";
const char kFakePublicKey[] = "fake-public-key";
const char kFakePublicKeySha256HashBase64Url[] =
    "vj5oRVhZmlDrE4G4RKNV37Etgr_XuNOwEFAzb888_KM=";
const char kFakePrivateKey[] = "fake-private-key";

}  // namespace

TEST(DeviceSyncCryptAuthKeyTest, CreateSymmetricKey) {
  CryptAuthKey key(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                   cryptauthv2::KeyType::RAW256);

  ASSERT_TRUE(key.IsSymmetricKey());
  ASSERT_FALSE(key.IsAsymmetricKey());
  EXPECT_EQ(key.symmetric_key(), kFakeSymmetricKey);
  EXPECT_EQ(key.status(), CryptAuthKey::Status::kActive);
  EXPECT_EQ(key.type(), cryptauthv2::KeyType::RAW256);
  EXPECT_EQ(key.handle(), kFakeSymmetricKeySha256HashBase64Url);

  CryptAuthKey key_given_handle(kFakeSymmetricKey,
                                CryptAuthKey::Status::kActive,
                                cryptauthv2::KeyType::RAW256, kFakeHandle);
  EXPECT_EQ(key_given_handle.handle(), kFakeHandle);
}

TEST(DeviceSyncCryptAuthKeyTest, CreateAsymmetricKey) {
  CryptAuthKey key(kFakePublicKey, kFakePrivateKey,
                   CryptAuthKey::Status::kActive, cryptauthv2::KeyType::P256);

  ASSERT_FALSE(key.IsSymmetricKey());
  ASSERT_TRUE(key.IsAsymmetricKey());
  EXPECT_EQ(key.public_key(), kFakePublicKey);
  EXPECT_EQ(key.private_key(), kFakePrivateKey);
  EXPECT_EQ(key.status(), CryptAuthKey::Status::kActive);
  EXPECT_EQ(key.type(), cryptauthv2::KeyType::P256);
  EXPECT_EQ(key.handle(), kFakePublicKeySha256HashBase64Url);

  CryptAuthKey key_given_handle(kFakePublicKey, kFakePrivateKey,
                                CryptAuthKey::Status::kActive,
                                cryptauthv2::KeyType::P256, kFakeHandle);
  EXPECT_EQ(key_given_handle.handle(), kFakeHandle);
}

TEST(DeviceSyncCryptAuthKeyTest, SymmetricKeyAsDictionary) {
  CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                             cryptauthv2::KeyType::RAW256, kFakeHandle);

  auto dict =
      base::Value::Dict()
          .Set("handle", kFakeHandle)
          .Set("status", CryptAuthKey::Status::kActive)
          .Set("type", cryptauthv2::KeyType::RAW256)
          .Set("symmetric_key", util::EncodeAsValueString(kFakeSymmetricKey));

  EXPECT_EQ(symmetric_key.AsSymmetricKeyDictionary(), dict);
}

TEST(DeviceSyncCryptAuthKeyTest, AsymmetricKeyAsDictionary) {
  CryptAuthKey asymmetric_key(kFakePublicKey, kFakePrivateKey,
                              CryptAuthKey::Status::kActive,
                              cryptauthv2::KeyType::P256, kFakeHandle);

  auto dict =
      base::Value::Dict()
          .Set("handle", kFakeHandle)
          .Set("status", CryptAuthKey::Status::kActive)
          .Set("type", cryptauthv2::KeyType::P256)
          .Set("public_key", util::EncodeAsValueString(kFakePublicKey))
          .Set("private_key", util::EncodeAsValueString(kFakePrivateKey));

  EXPECT_EQ(asymmetric_key.AsAsymmetricKeyDictionary(), dict);
}

TEST(DeviceSyncCryptAuthKeyTest, SymmetricKeyFromDictionary) {
  auto dict =
      base::Value::Dict()
          .Set("handle", kFakeHandle)
          .Set("status", CryptAuthKey::Status::kActive)
          .Set("type", cryptauthv2::KeyType::RAW256)
          .Set("symmetric_key", util::EncodeAsValueString(kFakeSymmetricKey));

  std::optional<CryptAuthKey> key =
      CryptAuthKey::FromDictionary(std::move(dict));
  ASSERT_TRUE(key);
  EXPECT_EQ(*key, CryptAuthKey(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                               cryptauthv2::KeyType::RAW256, kFakeHandle));
}

TEST(DeviceSyncCryptAuthKeyTest, AsymmetricKeyFromDictionary) {
  auto dict =
      base::Value::Dict()
          .Set("handle", kFakeHandle)
          .Set("status", CryptAuthKey::Status::kActive)
          .Set("type", cryptauthv2::KeyType::P256)
          .Set("public_key", util::EncodeAsValueString(kFakePublicKey))
          .Set("private_key", util::EncodeAsValueString(kFakePrivateKey));

  std::optional<CryptAuthKey> key =
      CryptAuthKey::FromDictionary(std::move(dict));
  ASSERT_TRUE(key);
  EXPECT_EQ(*key, CryptAuthKey(kFakePublicKey, kFakePrivateKey,
                               CryptAuthKey::Status::kActive,
                               cryptauthv2::KeyType::P256, kFakeHandle));
}

TEST(DeviceSyncCryptAuthKeyTest, KeyFromDictionary_MissingHandle) {
  auto dict = base::Value::Dict()
                  .Set("status", CryptAuthKey::Status::kActive)
                  .Set("type", cryptauthv2::KeyType::RAW256)
                  .Set("symmetric_key", kFakeSymmetricKey);

  EXPECT_FALSE(CryptAuthKey::FromDictionary(std::move(dict)));
}

TEST(DeviceSyncCryptAuthKeyTest, KeyFromDictionary_MissingStatus) {
  auto dict = base::Value::Dict()
                  .Set("handle", kFakeHandle)
                  .Set("type", cryptauthv2::KeyType::RAW256)
                  .Set("symmetric_key", kFakeSymmetricKey);

  EXPECT_FALSE(CryptAuthKey::FromDictionary(std::move(dict)));
}

TEST(DeviceSyncCryptAuthKeyTest, KeyFromDictionary_MissingType) {
  auto dict = base::Value::Dict()
                  .Set("handle", kFakeHandle)
                  .Set("status", CryptAuthKey::Status::kActive)
                  .Set("symmetric_key", kFakeSymmetricKey);

  EXPECT_FALSE(CryptAuthKey::FromDictionary(std::move(dict)));
}

TEST(DeviceSyncCryptAuthKeyTest,
     SymmetricKeyFromDictionary_MissingSymmetricKey) {
  auto dict = base::Value::Dict()
                  .Set("handle", kFakeHandle)
                  .Set("status", CryptAuthKey::Status::kActive)
                  .Set("type", cryptauthv2::KeyType::RAW256);

  EXPECT_FALSE(CryptAuthKey::FromDictionary(std::move(dict)));
}

TEST(DeviceSyncCryptAuthKeyTest, AsymmetricKeyFromDictionary_MissingPublicKey) {
  auto dict = base::Value::Dict()
                  .Set("handle", kFakeHandle)
                  .Set("status", CryptAuthKey::Status::kActive)
                  .Set("type", cryptauthv2::KeyType::P256)
                  .Set("private_key", kFakePrivateKey);

  EXPECT_FALSE(CryptAuthKey::FromDictionary(std::move(dict)));
}

TEST(DeviceSyncCryptAuthKeyTest,
     AsymmetricKeyFromDictionary_MissingPrivateKey) {
  auto dict = base::Value::Dict()
                  .Set("handle", kFakeHandle)
                  .Set("status", CryptAuthKey::Status::kActive)
                  .Set("type", cryptauthv2::KeyType::P256)
                  .Set("public_key", kFakePublicKey);

  EXPECT_FALSE(CryptAuthKey::FromDictionary(std::move(dict)));
}

TEST(DeviceSyncCryptAuthKeyTest, Equality) {
  CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                             cryptauthv2::KeyType::RAW256);
  CryptAuthKey asymmetric_key(kFakePublicKey, kFakePrivateKey,
                              CryptAuthKey::Status::kActive,
                              cryptauthv2::KeyType::P256);

  EXPECT_EQ(symmetric_key,
            CryptAuthKey(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                         cryptauthv2::KeyType::RAW256));
  EXPECT_EQ(asymmetric_key, CryptAuthKey(kFakePublicKey, kFakePrivateKey,
                                         CryptAuthKey::Status::kActive,
                                         cryptauthv2::KeyType::P256));
}

TEST(DeviceSyncCryptAuthKeyTest, NotEquality) {
  CryptAuthKey symmetric_key(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                             cryptauthv2::KeyType::RAW256);
  CryptAuthKey asymmetric_key(kFakePublicKey, kFakePrivateKey,
                              CryptAuthKey::Status::kActive,
                              cryptauthv2::KeyType::P256);
  EXPECT_NE(symmetric_key, asymmetric_key);

  EXPECT_NE(symmetric_key,
            CryptAuthKey(kFakeSymmetricKey, CryptAuthKey::Status::kInactive,
                         cryptauthv2::KeyType::RAW256));
  EXPECT_NE(symmetric_key,
            CryptAuthKey(kFakeSymmetricKey, CryptAuthKey::Status::kActive,
                         cryptauthv2::KeyType::RAW128));
  EXPECT_NE(symmetric_key,
            CryptAuthKey("different-sym-key", CryptAuthKey::Status::kActive,
                         cryptauthv2::KeyType::RAW256));

  EXPECT_NE(asymmetric_key, CryptAuthKey(kFakePublicKey, kFakePrivateKey,
                                         CryptAuthKey::Status::kInactive,
                                         cryptauthv2::KeyType::P256));
  EXPECT_NE(asymmetric_key, CryptAuthKey(kFakePublicKey, kFakePrivateKey,
                                         CryptAuthKey::Status::kActive,
                                         cryptauthv2::KeyType::CURVE25519));
  EXPECT_NE(asymmetric_key, CryptAuthKey("different-pub-key", kFakePrivateKey,
                                         CryptAuthKey::Status::kActive,
                                         cryptauthv2::KeyType::P256));
  EXPECT_NE(asymmetric_key, CryptAuthKey(kFakePublicKey, "different-priv-key",
                                         CryptAuthKey::Status::kActive,
                                         cryptauthv2::KeyType::P256));
}

}  // namespace ash::device_sync