Skip to content

Commit

Permalink
Implements signing for AV1 (#278)
Browse files Browse the repository at this point in the history
All signing tests have been enabled.
In addition, has_reference_hash is correctly reset, emulation
prevention API returns NOT SUPPORTED for AV1 and some comment
cleanup in signing tests.

Co-authored-by: bjornvolcker <bjornvolcker@users.noreply.github.com>
  • Loading branch information
bjornvolcker and bjornvolcker authored Dec 16, 2024
1 parent 6f89efd commit 34961e8
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 94 deletions.
3 changes: 3 additions & 0 deletions lib/src/includes/signed_video_sign.h
Original file line number Diff line number Diff line change
Expand Up @@ -502,10 +502,13 @@ signed_video_set_recurrence_interval_frames(signed_video_t *self, unsigned recur
* If this API is not used, SEI payload is written with EPBs, hence equivalent with setting
* |sei_epb| to True.
*
* NOTE: AV1 does not have emulation prevention. Therefore, this API is not supported for AV1.
*
* @param self Session struct pointer
* @param sei_epb SEI payload written with EPB (default True)
*
* @returns SV_OK SEI w/o EPB was successfully set,
* SV_NOT_SUPPORTED if codec is AV1,
* SV_INVALID_PARAMETER Invalid parameter.
*/
SignedVideoReturnCode
Expand Down
2 changes: 1 addition & 1 deletion lib/src/legacy/legacy_h26x_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ legacy_gop_info_reset(legacy_gop_info_t *gop_info)
gop_info->verified_signature_hash = -1;
// If a reset is forced, the stored hashes in |hash_list| have no meaning anymore.
gop_info->list_idx = 0;
gop_info->has_reference_hash = false;
gop_info->has_reference_hash = true;
gop_info->global_gop_counter_is_synced = false;
}

Expand Down
13 changes: 6 additions & 7 deletions lib/src/signed_video_h26x_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
#include "includes/signed_video_signing_plugin.h"
#include "signed_video_authenticity.h" // latest_validation_init()
#include "signed_video_defines.h" // svrc_t
#include "signed_video_h26x_internal.h" // h26x_nalu_list_item_t
#include "signed_video_h26x_internal.h" // h26x_nalu_list_item_t, METADATA_TYPE_USER_PRIVATE
#include "signed_video_h26x_nalu_list.h" // h26x_nalu_list_create()
#include "signed_video_internal.h" // gop_info_t, gop_state_t, MAX_HASH_SIZE, DEFAULT_HASH_SIZE
#include "signed_video_openssl_internal.h"
Expand All @@ -46,7 +46,6 @@
#define USER_DATA_UNREGISTERED 5
#define H264_NALU_HEADER_LEN 1 // length of forbidden_zero_bit, nal_ref_idc and nal_unit_type
#define H265_NALU_HEADER_LEN 2 // length of nal_unit_header as per ISO/ITU spec
#define METADATA_TYPE_USER_PRIVATE 25
#define AV1_OBU_HEADER_LEN 1
// The salt added to the recursive hash to get the final gop_hash
#define GOP_HASH_SALT 1
Expand Down Expand Up @@ -259,7 +258,7 @@ gop_info_reset(gop_info_t *gop_info)
gop_info->verified_signature_hash = -1;
// If a reset is forced, the stored hashes in |hash_list| have no meaning anymore.
gop_info->list_idx = 0;
gop_info->has_reference_hash = false;
gop_info->has_reference_hash = true;
gop_info->global_gop_counter_is_synced = false;
}

