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