M17-Project/M17_spec

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.
obraz

gdt commented

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:

  1. Use bit 11 of the TYPE field to indicate signed stream (1-signed, 0-unsigned).
  2. The most significant bit of the frame counter of the last speech/data frame must not be set if the stream is signed.*
  3. 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).*
  4. 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.
  5. 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.