Expand Down Expand Up @@ -1149,11 +1148,11 @@ hash_and_add(signed_video_t *self, const h26x_nalu_t *nalu)
svrc_t status = SV_UNKNOWN_FAILURE;
SV_TRY()
if (nalu->is_first_nalu_part && !nalu->is_last_nalu_part) {
// If this is the first part of a non-complete NALU, initialize the |crypto_handle| to enable
// sequentially updating the hash with more parts.
// If this is the first part of a non-complete NALU/OBU, initialize the |crypto_handle| to
// enable sequentially updating the hash with more parts.
SV_THROW(openssl_init_hash(self->crypto_handle, false));
}
// Select hash function, hash the NALU and store as 'latest hash'
// Select hash function, hash the NALU/OBU and store as 'latest hash'
hash_wrapper_t hash_wrapper = get_hash_wrapper(self, nalu);
SV_THROW(hash_wrapper(self, nalu, nalu_hash, hash_size));
#ifdef SIGNED_VIDEO_DEBUG
Expand Down Expand Up @@ -1274,7 +1273,7 @@ signed_video_create(SignedVideoCodec codec)
self->authenticity_level = DEFAULT_AUTHENTICITY_LEVEL;
self->recurrence = RECURRENCE_ALWAYS;
self->add_public_key_to_sei = true;
self->sei_epb = true;
self->sei_epb = codec != SV_CODEC_AV1;
self->signing_started = false;
self->sign_data = sign_or_verify_data_create();
self->sign_data->hash_size = openssl_get_hash_size(self->crypto_handle);
Expand Down
2 changes: 2 additions & 0 deletions lib/src/signed_video_h26x_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
#include "signed_video_defines.h" // svrc_t
#include "signed_video_internal.h" // gop_info_t, gop_state_t, MAX_HASH_SIZE

#define METADATA_TYPE_USER_PRIVATE 25

typedef struct _h26x_nalu_list_item_t h26x_nalu_list_item_t;

