ECDSA signed streams - a possible authentication method
NebulaOnion opened this issue · 10 comments
HMAC is a good idea to preserve message integrity
128-bit payload of each frame can be used to prepare a transmission digest and be RSA-signed along with a transmission start/stop timestamp (plus padding). That RSA-based signature could be appended to the voice datastream between the last voice frame and the EoT marker.
The transmission digest could be constructed as follows (assuming RSA-1024 is used):
- initialize 7*128=896 bit vector with zeros at transmission start
- after each frame, XOR the content of the vector at position (n mod 7)*16 (16 bytes long) with frame contents (n - frame number)
- at transmission end, append the least significant byte of the frame counter and 32-bit timestamp as described in the spec (META field)
- the remaining 11 bytes are for RSA padding
- sign with RSA and transmit as 8 additional frames after speech payload
I just tested RSA-512 signing on a Module17 with the code below, using kokke/tiny-bignum-c with vanilla bignum_mult()
:
bignum_from_string(&msg, "0001ffffffffffffffffffffffffffffffffffffffffffffffffffff003021300906052b0e03021a050004148c723a0fa70b111017b4a6f06afe1c0dbcec14e3", 128);
bignum_from_string(&e, "61a4eb153f3f2a9be18303a7a8f964366074fe9b15756e97fad48c19a8374b870589dde72e4377f3837ab59fa76b55563642f2df635da71a3aa50ab835201b61", 128);
bignum_from_string(&n, "cbfb45e6b09f1af40df60ddc865b6f98a1fd724678b583bfb5ae8539627bffdcd930d7c3f996f75e15172a017f143101ecd28fc629b800e24f0a83665d77c0a3", 128);
while(1){
IO_A_GPIO_Port->BSRR = (uint32_t)IO_A_Pin;
bignum_pow_mod(&msg, &e, &n, &res);
IO_A_GPIO_Port->BSRR = (uint32_t)IO_A_Pin<<16;
HAL_Delay(100);
}
Execution time is about 14 seconds, which is not acceptable.
EC is probably faster, but still not fast enough. For 2-party communication, one can agree on a secret key and use that for HMAC, much like IPsec/IKE. For broadcast authentication,it's much harder.
There is a scheme in use by Galileo for broadcast authentication. I have no idea if it would scale to M17-class hardware, but I think it's worth understanding as prior art: https://gssc.esa.int/navipedia/index.php/Galileo_Open_Service_Navigation_Message_Authentication
I'd like someone to check if this class of microcontrollers can go down to a few hundred milliseconds, at most. The bignum implementation I used was nowhere close to optimal. Maybe utilizing Chinese remainder theorem would help.
libecc might be a good solution. It could sign a 16-byte stream digest in an acceptable time.
Update: I have tested CMOX on a Module17 (STM32F405 running at 168 MHz) and it is able to sign a 16-byte digest with secp256r1 in under 15 ms (around 8ms for brainpool p160r1). The digest is chain-XORed payload starting at frame 0, 16-byte long.
micro-ecc might be a good alternative.
To add signatures, the spec document needs to implement the following:
- Use bit 11 of the
TYPE
field to indicate signed stream (1-signed, 0-unsigned). - The most significant bit of the frame counter of the last speech/data frame must not be set if the stream is signed.*
- If the stream is signed, the last 4 frames should have frame numbers equal to 0x7FFC, 0x7FFD, 0x7FFE, 0xFFFF, with the last one having MSB set to 1 (stream end).*
- The contents of the last 4 frames is the signature. It is calculated with the stream digest and user's private key over
secp256r1
curve - 512-bit long vector. - EoT marker frame finalizes the transmission.
The stream digest is a 16-byte vector, calculated by chain-XORing payload starting at frame 0, over the whole transmission.
*) It is debatable if the MSB of the TYPE
field marks the transmission end or stream end (payload end). This needs some discussion.
Tested signing speed with micro-ecc: 42.4ms at -O2, 41.6ms at -O3
CMOX: <15ms
Both with the Module17.
I'm closing this issue. I will open another one, covering both auth and crypto.