| // 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. |
| |
| #ifndef CAST_STREAMING_FRAME_CRYPTO_H_ |
| #define CAST_STREAMING_FRAME_CRYPTO_H_ |
| |
| #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(); |
| EncryptedFrame(EncryptedFrame&&) noexcept; |
| EncryptedFrame& operator=(EncryptedFrame&&); |
| |
| protected: |
| // 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 { |
| public: |
| // 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); |
| |
| ~FrameCrypto(); |
| |
| 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) { |
| return encoded_frame.data.size(); |
| } |
| static int GetPlaintextSize(const EncryptedFrame& encrypted_frame) { |
| return encrypted_frame.data.size(); |
| } |
| |
| private: |
| // 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 |
| |
| #endif // CAST_STREAMING_FRAME_CRYPTO_H_ |