blob: 0c8e54b0e0b1f499ca792d469cbb28a6af28200a [file] [log] [blame]
// Copyright 2021 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CRYPTOHOME_CRYPTO_RECOVERY_CRYPTO_H_
#define CRYPTOHOME_CRYPTO_RECOVERY_CRYPTO_H_
#include <memory>
#include <brillo/secure_blob.h>
#include "cryptohome/crypto/ecdh_hkdf.h"
#include "cryptohome/crypto/elliptic_curve.h"
namespace cryptohome {
// Cryptographic operations for cryptohome recovery.
// Recovery mechanism involves dealer, publisher, mediator and destination. The
// dealer is invoked during initial setup to generate random shares. The dealer
// functionality is implemented in `GenerateShares` method. The publisher
// performs the actual encryption of the cryptohome recovery key using a
// symmetric key derived from `publisher_dh` - the result of
// `GeneratePublisherKeys` method. The mediator is an external service that is
// invoked during the recovery process to perform mediation of an encrypted
// mediator share. The destination is invoked as part of the recovery UX on the
// device to obtain a cryptohome recovery key. The recovery key can be derived
// from `destination_dh` - the result of `RecoverDestination` method. Note that
// in a successful recovery `destination_dh` should be equal to `publisher_dh`.
class RecoveryCrypto {
public:
// Mediator share is encrypted using AES-GCM with symmetric key derived from
// ECDH+HKDF over mediator public key and ephemeral public key.
// Ephemeral public key `ephemeral_pub_key`, AES-GCM `tag` and `iv` are stored
// in the structure as they are necessary to perform decryption.
struct EncryptedMediatorShare {
brillo::SecureBlob tag;
brillo::SecureBlob iv;
brillo::SecureBlob ephemeral_pub_key;
brillo::SecureBlob encrypted_data;
};
// HSM Payload is created at onboarding and contains all the data that are
// persisted on a chromebook and will be eventually used for recovery.
struct HsmPayload {
brillo::SecureBlob tag;
brillo::SecureBlob iv;
brillo::SecureBlob associated_data;
brillo::SecureBlob cipher_text;
};
// Recovery Request Payload is created during recovery flow.
// `associated_data` contains data from `HsmPayload`, request metadata (RMD),
// and epoch public key (G*r).
struct RequestPayload {
brillo::SecureBlob tag;
brillo::SecureBlob iv;
brillo::SecureBlob associated_data;
brillo::SecureBlob cipher_text;
};
// Constant value of hkdf_info for mediator share. Must be kept in sync with
// the server.
static const char kMediatorShareHkdfInfoValue[];
// Constant value of hkdf_info for request payload plaintext. Must be kept in
// sync with the server.
static const char kRequestPayloadPlainTextHkdfInfoValue[];
// Constant value of hkdf_info for response payload plaintext. Must be kept in
// sync with the server.
static const char kResponsePayloadPlainTextHkdfInfoValue[];
// Elliptic Curve type used by the protocol.
static const EllipticCurve::CurveType kCurve;
// Hash used by HKDF for encrypting mediator share.
static const HkdfHash kHkdfHash;
// Creates instance. Returns nullptr if error occurred.
static std::unique_ptr<RecoveryCrypto> Create();
virtual ~RecoveryCrypto();
// Generates Request payload that will be sent to Recovery Mediator Service
// during recovery process.
// Consist of the following steps:
// 1. Construct associated data AD2 = {hsm_payload, `request_metadata`}.
// 2. Generate symmetric key for encrypting plain text from (G*r)*s
// (`epoch_pub_key` * `channel_priv_key`).
// 3. Generate ephemeral key pair {x, G*x} and calculate an inverse G*-x.
// 4. Save G*x to `ephemeral_pub_key` parameter.
// 5. Construct plain text PT2 = {G*-x}.
// 6. Encrypt {AD2, PT2} using AES-GCM scheme.
virtual bool GenerateRequestPayload(
const HsmPayload& hsm_payload,
const brillo::SecureBlob& request_meta_data,
const brillo::SecureBlob& channel_priv_key,
const brillo::SecureBlob& channel_pub_key,
const brillo::SecureBlob& epoch_pub_key,
RequestPayload* request_payload,
brillo::SecureBlob* ephemeral_pub_key) const = 0;
// Generates HSM payload that will be persisted on a chromebook at enrollment
// to be subsequently used for recovery.
// Consist of the following steps:
// 1. Generate publisher key pair (u, G * u according to the protocol spec).
// 2. Generate dealer key pair (a, G * a)
// 3. Generate 2 shares: mediator (b1) and destination (b2).
// 4. Generate channel key pair (s, G*s) and set `channel_priv_key` and
// `channel_pub_key`.
// 5. Construct associated data {G*s, G*u, `rsa_pub_key`,
// `onboarding_metadata`}.
// 6. Construct plain text {G*a, b2, kav} (note kav == key auth value is used
// only in TPM 1.2 and will be generated for non-empty `rsa_pub_key`).
// 7. Calculate shared secret G*(a(b1+b2)) and convert it to the
// `recovery_key`.
// 8. Generate symmetric key for encrypting PT from (G*h)*u (where G*h is the
// mediator public key provided as input).
// 9. Encrypt {AD, PT} using AES-GCM scheme.
//
// G*s is included in associated data, s is either wrapped with TPM 2.0 or
// stored in host for TPM 1.2.
// The resulting destination share should be either added to TPM 2.0 or sealed
// with kav for TPM 1.2 and stored in the host.
virtual bool GenerateHsmPayload(
const brillo::SecureBlob& mediator_pub_key,
const brillo::SecureBlob& rsa_pub_key,
const brillo::SecureBlob& onboarding_metadata,
HsmPayload* hsm_payload,
brillo::SecureBlob* destination_share,
brillo::SecureBlob* recovery_key,
brillo::SecureBlob* channel_pub_key,
brillo::SecureBlob* channel_priv_key) const = 0;
// Generates shares for recovery. Returns false if error occurred.
// Formula:
// dealer_pub_key = G * (mediator_share + destination_share (mod order))
// where G is an elliptic curve group generator.
// Encrypts `mediator_share` to `mediator_pub_key` and returns as
// `encrypted_mediator_share`.
virtual bool GenerateShares(const brillo::SecureBlob& mediator_pub_key,
EncryptedMediatorShare* encrypted_mediator_share,
brillo::SecureBlob* destination_share,
brillo::SecureBlob* dealer_pub_key) const = 0;
// Generates publisher public keys. Returns false if error occurred.
// Formula:
// publisher_pub_key = G * secret
// publisher_recovery_key = HKDF((dealer_pub_key * secret))
// where G is an elliptic curve group generator.
virtual bool GeneratePublisherKeys(
const brillo::SecureBlob& dealer_pub_key,
brillo::SecureBlob* publisher_pub_key,
brillo::SecureBlob* publisher_recovery_key) const = 0;
// Recovers destination. Returns false if error occurred.
// Formula:
// mediated_point = `mediated_publisher_pub_key` + `ephemeral_pub_key`
// destination_recovery_key = HKDF((publisher_pub_key * destination_share
// + mediated_point))
virtual bool RecoverDestination(
const brillo::SecureBlob& publisher_pub_key,
const brillo::SecureBlob& destination_share,
const base::Optional<brillo::SecureBlob>& ephemeral_pub_key,
const brillo::SecureBlob& mediated_publisher_pub_key,
brillo::SecureBlob* destination_recovery_key) const = 0;
// Decrypt cipher text of response payload `response_payload_ct` and store the
// result in `response_plain_text`. The key for decryption is
// HKDF(ECDH(channel_priv_key, epoch_pub_key)). The associated data is
// `response_payload_ad`. The AES-GCM tag and iv for decryption are
// `response_payload_tag` and `response_payload_iv`.
virtual bool DecryptResponsePayload(
const brillo::SecureBlob& channel_priv_key,
const brillo::SecureBlob& epoch_pub_key,
const brillo::SecureBlob& response_payload_ct,
const brillo::SecureBlob& response_payload_ad,
const brillo::SecureBlob& response_payload_iv,
const brillo::SecureBlob& response_payload_tag,
brillo::SecureBlob* response_plain_text) const = 0;
// Serialize `encrypted_mediator_share` by simply concatenating fixed-length
// blobs into `serialized_blob`. Returns false if error occurred.
static bool SerializeEncryptedMediatorShareForTesting(
const EncryptedMediatorShare& encrypted_mediator_share,
brillo::SecureBlob* serialized_blob);
// Deserialize `encrypted_mediator_share` assuming `serialized_blob` contains
// chunks representing encrypted mediator share fixed-length blobs. Returns
// false if error occurred.
static bool DeserializeEncryptedMediatorShareForTesting(
const brillo::SecureBlob& serialized_blob,
EncryptedMediatorShare* encrypted_mediator_share);
};
} // namespace cryptohome
#endif // CRYPTOHOME_CRYPTO_RECOVERY_CRYPTO_H_