typedef enum {
Expand Down
104 changes: 72 additions & 32 deletions lib/src/signed_video_h26x_sign.c
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
#include "includes/signed_video_signing_plugin.h"
#include "signed_video_authenticity.h" // allocate_memory_and_copy_string
#include "signed_video_defines.h" // svrc_t, sv_tlv_tag_t
#include "signed_video_h26x_internal.h" // parse_nalu_info()
#include "signed_video_h26x_internal.h" // parse_nalu_info(), METADATA_TYPE_USER_PRIVATE
#include "signed_video_internal.h" // gop_info_t
#include "signed_video_openssl_internal.h"
#include "signed_video_tlv.h" // tlv_list_encode_or_get_size()
Expand Down Expand Up @@ -248,9 +248,29 @@ generate_sei_nalu(signed_video_t *self, uint8_t **payload, uint8_t **payload_sig
sei_buffer_size += payload_size / 256 + 1; // Size field
sei_buffer_size += payload_size;
sei_buffer_size += 1; // Stop bit in a separate byte
if (self->codec != SV_CODEC_AV1) {
sei_buffer_size += self->codec == SV_CODEC_H264 ? 6 : 7; // NALU header
sei_buffer_size += payload_size / 256 + 1; // Size field
sei_buffer_size += payload_size;
sei_buffer_size += 1; // Stop bit in a separate byte
} else {
payload_size += 3; // 2 trailing-bit bytes, 1 metadata_type byte
int payload_size_bytes = 0;
size_t tmp_payload_size = payload_size;
while (tmp_payload_size > 0) {
payload_size_bytes++;
tmp_payload_size >>= 7;
}
sei_buffer_size += 1; // OBU header
sei_buffer_size += payload_size_bytes; // Size field
sei_buffer_size += payload_size;
}

// Secure enough memory for emulation prevention. Worst case will add 1 extra byte per 3 bytes.
sei_buffer_size = sei_buffer_size * 4 / 3;
if (self->codec != SV_CODEC_AV1) {
// Secure enough memory for emulation prevention. Worst case will add 1 extra byte per 3
// bytes.
sei_buffer_size = sei_buffer_size * 4 / 3;
}

// Allocate memory for payload + SEI header to return
*payload = (uint8_t *)malloc(sei_buffer_size);
Expand All @@ -263,30 +283,54 @@ generate_sei_nalu(signed_video_t *self, uint8_t **payload, uint8_t **payload_sig
// Reset last_two_bytes before writing bytes
self->last_two_bytes = LAST_TWO_BYTES_INIT_VALUE;
uint16_t *last_two_bytes = &self->last_two_bytes;
// Start code prefix
*payload_ptr++ = 0x00;
*payload_ptr++ = 0x00;
*payload_ptr++ = 0x00;
*payload_ptr++ = 0x01;

if (self->codec == SV_CODEC_H264) {
write_byte(last_two_bytes, &payload_ptr, 0x06, false); // SEI NAL type
} else if (self->codec == SV_CODEC_H265) {
write_byte(last_two_bytes, &payload_ptr, 0x4E, false); // SEI NAL type
// nuh_layer_id and nuh_temporal_id_plus1
write_byte(last_two_bytes, &payload_ptr, 0x01, false);
}
// last_payload_type_byte : user_data_unregistered
write_byte(last_two_bytes, &payload_ptr, 0x05, false);

// Payload size
size_t size_left = payload_size;
while (size_left >= 0xFF) {
write_byte(last_two_bytes, &payload_ptr, 0xFF, false);
size_left -= 0xFF;
if (self->codec != SV_CODEC_AV1) {
// Start code prefix
*payload_ptr++ = 0x00;
*payload_ptr++ = 0x00;
*payload_ptr++ = 0x00;
*payload_ptr++ = 0x01;

if (self->codec == SV_CODEC_H264) {
write_byte(last_two_bytes, &payload_ptr, 0x06, false); // SEI NAL type
} else if (self->codec == SV_CODEC_H265) {
write_byte(last_two_bytes, &payload_ptr, 0x4E, false); // SEI NAL type
// nuh_layer_id and nuh_temporal_id_plus1
write_byte(last_two_bytes, &payload_ptr, 0x01, false);
}
// last_payload_type_byte : user_data_unregistered
write_byte(last_two_bytes, &payload_ptr, 0x05, false);

// Payload size
size_t size_left = payload_size;
while (size_left >= 0xFF) {
write_byte(last_two_bytes, &payload_ptr, 0xFF, false);
size_left -= 0xFF;
}
// last_payload_size_byte - u(8)
write_byte(last_two_bytes, &payload_ptr, (uint8_t)size_left, false);
} else {
write_byte(last_two_bytes, &payload_ptr, 0x2A, false); // OBU header
// Write payload size
size_t size_left = payload_size;
while (size_left > 0) {
// get first 7 bits
int byte = (0x7F & size_left);
// Check if more bytes to come
size_left >>= 7;
if (size_left > 0) {
// More bytes to come. Set highest bit
byte |= 0x80;
} else {
// No more bytes to come. Clear highest bit
byte &= 0x7F;
}
write_byte(last_two_bytes, &payload_ptr, byte, false); // obu_size
}
// Write metadata_type
write_byte(last_two_bytes, &payload_ptr, METADATA_TYPE_USER_PRIVATE, false); // metadata_type
// Intermediate trailing byte
write_byte(last_two_bytes, &payload_ptr, 0x80, false); // trailing byte
}
// last_payload_size_byte - u(8)
write_byte(last_two_bytes, &payload_ptr, (uint8_t)size_left, false);

// User data unregistered UUID field
h26x_set_nal_uuid_type(self, &payload_ptr, UUID_TYPE_SIGNED_VIDEO);
Expand Down Expand Up @@ -402,7 +446,7 @@ get_sign_and_complete_sei_nalu(signed_video_t *self,
tlv_list_encode_or_get_size(self, gop_info_encoders, num_gop_encoders, payload_ptr);
payload_ptr += written_size;

// Stop bit
// Stop bit (Trailing bit identical for both H.26x and AV1)
write_byte(last_two_bytes, &payload_ptr, 0x80, false);

#ifdef SIGNED_VIDEO_DEBUG
Expand Down Expand Up @@ -502,11 +546,6 @@ signed_video_add_nalu_part_for_signing_with_timestamp(signed_video_t *self,
}
nalu.hashable_data_size = nalu_data_size;
}
if (self->codec == SV_CODEC_AV1) {
// Not yet implemented, but return SV_OK to run through tests.
free(nalu.nalu_data_wo_epb);
return prepare_for_nalus_to_prepend(self);
}

svrc_t status = SV_UNKNOWN_FAILURE;
SV_TRY()
Expand Down Expand Up @@ -884,6 +923,7 @@ SignedVideoReturnCode
signed_video_set_sei_epb(signed_video_t *self, bool sei_epb)
{
if (!self) return SV_INVALID_PARAMETER;
if (self->codec == SV_CODEC_AV1) return SV_NOT_SUPPORTED;
self->sei_epb = sei_epb;
return SV_OK;
}
Expand Down
Loading

0 comments on commit 34961e8

Please sign in to comment.