1*3f982cf4SFabien Sanglard // Copyright 2019 The Chromium Authors. All rights reserved.
2*3f982cf4SFabien Sanglard // Use of this source code is governed by a BSD-style license that can be
3*3f982cf4SFabien Sanglard // found in the LICENSE file.
4*3f982cf4SFabien Sanglard
5*3f982cf4SFabien Sanglard #include "cast/streaming/frame_crypto.h"
6*3f982cf4SFabien Sanglard
7*3f982cf4SFabien Sanglard #include <random>
8*3f982cf4SFabien Sanglard #include <utility>
9*3f982cf4SFabien Sanglard
10*3f982cf4SFabien Sanglard #include "openssl/crypto.h"
11*3f982cf4SFabien Sanglard #include "openssl/err.h"
12*3f982cf4SFabien Sanglard #include "openssl/rand.h"
13*3f982cf4SFabien Sanglard #include "util/big_endian.h"
14*3f982cf4SFabien Sanglard #include "util/crypto/openssl_util.h"
15*3f982cf4SFabien Sanglard #include "util/crypto/random_bytes.h"
16*3f982cf4SFabien Sanglard
17*3f982cf4SFabien Sanglard namespace openscreen {
18*3f982cf4SFabien Sanglard namespace cast {
19*3f982cf4SFabien Sanglard
EncryptedFrame()20*3f982cf4SFabien Sanglard EncryptedFrame::EncryptedFrame() {
21*3f982cf4SFabien Sanglard data = absl::Span<uint8_t>(owned_data_);
22*3f982cf4SFabien Sanglard }
23*3f982cf4SFabien Sanglard
24*3f982cf4SFabien Sanglard EncryptedFrame::~EncryptedFrame() = default;
25*3f982cf4SFabien Sanglard
EncryptedFrame(EncryptedFrame && other)26*3f982cf4SFabien Sanglard EncryptedFrame::EncryptedFrame(EncryptedFrame&& other) noexcept
27*3f982cf4SFabien Sanglard : EncodedFrame(static_cast<EncodedFrame&&>(other)),
28*3f982cf4SFabien Sanglard owned_data_(std::move(other.owned_data_)) {
29*3f982cf4SFabien Sanglard data = absl::Span<uint8_t>(owned_data_);
30*3f982cf4SFabien Sanglard other.data = absl::Span<uint8_t>{};
31*3f982cf4SFabien Sanglard }
32*3f982cf4SFabien Sanglard
operator =(EncryptedFrame && other)33*3f982cf4SFabien Sanglard EncryptedFrame& EncryptedFrame::operator=(EncryptedFrame&& other) {
34*3f982cf4SFabien Sanglard this->EncodedFrame::operator=(static_cast<EncodedFrame&&>(other));
35*3f982cf4SFabien Sanglard owned_data_ = std::move(other.owned_data_);
36*3f982cf4SFabien Sanglard data = absl::Span<uint8_t>(owned_data_);
37*3f982cf4SFabien Sanglard other.data = absl::Span<uint8_t>{};
38*3f982cf4SFabien Sanglard return *this;
39*3f982cf4SFabien Sanglard }
40*3f982cf4SFabien Sanglard
FrameCrypto(const std::array<uint8_t,16> & aes_key,const std::array<uint8_t,16> & cast_iv_mask)41*3f982cf4SFabien Sanglard FrameCrypto::FrameCrypto(const std::array<uint8_t, 16>& aes_key,
42*3f982cf4SFabien Sanglard const std::array<uint8_t, 16>& cast_iv_mask)
43*3f982cf4SFabien Sanglard : aes_key_{}, cast_iv_mask_(cast_iv_mask) {
44*3f982cf4SFabien Sanglard // Ensure that the library has been initialized. CRYPTO_library_init() may be
45*3f982cf4SFabien Sanglard // safely called multiple times during the life of a process.
46*3f982cf4SFabien Sanglard CRYPTO_library_init();
47*3f982cf4SFabien Sanglard
48*3f982cf4SFabien Sanglard // Initialize the 244-byte AES_KEY struct once, here at construction time. The
49*3f982cf4SFabien Sanglard // const_cast<> is reasonable as this is a one-time-ctor-initialized value
50*3f982cf4SFabien Sanglard // that will remain constant from here onward.
51*3f982cf4SFabien Sanglard const int return_code = AES_set_encrypt_key(
52*3f982cf4SFabien Sanglard aes_key.data(), aes_key.size() * 8, const_cast<AES_KEY*>(&aes_key_));
53*3f982cf4SFabien Sanglard if (return_code != 0) {
54*3f982cf4SFabien Sanglard ClearOpenSSLERRStack(CURRENT_LOCATION);
55*3f982cf4SFabien Sanglard OSP_LOG_FATAL << "Failure when setting encryption key; unsafe to continue.";
56*3f982cf4SFabien Sanglard OSP_NOTREACHED();
57*3f982cf4SFabien Sanglard }
58*3f982cf4SFabien Sanglard }
59*3f982cf4SFabien Sanglard
60*3f982cf4SFabien Sanglard FrameCrypto::~FrameCrypto() = default;
61*3f982cf4SFabien Sanglard
Encrypt(const EncodedFrame & encoded_frame) const62*3f982cf4SFabien Sanglard EncryptedFrame FrameCrypto::Encrypt(const EncodedFrame& encoded_frame) const {
63*3f982cf4SFabien Sanglard EncryptedFrame result;
64*3f982cf4SFabien Sanglard encoded_frame.CopyMetadataTo(&result);
65*3f982cf4SFabien Sanglard result.owned_data_.resize(encoded_frame.data.size());
66*3f982cf4SFabien Sanglard result.data = absl::Span<uint8_t>(result.owned_data_);
67*3f982cf4SFabien Sanglard EncryptCommon(encoded_frame.frame_id, encoded_frame.data, result.data);
68*3f982cf4SFabien Sanglard return result;
69*3f982cf4SFabien Sanglard }
70*3f982cf4SFabien Sanglard
Decrypt(const EncryptedFrame & encrypted_frame,EncodedFrame * encoded_frame) const71*3f982cf4SFabien Sanglard void FrameCrypto::Decrypt(const EncryptedFrame& encrypted_frame,
72*3f982cf4SFabien Sanglard EncodedFrame* encoded_frame) const {
73*3f982cf4SFabien Sanglard encrypted_frame.CopyMetadataTo(encoded_frame);
74*3f982cf4SFabien Sanglard // AES-CTC is symmetric. Thus, decryption back to the plaintext is the same as
75*3f982cf4SFabien Sanglard // encrypting the ciphertext; and both are the same size.
76*3f982cf4SFabien Sanglard if (encrypted_frame.data.size() < encoded_frame->data.size()) {
77*3f982cf4SFabien Sanglard encoded_frame->data = absl::Span<uint8_t>(encoded_frame->data.data(),
78*3f982cf4SFabien Sanglard encrypted_frame.data.size());
79*3f982cf4SFabien Sanglard }
80*3f982cf4SFabien Sanglard EncryptCommon(encrypted_frame.frame_id, encrypted_frame.data,
81*3f982cf4SFabien Sanglard encoded_frame->data);
82*3f982cf4SFabien Sanglard }
83*3f982cf4SFabien Sanglard
EncryptCommon(FrameId frame_id,absl::Span<const uint8_t> in,absl::Span<uint8_t> out) const84*3f982cf4SFabien Sanglard void FrameCrypto::EncryptCommon(FrameId frame_id,
85*3f982cf4SFabien Sanglard absl::Span<const uint8_t> in,
86*3f982cf4SFabien Sanglard absl::Span<uint8_t> out) const {
87*3f982cf4SFabien Sanglard OSP_DCHECK(!frame_id.is_null());
88*3f982cf4SFabien Sanglard OSP_DCHECK_EQ(in.size(), out.size());
89*3f982cf4SFabien Sanglard
90*3f982cf4SFabien Sanglard // Compute the AES nonce for Cast Streaming payload encryption, which is based
91*3f982cf4SFabien Sanglard // on the |frame_id|.
92*3f982cf4SFabien Sanglard std::array<uint8_t, 16> aes_nonce{/* zero initialized */};
93*3f982cf4SFabien Sanglard static_assert(AES_BLOCK_SIZE == sizeof(aes_nonce),
94*3f982cf4SFabien Sanglard "AES_BLOCK_SIZE is not 16 bytes.");
95*3f982cf4SFabien Sanglard WriteBigEndian<uint32_t>(frame_id.lower_32_bits(), aes_nonce.data() + 8);
96*3f982cf4SFabien Sanglard for (size_t i = 0; i < aes_nonce.size(); ++i) {
97*3f982cf4SFabien Sanglard aes_nonce[i] ^= cast_iv_mask_[i];
98*3f982cf4SFabien Sanglard }
99*3f982cf4SFabien Sanglard
100*3f982cf4SFabien Sanglard std::array<uint8_t, 16> ecount_buf{/* zero initialized */};
101*3f982cf4SFabien Sanglard unsigned int block_offset = 0;
102*3f982cf4SFabien Sanglard AES_ctr128_encrypt(in.data(), out.data(), in.size(), &aes_key_,
103*3f982cf4SFabien Sanglard aes_nonce.data(), ecount_buf.data(), &block_offset);
104*3f982cf4SFabien Sanglard }
105*3f982cf4SFabien Sanglard
106*3f982cf4SFabien Sanglard } // namespace cast
107*3f982cf4SFabien Sanglard } // namespace openscreen
108