| 433 | */ |
| 434 | template<std::size_t max_payload_size> |
| 435 | static inline std::string_view encode_control(session_t *session, const std::string_view &plaintext, std::array<std::uint8_t, max_payload_size> &tagged_cipher) { |
| 436 | static_assert( |
| 437 | max_payload_size >= sizeof(control_encrypted_t) + sizeof(crypto::cipher::tag_size), |
| 438 | "max_payload_size >= sizeof(control_encrypted_t) + sizeof(crypto::cipher::tag_size)" |
| 439 | ); |
| 440 | |
| 441 | if (session->config.controlProtocolType != 13) { |
| 442 | return plaintext; |
| 443 | } |
| 444 | |
| 445 | auto seq = session->control.seq++; |
| 446 | |
| 447 | auto &iv = session->control.outgoing_iv; |
| 448 | if (session->config.encryptionFlagsEnabled & SS_ENC_CONTROL_V2) { |
| 449 | // We use the deterministic IV construction algorithm specified in NIST SP 800-38D |
| 450 | // Section 8.2.1. The sequence number is our "invocation" field and the 'CH' in the |
| 451 | // high bytes is the "fixed" field. Because each client provides their own unique |
| 452 | // key, our values in the fixed field need only uniquely identify each independent |
| 453 | // use of the client's key with AES-GCM in our code. |
| 454 | // |
| 455 | // The sequence number is 32 bits long which allows for 2^32 control stream messages |
| 456 | // to be sent to each client before the IV repeats. |
| 457 | iv.resize(12); |
| 458 | std::copy_n((uint8_t *) &seq, sizeof(seq), std::begin(iv)); |
| 459 | iv[10] = 'H'; // Host originated |
| 460 | iv[11] = 'C'; // Control stream |
| 461 | } else { |
| 462 | // Nvidia's old style encryption uses a 16-byte IV |
| 463 | iv.resize(16); |
| 464 | |
| 465 | iv[0] = (std::uint8_t) seq; |
| 466 | } |
| 467 | |
| 468 | auto packet = (control_encrypted_p) tagged_cipher.data(); |
| 469 | |
| 470 | auto bytes = session->control.cipher.encrypt(plaintext, packet->payload(), &iv); |
| 471 | if (bytes <= 0) { |
| 472 | BOOST_LOG(error) << "Couldn't encrypt control data"sv; |
| 473 | return {}; |
| 474 | } |
| 475 | |
| 476 | std::uint16_t packet_length = bytes + crypto::cipher::tag_size + sizeof(control_encrypted_t::seq); |
| 477 | |
| 478 | packet->encryptedHeaderType = util::endian::little(0x0001); |
| 479 | packet->length = util::endian::little(packet_length); |
| 480 | packet->seq = util::endian::little(seq); |
| 481 | |
| 482 | return std::string_view {(char *) tagged_cipher.data(), packet_length + sizeof(control_encrypted_t) - sizeof(control_encrypted_t::seq)}; |
| 483 | } |
| 484 | |
| 485 | int start_broadcast(broadcast_ctx_t &ctx); |
| 486 | void end_broadcast(broadcast_ctx_t &ctx); |
no test coverage detected