blob: ba33629f9711d8c0afa5a48fb752ee972aa1fd17 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <stddef.h>
#include <stdint.h>
#include <array>
#include <vector>
#include "absl/types/span.h"
#include "cast/streaming/encoded_frame.h"
#include "openssl/aes.h"
#include "platform/base/macros.h"
namespace openscreen {
namespace cast {
class FrameCollector;
class FrameCrypto;
// A subclass of EncodedFrame that represents an EncodedFrame with encrypted
// payload data, and owns the buffer storing the encrypted payload data. Use
// FrameCrypto (below) to explicitly convert between EncryptedFrames and
// EncodedFrames.
struct EncryptedFrame : public EncodedFrame {
EncryptedFrame(EncryptedFrame&&) noexcept;
EncryptedFrame& operator=(EncryptedFrame&&);
// Since only FrameCrypto and FrameCollector are trusted to generate the
// payload data, only they are allowed direct access to the storage.
friend class FrameCollector;
friend class FrameCrypto;
// Note: EncodedFrame::data must be updated whenever any mutations are
// performed on this member!
std::vector<uint8_t> owned_data_;
// Encrypts EncodedFrames before sending, or decrypts EncryptedFrames that have
// been received.
class FrameCrypto {
// Construct with the given 16-bytes AES key and IV mask. Both arguments
// should be randomly-generated for each new streaming session.
// GenerateRandomBytes() can be used to create them.
FrameCrypto(const std::array<uint8_t, 16>& aes_key,
const std::array<uint8_t, 16>& cast_iv_mask);
EncryptedFrame Encrypt(const EncodedFrame& encoded_frame) const;
// Decrypt the given |encrypted_frame| into the output |encoded_frame|. The
// caller must provide a sufficiently-sized data buffer (see
// GetPlaintextSize()).
void Decrypt(const EncryptedFrame& encrypted_frame,
EncodedFrame* encoded_frame) const;
// AES crypto inputs and outputs (for either encrypting or decrypting) are
// always the same size in bytes. The following are just "documentative code."
static int GetEncryptedSize(const EncodedFrame& encoded_frame) {
static int GetPlaintextSize(const EncryptedFrame& encrypted_frame) {
// The 244-byte AES_KEY struct, derived from the |aes_key| passed to the ctor,
// and initialized by boringssl's AES_set_encrypt_key() function.
const AES_KEY aes_key_;
// Random bytes used in the custom heuristic to generate a different
// initialization vector for each frame.
const std::array<uint8_t, 16> cast_iv_mask_;
// AES-CTR is symmetric. Thus, the "meat" of both Encrypt() and Decrypt() is
// the same.
void EncryptCommon(FrameId frame_id,
absl::Span<const uint8_t> in,
absl::Span<uint8_t> out) const;
} // namespace cast
} // namespace openscreen