// Copyright 2020 Google LLC. All Rights Reserved. #ifndef WHITEBOX_API_LICENSE_WHITEBOX_H_ #define WHITEBOX_API_LICENSE_WHITEBOX_H_ #include #include #include "api/result.h" #ifdef __cplusplus extern "C" { #endif // The opaque type representing a single white-box instance. typedef struct WB_License_Whitebox WB_License_Whitebox; typedef enum { WB_CIPHER_MODE_CTR, WB_CIPHER_MODE_CBC, } WB_CipherMode; // Creates a new white-box instance using |whitebox_init_data|. A pointer to the // white-box instance will be returned via |whitebox|. // // Args: // whitebox_init_data (in) : The implementation-specific initialization data // needed to initialize a new white-box instance. // // whitebox_init_data_size (in) : The number of bytes in |whitebox_init_data|. // // whitebox (out) : The output parameter used to return the new white-box // instance. // // Returns: // WB_RESULT_OK if the white-box instance was successfully created. // // WB_RESULT_INVALID_PARAMETER if |whitebox_init_data| was null or invalid. // // WB_RESULT_OUT_OF_MEMORY if the necessary memory could not be allocated. WB_Result WB_License_Create(const uint8_t* whitebox_init_data, size_t whitebox_init_data_size, WB_License_Whitebox** whitebox); // Releases all resources used by the white-box instance pointed to by // |whitebox|. // // Args: // whitebox (in) : A pointer to a white-box instance. Passing in null will // result in a no-op. void WB_License_Delete(WB_License_Whitebox* whitebox); // Signs a license request using the CDM's private signing key. // // Args: // whitebox (in) : A pointer to the current white-box instance. // // license_request (in) : The license request in serialized form. // // license_request_size (in) : The number of bytes in the license_request. // // signature (out) : The generated signature for |license_request|. // // signature_size (in/out) : As input, this contains the max number of bytes // that can be written to |signature|. As output, |signature_size| is set to // the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL. // // Returns: // WB_RESULT_OK if the signature was successfully generated. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |license_request| was // null, if |license_request_size| was zero, if |signature| was null, or if // |signature_size| was null. // // WB_RESULT_BUFFER_TOO_SMALL if |signature_size| (as input) was less than the // required size. WB_Result WB_License_SignLicenseRequest(const WB_License_Whitebox* whitebox, const uint8_t* license_request, size_t license_request_size, uint8_t* signature, size_t* signature_size); // Verifies a license response using HMAC and the server signing key. // // Extracts and loads content and signing keys for use. Any content keys that // exceed the security levels permitted by the instance, will be thrown away, // but the key ids are retained (see WB_RESULT_INSUFFICIENT_SECURITY_LEVEL). All // non-content keys and non-signing keys will be thrown away. // // This function can only be called once per white-box instance. To parse a new // license response, a new white-box instance must be used. // // Args: // whitebox (in/out) : The white-box instance that will load the keys. // // message (in) : The message field of the license response. // // message_size (in) : The number of bytes in |message|. // // signature (in) : The signature field of the license response. // // signature_size (in) : The number of bytes in |signature|. // // session_key (in) : The session key field of the license response. // // session_key_size (in) : The number of bytes in |session_key|. // // license_request (in) : The license request that was sent in order to get the // license response. // // license_request_size (in) : The number of bytes in |license_request|. // // Returns: // WB_RESULT_OK if the response was verified and the keys were loaded into // |whitebox|. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |message| was null, // if |message_size| was zero, if |message| did not conform to the expected // format, if |signature| was null, if |signature_size| was incorrect, if // |session_key| was null, if |session_key_size| was incorrect, if // |session_key| could not be unwrapped correctly, if |license_request| was // null, or if |license_request_size| was zero. // // WB_RESULT_INVALID_SIGNATURE if |message|'s signature does not match // |signature|. // // WB_RESULT_INVALID_STATE if a license has already been loaded. WB_Result WB_License_ProcessLicenseResponse(WB_License_Whitebox* whitebox, const uint8_t* message, size_t message_size, const uint8_t* signature, size_t signature_size, const uint8_t* session_key, size_t session_key_size, const uint8_t* license_request, size_t license_request_size); // Signs |message| and return the signature via |signature| using HMAC and the // client renewal signing key // // Args: // whitebox (in) : The white-box instance containing the signing key. // // message (in) : The message that should be signed. // // message_size (in) : The number of bytes in |message|. // // signature (out) : The output parameter used to return the signature. // // signature_size (in/out) : As input, this contains the max number of bytes // that can be written to |signature|. As output, |signature_size| is set to // the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL. // // Returns: // WB_RESULT_OK if |message| was successfully signed. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |message| was null, // if |message_size| was zero, if |signature| was null, or if |signature_size| // was null. // // WB_RESULT_BUFFER_TOO_SMALL if |signature_size| (as input) was less than the // required size. // // WB_RESULT_INVALID_STATE if |whitebox| had no signing keys. WB_Result WB_License_SignRenewalRequest(const WB_License_Whitebox* whitebox, const uint8_t* message, size_t message_size, uint8_t* signature, size_t* signature_size); // Verifies the renewal response using HMAC and the server signing key. // // Args: // whitebox (in) : The white-box containing the server signing key. // // message (in) : The message that needs to be verified. // // message_size (in) : The number of bytes in |message|. // // signature (in) : The expected signature for |message|. // // signature_size (in) : The number of bytes in |signature|. // // Returns: // WB_RESULT_OK if |message|'s signature matches |signature|. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |message| was null, // if |message_size| was zero, if |signature| was null, of if |signature_size| // was incorrect. // // WB_RESULT_INVALID_SIGNATURE if |message|'s signature did not match // |signature|. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. WB_Result WB_License_VerifyRenewalResponse(const WB_License_Whitebox* whitebox, const uint8_t* message, size_t message_size, const uint8_t* signature, size_t signature_size); // Gets the secret string needed by WB_License_Unmask() in order to unmask the // masked decrypted content returned by WB_License_MaskedDecrypt(). // // Args: // whitebox (in) : The white-box instance that will be used for the calls to // WB_License_MaskedDecrypt(). // // mode (in) : The AES decryption mode that will be used for the calls to // WB_License_MaskedDecrypt(). // // key_id (in) : The key id that will be used for the call to // WB_License_MaskedDecrypt(). The key id must match a key loaded in // |whitebox|. // // key_id_size (in) : The number of bytes in |key_id|. // // secret_string (out) : The output parameter used to return the secret string // that can be passed to WB_License_Unmask(). // // secret_string_size (in/out) : As input, this contains the max number of // bytes that can be written to |secret_string|. As output, // |secret_string_size| is set to the required size on WB_RESULT_OK and // WB_RESULT_BUFFER_TOO_SMALL. // // Returns: // WB_RESULT_OK if |key_id| matches a key from the license response and the // secret string was written to |secret_string|. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid, // if |key_id| was null, if |key_id_size| was zero, if |secret_string| was // null, or if |secret_string_size| was null. // // WB_RESULT_INSUFFICIENT_SECURITY_LEVEL if |key_id| referred to a key from // the license, but the |whitebox| was not allowed to use it. // // WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a content key from the // loaded license. // // WB_RESULT_BUFFER_TOO_SMALL if |secret_string_size| (as input) was less than // the required size. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. WB_Result WB_License_GetSecretString(const WB_License_Whitebox* whitebox, WB_CipherMode mode, const uint8_t* key_id, size_t key_id_size, uint8_t* secret_string, size_t* secret_string_size); // Decrypts |input_data| and writes the plaintext to |output_data|. // // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. // // mode (in) : The decryption algorithm that should be used to decrypt // |input_data|. // // key_id (in) : The identifier for which key in |whitebox| to use to decrypt // |input_data|. // // key_id_size (in) : The number of bytes in |key_id|. // // input_data (in) : The ciphertext. // // input_data_size (in) : The number of bytes in |input_data|. If |mode| is set // to CBC, then |input_data_size| must be a multiple of 16. Regardless of mode, // this |input_data_size| must be greater than zero. // // iv (in) : The iv. // // iv_size (in) : The number of bytes in |iv|. This must be 16. // // output_data (out) : The output parameter for the plaintext. // // output_data_size (in/out) : As input, this contains the max number of bytes // that can be written to |output_data|. As output, |output_data_size| is set // to the required size on WB_RESULT_OK and WB_RESULT_BUFFER_TOO_SMALL. // // Returns: // WB_RESULT_OK if |input_data| was successfully decrypted. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid, // if |key_id| was null, if |key_id_size| was zero, if |input_data| was null, // if |input_data_size| was invalid, if |iv| was null, if |iv_size| was // invalid, if |output_data| was null, or if |output_data_size| was null. // // WB_RESULT_INSUFFICIENT_SECURITY_LEVEL if |key_id| referred to a key from // the license, but the |whitebox| was not allowed to use it. // // WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a content key from the // loaded license. // // WB_RESULT_BUFFER_TOO_SMALL if |output_data_size| (as input) was less than // the required size. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. WB_Result WB_License_Decrypt(const WB_License_Whitebox* whitebox, WB_CipherMode mode, const uint8_t* key_id, size_t key_id_size, const uint8_t* input_data, size_t input_data_size, const uint8_t* iv, size_t iv_size, uint8_t* output_data, size_t* output_data_size); // Decrypts |input_data| and write the obfuscated plaintext to // |masked_output_data|. The obfuscated plaintext can be deobfuscated using // WB_License_GetSecretString() and WB_License_Unmask(). // // Args: // whitebox (in) : The white-box containing the keys needed to decrypt // |input_data|. // // mode (in) : The decryption algorithm that should be used to decrypt // |input_data|. // // key_id (in) : The identifier for which key in |whitebox| to use to decrypt // |input_data|. // // key_id_size (in) : The number of bytes in |key_id|. // // input_data (in) : The ciphertext. // // input_data_size (in) : The number of bytes in |input_data|. If |mode| is set // to CBC, then |input_data_size| must be a multiple of 16. Regardless of mode, // this |input_data_size| must be greater than zero. // // iv (in) : The iv. // // iv_size (in) : The number of bytes in |iv|. This must be 16. // // masked_output_data (out) : The output parameter for the obfuscated // plaintext. // // masked_output_data_size (in/out) : As input, this contains the max number of // bytes that can be written to |masked_output_data|. As output, // |masked_output_data_size| is set to the required size on WB_RESULT_OK and // WB_RESULT_BUFFER_TOO_SMALL. // // Returns: // WB_RESULT_OK if |input_data| was successfully decrypted. // // WB_RESULT_INVALID_PARAMETER if |whitebox| was null, if |mode| was invalid, // if |key_id| was null, if |key_id_size| was zero, if |input_data| was null, // if |input_data_size| was invalid, if |iv| was null, if |iv_size| was // invalid, if |masked_output_data| was null, or if |masked_output_data_size| // was null. // // WB_RESULT_INSUFFICIENT_SECURITY_LEVEL if |key_id| referred to a key from // the license, but the |whitebox| was not allowed to use it. // // WB_RESULT_KEY_UNAVAILABLE if |key_id| did not match a content key from the // loaded license. // // WB_RESULT_BUFFER_TOO_SMALL if |masked_output_data_size| (as input) was less // than the required size. // // WB_RESULT_INVALID_STATE if |whitebox| had not loaded a license. WB_Result WB_License_MaskedDecrypt(const WB_License_Whitebox* whitebox, WB_CipherMode mode, const uint8_t* key_id, size_t key_id_size, const uint8_t* input_data, size_t input_data_size, const uint8_t* iv, size_t iv_size, uint8_t* masked_output_data, size_t* masked_output_data_size); // Unmasks the data in |buffer| using |secret_string|. |buffer| is operated on // in-place. // // Args: // secret_string (in) : The "key" used to unmask the data in |buffer|. // // secret_string_size (in) : The number of bytes in |secret_string|. // // buffer (in/out) : As input, this is the masked data. As output, this is the // unmasked data. The number of bytes in the masked data will be equal to the // number of bytes in the unmasked data. // // buffer_size (in) : The number of bytes in |buffer|. void WB_License_Unmask(const uint8_t* secret_string, size_t secret_string_size, uint8_t* buffer, size_t buffer_size); #ifdef __cplusplus } #endif #endif // WHITEBOX_API_LICENSE_WHITEBOX_H_