diff --git a/example/simulcrypt_client.cc b/example/simulcrypt_client.cc deleted file mode 100644 index f2a6979..0000000 --- a/example/simulcrypt_client.cc +++ /dev/null @@ -1,80 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 Google LLC. -// -// This software is licensed under the terms defined in the Widevine Master -// License Agreement. For a copy of this agreement, please contact -// widevine-licensing@google.com. -//////////////////////////////////////////////////////////////////////////////// - -// Example client that talks to server_main. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gflags/gflags.h" -#include "glog/logging.h" - -DEFINE_string(server, "", "Server host name"); -DEFINE_int32(port, 0, "Server port number"); - -constexpr uint32_t kBufferSize = 256; - -int main(int argc, char **argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - CHECK(!FLAGS_server.empty()) << "need --server"; - CHECK(FLAGS_port != 0) << "need --port"; - - struct hostent server; - { - int buflen = 1024; - char buf[1024]; - struct hostent *result; - int h_errnop; - gethostbyname_r(/* __name= */ FLAGS_server.c_str(), - /* __result_buf= */ &server, /* __buf= */ buf, - /* __buflen= */ buflen, - /* __result= */ &result, /* __h_errnop= */ &h_errnop); - } - - struct sockaddr_in server_addr; - bzero(reinterpret_cast(&server_addr), sizeof(server_addr)); - server_addr.sin_family = AF_INET; - // TODO(user): Consider using inet_pton() to populate server_addr.sin_addr. - bcopy(server.h_addr, reinterpret_cast(&server_addr.sin_addr.s_addr), - server.h_length); - server_addr.sin_port = htons(FLAGS_port); - - int socket_fd = socket(AF_INET, SOCK_STREAM, /* protocol= */ 0); - CHECK(socket_fd >= 0) << "failed to opening socket"; - CHECK(connect(socket_fd, (struct sockaddr *)&server_addr, - sizeof(server_addr)) >= 0) - << "failed to connect to socket"; - - printf("Please enter the message: "); - char buffer[kBufferSize]; - bzero(buffer, kBufferSize); - fgets(buffer, kBufferSize - 1, stdin); - int total_bytes_written = 0; - while (total_bytes_written != strlen(buffer)) { - int num_bytes_written = write(socket_fd, buffer, strlen(buffer)); - if (num_bytes_written < 0) { - LOG(FATAL) << "ERROR writing to socket: " << strerror(errno); - } - total_bytes_written += num_bytes_written; - } - bzero(buffer, kBufferSize); - if (read(socket_fd, buffer, kBufferSize - 1) < 0) { - LOG(FATAL) << "ERROR reading from socket: " << strerror(errno); - } - printf("Read from buffer: %s\n", buffer); - - close(socket_fd); - return 0; -} diff --git a/example/test_simulcrypt_messages.h b/example/test_simulcrypt_messages.h deleted file mode 100644 index 7bff06d..0000000 --- a/example/test_simulcrypt_messages.h +++ /dev/null @@ -1,166 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 Google LLC. -// -// This software is licensed under the terms defined in the Widevine Master -// License Agreement. For a copy of this agreement, please contact -// widevine-licensing@google.com. -//////////////////////////////////////////////////////////////////////////////// - -// Example Simulcrypt messages used in unit tests and example client. - -#ifndef MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_SIMULCRYPT_MESSAGES_H_ -#define MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_SIMULCRYPT_MESSAGES_H_ - -namespace widevine { -namespace cas { - -const char kTestEcmgStreamSetupMessage[] = { // protocol_version - '\x01', - // message_type - Stream_set-up - '\x01', '\x01', - // message_length - // 18 bytes below, 3 parameters 6 bytes each - '\x00', '\x12', - // parameter_type - ECM_channel_id - '\x00', '\x0e', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x01', - // parameter_type - ECM_stream_id - '\x00', '\x0f', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x02', - // parameter_type - nominal_CP_duration - '\x00', '\x10', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x03'}; - -const char kTestEcmgCwProvisionMessageWithOneCw[] = { - // protocol_version - '\x01', - // message_type - CW_provision - '\x02', '\x01', - // message_length - // 64 bytes below, 3 * 6 + 8 + 10 + 1 * 22 + 6 - '\x00', '\x40', - // parameter_type - ECM_channel_id - '\x00', '\x0e', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x01', - // parameter_type - ECM_stream_id - '\x00', '\x0f', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x02', - // parameter_type - CP_number - '\x00', '\x12', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\xa1', - // parameter_type - access_criteria - '\x00', '\x0d', - // parameter_length - '\x00', '\x04', - // parameter_value - '\x00', '\x00', '\x00', '\x00', - // parameter_type - CW_encryption - '\x00', '\x18', - // parameter_length - '\x00', '\x06', - // parameter_value - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - // parameter_type - CP_CW_combination - '\x00', '\x14', - // parameter_length - 2 + 16 - '\x00', '\x12', - // parameter_value - CP then CW - // CP - '\x00', '\xa1', - // CW (16 bytes) - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - // parameter_type - CP_duration - '\x00', '\x13', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x0a'}; - -const char kTestEcmgCwProvisionMessageWithTwoCw[] = { - // protocol_version - '\x01', - // message_type - CW_provision - '\x02', '\x01', - // message_length - // 86 bytes below, 3 * 6 + 8 + 10 + 2 * 22 + 6 - '\x00', '\x56', - // parameter_type - ECM_channel_id - '\x00', '\x0e', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x01', - // parameter_type - ECM_stream_id - '\x00', '\x0f', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x02', - // parameter_type - CP_number - '\x00', '\x12', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\xa1', - // parameter_type - access_criteria - '\x00', '\x0d', - // parameter_length - '\x00', '\x04', - // parameter_value - '\x00', '\x00', '\x00', '\x00', - // parameter_type - CW_encryption - '\x00', '\x18', - // parameter_length - '\x00', '\x06', - // parameter_value - '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', - // parameter_type - CP_CW_combination - '\x00', '\x14', - // parameter_length - 2 + 16 - '\x00', '\x12', - // parameter_value - CP then CW - // CP - '\x00', '\xa1', - // CW (16 bytes) - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', '\x11', - // parameter_type - CP_CW_combination - '\x00', '\x14', - // parameter_length - 2 + 16 - '\x00', '\x12', - // parameter_value - CP then CW - // CP - '\x00', '\xa2', - // CW (16 bytes) - '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', - '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', '\x22', - // parameter_type - CP_duration - '\x00', '\x13', - // parameter_length - '\x00', '\x02', - // parameter_value - '\x00', '\x0a'}; - -} // namespace cas -} // namespace widevine - -#endif // MEDIA_CAS_PACKAGER_SDK_EXAMPLE_TEST_SIMULCRYPT_MESSAGES_H_ diff --git a/libmedia_cas_packager_sdk.so b/libmedia_cas_packager_sdk.so index 6b5e6d0..06bab3b 100755 Binary files a/libmedia_cas_packager_sdk.so and b/libmedia_cas_packager_sdk.so differ diff --git a/media_cas_packager_sdk/public/simulcrypt_server b/media_cas_packager_sdk/public/simulcrypt_server index 298a45a..965e886 100644 Binary files a/media_cas_packager_sdk/public/simulcrypt_server and b/media_cas_packager_sdk/public/simulcrypt_server differ diff --git a/media_cas_packager_sdk/public/simulcrypt_server.cc b/media_cas_packager_sdk/public/simulcrypt_server.cc deleted file mode 100644 index 96321e3..0000000 --- a/media_cas_packager_sdk/public/simulcrypt_server.cc +++ /dev/null @@ -1,84 +0,0 @@ -//////////////////////////////////////////////////////////////////////////////// -// Copyright 2018 Google LLC. -// -// This software is licensed under the terms defined in the Widevine Master -// License Agreement. For a copy of this agreement, please contact -// widevine-licensing@google.com. -//////////////////////////////////////////////////////////////////////////////// - -// Example server that listens on a port for Simulcrypt API messages. - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gflags/gflags.h" -#include "glog/logging.h" - -DEFINE_int32(port, 0, "Server port number"); - -constexpr uint32_t kBufferSize = 256; -constexpr uint32_t kLicenseBacklog = 5; -constexpr uint32_t kWriteChunkSize = 18; - -int main(int argc, char **argv) { - gflags::ParseCommandLineFlags(&argc, &argv, true); - CHECK(FLAGS_port != 0) << "need --port"; - - struct sockaddr_in server_address; - bzero(reinterpret_cast(&server_address), sizeof(server_address)); - server_address.sin_family = AF_INET; - server_address.sin_addr.s_addr = htonl(INADDR_ANY); - server_address.sin_port = htons(FLAGS_port); - - int listen_socket_fd = socket(AF_INET, SOCK_STREAM, /* protocol= */ 0); - CHECK(listen_socket_fd >= 0) << "failed to open socket"; - CHECK(bind(listen_socket_fd, (struct sockaddr *)&server_address, - sizeof(server_address)) >= 0) - << "error on binding"; - std::cout << "Server listening ..." << std::endl << std::flush; - int return_val = listen(listen_socket_fd, kLicenseBacklog); - switch (return_val) { - case EADDRINUSE: - LOG(FATAL) << "Another socket is already listening on the same port."; - break; - case EBADF: - LOG(FATAL) << "The argument sockfd is not a valid descriptor."; - break; - case ENOTSOCK: - LOG(FATAL) << "The argument sockfd is not a socket."; - break; - case EOPNOTSUPP: - LOG(FATAL) << "The socket is not of a type that supports the listen() " - "operation."; - default: - break; - } - - struct sockaddr_in client_address; - socklen_t clilet_address_size = sizeof(client_address); - int client_socket_fd = accept( - listen_socket_fd, reinterpret_cast(&client_address), - &clilet_address_size); - CHECK(client_socket_fd >= 0) << "error on accept"; - - char buffer[kBufferSize]; - bzero(buffer, kBufferSize); - if (read(client_socket_fd, buffer, kBufferSize - 1) < 0) { - LOG(FATAL) << "ERROR reading from socket"; - } - printf("Here is the message: %s", buffer); - if (write(client_socket_fd, "I got your message", kWriteChunkSize) < 0) { - LOG(FATAL) << "ERROR writing to socket"; - } - - close(client_socket_fd); - close(listen_socket_fd); - return 0; -} diff --git a/media_cas_packager_sdk/public/wv_cas_ecm.h b/media_cas_packager_sdk/public/wv_cas_ecm.h new file mode 100644 index 0000000..54695ab --- /dev/null +++ b/media_cas_packager_sdk/public/wv_cas_ecm.h @@ -0,0 +1,128 @@ +//////////////////////////////////////////////////////////////////////////////// +// Copyright 2018 Google LLC. +// +// This software is licensed under the terms defined in the Widevine Master +// License Agreement. For a copy of this agreement, please contact +// widevine-licensing@google.com. +//////////////////////////////////////////////////////////////////////////////// + +#ifndef MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_ +#define MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_ + +#include +#include +#include +#include +#include +#include + +#include "util/status.h" +#include "media_cas_packager_sdk/internal/ecm.h" +#include "media_cas_packager_sdk/internal/ecm_generator.h" +#include "protos/public/media_cas.pb.h" + +namespace widevine { +namespace cas { + +// Class for generating Widevine CAS ECMs. +// See wv_cas_ecm_test.cc for example usage. +// This class is NOT thread-safe. +class WvCasEcm { + public: + WvCasEcm() = default; + WvCasEcm(const WvCasEcm&) = delete; + WvCasEcm& operator=(const WvCasEcm&) = delete; + virtual ~WvCasEcm() = default; + + // Initialize an instance of this class. + // + // Args: + // - |content_iv_size| iv size in bytes for encrypting the content, + // only support 8 bytes now + // TODO(user): Double-check with jfore@ regarding only support 8 bytes. + // - |key_rotation_enabled| whether key rotation is enabled, + // if this is 'true' only subsequent call to GenerateEcm will be allowed, + // if this is 'false' only subsequent call to GenerateSingleKeyEcm will + // be allowed + // - |crypto_mode| crypto mode for encrypting content, + // kCryptoModeCbc = 0, kCryptoModeCtr = 1 + // only CTR is supported by Widevine CAS plugin for now + // TODO(user): Check with jfore@ regarding supporting kCryptoModeCbc. + // + // Returns: + // - A status indicating whether there was any error during initialization + // + // Note: + // - 'even'/'odd' key in the ECM will be be encrypted using AEC_CBC + util::Status Initialize(int content_iv_size, bool key_rotation_enabled, + int crypto_mode); + + // Generate an ECM containing two keys (even and odd). Can be called when + // |key_rotation_enabled| is initialized to 'true'. + // + // Args: + // - |even_key| clear even content key + // - |even_wrapping_iv| iv used when encrypting |even_key| in the ECM + // - |even_content_iv| iv used along with |even_key| for encrypting content + // - |odd_key| clear odd content key + // - |odd_wrapping_iv| iv used when encrypting |odd_key| in the ECM + // - |odd_content_iv| iv used along with |odd_key| for encrypting content + // - |entitlement_key_id| key id for |entitlement_key| + // - |entitlement_key| entitlement key used to encrypt even and odd keys + // - |ecm| for returning the generated ECM, must not be nullptr + // + // Returns: + // - A status indicating whether there was any error during processing + // + // Note: + // - The same |entitlement_key| will be used to encrypt both |even_key| + // and |odd_key| in the ECM + // - Currently, we only allow |even_content_iv| and |odd_content_iv| + // to be of size 8 bytes, so we assume the encryptor would append suffix + // {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'} + // to |even_content_iv| and |odd_content_iv| to obtain a 16 bytes IV + // before encrypting the content + util::Status GenerateEcm(const std::string& even_key, + const std::string& even_wrapping_iv, + const std::string& even_content_iv, const std::string& odd_key, + const std::string& odd_wrapping_iv, + const std::string& odd_content_iv, + const std::string& entitlement_key_id, + const std::string& entitlement_key, std::string* ecm); + + // Generate an ECM containing only a singe even key. Can be called when + // |key_rotation_enabled| is initialized to 'false'. + // + // Args: + // - |even_key| clear even content key + // - |even_wrapping_iv| iv used when encrypting |even_key| in the ECM + // - |even_content_iv| iv used along with |even_key| for encrypting content + // - |entitlement_key_id| key id for |entitlement_key| + // - |entitlement_key| entitlement key used to encrypt even key + // - |ecm| for returning the generated ECM, must not be nullptr + // + // Returns: + // - A status indicating whether there was any error during processing + // + // Note: + // + // - Currently, we only allow |even_content_iv| + // to be of size 8 bytes, so we assume the encryptor would append suffix + // {'\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00', '\x00'} + // to |even_content_iv| to obtain a 16 bytes IV + // before encrypting the content + util::Status GenerateSingleKeyEcm(const std::string& even_key, + const std::string& even_wrapping_iv, + const std::string& even_content_iv, + const std::string& entitlement_key_id, + const std::string& entitlement_key, std::string* ecm); + + private: + bool initialized_ = false; + EcmInitParameters ecm_init_params_; +}; + +} // namespace cas +} // namespace widevine + +#endif // MEDIA_CAS_PACKAGER_SDK_PUBLIC_WV_CAS_ECM_H_