Code change:
I think that the hash/auth tag list should be better moved at the end of the frame after the auth tag to make it easier to apply the encryption and generating the auth tag without having to reconstruct the frame to insert the signature in the middle of it. So, my new proposal would be first to generate the frame header with the s bit = 1, append the payload, encrypt the frame and add the auth tag as normal: Then append the tags before that frame at the end and the number of auth tags without the current frame one Then calculate the signature of the auth tags in reverse order: And then append the Signature at the end of the frame: When the receiver gets the frame, it will also be able to reuse the buffer to calculate the Signature without having to move momory around. In case it is not secure to use the auth tags, it would be still be similar: The receiver would have to generate the Hash of the frame up to the Auth tag, and then calculate the signature with the rest of the hashes on the list.
Adding Signature at the end will mean adding a new offset field to point to where the Signature block start as it will be a variable length block (depends how many hashes it has), where if it was put at the beginning, we won't need to add an offset field.I think doing signature over the auth tag is fineYou are right about the startFrameIndex, it won't be enough. What about having startFrameIndex 4 bytes or whatever, then having one byte frameOffset for every other hash to get the frameindex by using this offset from the start index, assuming 255 is enough range. I just don't want to add full length frameId for every hash
didn't you said that: Why is it fixed if it is at the beginning, but variable if it is in the end? why do we need the at all? The receiver would just need to have an ordered map of the pending to be verified authentication tags and remove them when they signature for each is received. The receiver should have also a verification timeout and if a signature is not received for that tag in time, it would be considered as failed.
Ok, I see, ECDSA signatures are ASN1 encoded objects, so the length can be derived by parsing it from the start bite. Is that correct?
I have made a new tentative approach with my comments above. What do you think?
Sorry I should have been more clear The signature itself is fixed length (ex 64 bytes for ed25519) but The entire signature block will be variable depends on the number of signature, unless you want to make this number fixed (ex always 50 hashes)We need frameIndex so the recipient know which hashes to use to verify the signature, we can't just relay on an ordered list of all previous hashes because the signature block could have hashes of missing frames, or even the signature packet could be lost itself
What is a signature block? What is the difference between the signature and the signature block? That should be covered by my proposal.
signature = sign(data) Signature block is what I referred to on my drawing as signature header+ signature + hash list
If I understood your proposal correctly, you are sending the whole list of hashes so the receiver can recreate the if any of them is missing. So you don't really don't need the index of each frame, as you there should be (almost) a 1-to-1 mapping between the hashes/auth tag and the frame index (how probable is to have a hash or auth tag collision?). So, given the hash/auth tag list, the receiver could derive the frame index of it (by keeping an internal map)
I think that's good for now. My initial thought was to have the sender chose the packet to sign, they can be different number each time, also they might chose not ti sign every packet, for example random X packets every Y seconds. Anyway, we can always improve later, your proposal is good to start with
This should be also possible with current approach, right? Have you seen any reason that it couldn't be done?
In the draft it says that: >when the signature is sent, it will also send all the hashes it used to calculate the signature How is the bitstream format of the signature+hashes, also how is the signature added to the frame (after the auth tag?) and how is the presence of the signature in a frame signaled?
How about something like this for the signature format? The signature is appended after the block if the bit of the SFrame header is 1. The first byte (SLEN) is the length of the signature data . After the signature there will be 1 or more blocks of HMACs. A they can be off different size, each HMAC block will have 1 byte header with HNUM (4 bits) indicating the number of HMACs present and HLEN(4 bits) to indicate the size in bytes of each HMAC. To indicate the end of the HMACS blocks an HMAC header block with HNUM=0 and HLEN=0 will be inserted.
One question, what are the sizes of the HMACs? I have considered the ones for AES which are 4 and 8, but in GCM are bigger, right? Are they required to be even or a power of 2? we could do either length=2^(HLEN+1) or LEN=2(HLEN+2) in that case.
I don't think they have to be 2*n. SHA-256 is, of course, but SHA-384 isn't
Currently it says that: However, if using SVC, the hash will be calculated over all the frames of the different spatial layers within the same superframe/picture. However the SFU will be able to drop frames within the same stream (either spatial or temporal) to match target bitrate. In that case, the receiver will never get a full frame and be able to check the signature. Which will render it a kind of useless feature. An easy way of solving the issue would be to perform signature only on the base layer or take into consideration the dependency graph and send multiple signatures in parallel (each for a branch of the dependency graph).
This is a good point and suggests 'frame' really refers to each independently decodable unit.
I think I mixed two things on this issue and my original comment is not totally accurate. The signature will contain the HMAC of all the frames it contains, so if any of them is dropped, the receiver can still compute the signature of the received ones. However, if the signature is not sent on the base layer, then it can be dropped by the SFU. I think it still makes sense to send different signatures over different layers to avoid having to send data on the wire that will be dropped by the SFU.

Related discussion:
text: extra cost. Adding a digital signature to each encrypted frame will be an <del> overkill, instead we propose adding signature over N frames. Because some frames could be lost and never delivered, when the signature is sent, it will also send all the hashes it used to calculate the signature, and the recipient client will only use these hashes if they didn't receive the matching frame.  For example Client A sends a signature every 5 frames, so it sends the signature and Hash(Frame1), ...,Hash(Frame5), client B received only frames 1,2,4 and 5.  When B receives the signature and the hashes, it will compute the hashes of frames 1,2,4 and 5 locally and use the received Hash(Frame3) to verify the signature.  It is up to the application to decide what to do when signature verification fails. The signature keys are exchanged out of band along the secret keys. </del> <ins> overkill, instead we propose adding signature over multiple frames. The signature is calculated by contatenating the authentication tags of the frames that the sender wants to authenticate (in reverse sent order) and signing it with the signature key.  Signature keys are exchanged out of band along the secret keys. The authentication tags for the previous frames covered by the signature and the signature itself will be appended at end of the frame, after the current frame authentication tag, in the same order that the signature was calculated, and the SFrame header metadata signature bit (S) will be set to 1. Note that the authentication tag for the current frame will only authenticate the SFrame header and the encrypted payload, ant not the signature nor the previous frames's authentication tags (N-1 to N-M) used to calculate the signature. The last byte (NUM) after the authentication tag list and before the signature indicates the number of the authentication tags from previous frames present in the current frame.  All the authentications tags MUST have the same size, which MUST be equal to the authentication tag size of the current frame.  The signature is fixed size depending on the signature algorithm used (for example, 64 bytes for Ed25519). The receiver has to keep track of all the frames received but yet not verified, by storing the authentication tags of each received frame. When a signature is received, the reciever will verify it with the signature key associated to the key id of the frame the singature was sent in.  If the verification is sucessful, the received will mark the frames as authenticated and remove them from the list of the not verified frames.  It is up to the application to decide what to do when signature verification fails. When using SVC, the hash will be calculated over all the frames of the different spatial layers within the same superframe/picture. However the SFU will be able to drop frames within the same stream (either spatial or temporal) to match target bitrate. If the signature is sent on a frame which layer that is dropped by the SFU, the receiver will not receive it and will not be able to perform the signature of the other received layers. An easy way of solving the issue would be to perform signature only on the base layer or take into consideration the frame dependency graph and send multiple signatures in parallel (each for a branch of the dependency graph). In case of simulcast or K-SVC, each spatial layer sould be authenticated with different signatures to prevent the SFU to discard frames with the signature info. In any case, it is possible that the frame with the signature is lost or the SFU drops it, so the receiver MUST be prepared to not receive a signature for a frame and remove it from the pending to be verified list after a timeout. </ins> 4.