Most cryptosystems today offer flexible-enough primitives that you can come up with a lot of different possible ways to do things like this. Whether they are useful is a different story.
IMO you should probably do something more normal, and just store the certificate chain with the device programming.
*After about 10 minutes of analysis, so YMMV taking my word for it.
Do you still see an opening for a MitM if you assume TOFU works? There is authentication, just not on first connect. I'd be interested in your view on what I missed.
The exfiltration is of course a concern. Part of the prototype I'm doing, is looking into how much we can protect against this. (See also feedback I left to tillitis regarding access to the assigned secret, <https://github.com/tillitis/tillitis-key1/issues/186>.)
Concerning rotations, absolutely correct. Consider though that any change of program-binary or user-supplied secret or device brings its own secret. Note that because of the lack of persistence on the device, a client would store a data, even if only for use within the device.
Note that the secret is determined at every execution as the program-binary loads. The device, TKey, itself is a general RiscV processing unit with device-firmware that initializes a little bit of device and memory, takes the program sent to the device, then starts executing at the program-binary's entry-point.
(1) the tillitis CA certifies your TKey device platform. You can now trust that it's running a specific firmware version with some platform pubkey.
(2) Your custom software is running and derives a keypair from it's derived secret + program binary hash.
(3) Somehow your custom software's pubkey gets locally certified by the platform's pubkey from (1). (not sure what this looks like w/ the TKey)
You now have a chain of trust from (1) the tillitis CA -> (3) the TKey device platform pubkey @ some specific firmware version -> (2) your custom software pubkey @ some specific version.
Now that we have a trusted pubkey for our service, I would open a secure channel to it via Noise IK or something (https://noiseexplorer.com/patterns/IK/). The TKey platform definitely looks a bit anemic so getting this working might be a challenge...
Then you not only have access to the device secret, you can even choose it yourself.
Shout out to https://www.trustedfirmware.org/projects/mbed-tls/
If the device lacks access to storage it cannot store any state. How do you ensure the RNG isn't initialized to the same value every time? I'm not sure how that impacts some of the assumptions about security here.
Or used.
sk_identity is static over the lifetime of the device, so doesn't need new entropy.
sk_device is generated after pk_user is recieved, so can use HASH(sk_identity,pk_user) as entropy. This results in the same pk_device for every session with a given pk_user, which theoretically enables traffic analysis, but the security model implies traffic analysis is out-of-scope.
signature and enc_sig might need entropy as well, but can still use HASH(sk_identity,pk_user).
This is my first time seeing Verifpal, but it looks like a huge foot gun in the wrong hands. Here the author was lead to believe there was some sort of formal validation of his roll-your-own crypto, while glossing over obvious potential implementation flaws.
I haven't tested yet how fast the TRNG refreshes. Right now, I take 4 bytes (1 collection) of TRNG entropy to be hashed with a static byte-buffer.
The RNG would be used for (sk_device,pk_device). So 'identity' keypair for authn, 'device' (ephemeral) keypair for key-exchange.
I used this (and the NNpsk0 handshake [2]) as the basis for an E2EE chat app.
You may eventually need to rotate its identity key, and if you want to do that, you need a certificate system.
A certificate is also a secret + certified public key, right? So, if you cannot store the certification on the TKey (no persistence) than you're left with the same construction. Right now, I'm skipping the complexity of certs (PKCS11, IIRC) etc. The identity being persistent is in order to authenticate the device.
I think you're over-describing your use case, to the point that it's unclear what you're really saying. I read your "Introduction" section several times, and I don't understand if you're just saying "the use case is an authenticated key exchange" or something different. That makes it hard to judge the protocol.
> Device gets authenticated
> The device, however, does not have storage capability
These two requirements are contradictory. How do you "authenticate" a server that has a different identity each time you interact with it?
> [The protocol] is built on top of a Diffie-Hellman Key Exchange
Why not just use Diffie-Hellman? What else is this offering?
Okay. I indeed failed to abstract away from the device properly. I'm guessing that the confusion comes from the fact that I had a specific device in mind, but failed to describe it.
> These two requirements are contradictory. How do you "authenticate" a server that has a different identity each time you interact with it?
Not necessarily. So how TKey works: the hardware contains a preprogrammed device secret. The hardware does not have storage. Upon each power-up it expects a program to be loaded. Upon loading that program, a secret is computed for that specific program: `blake2s(device-secret, program-binary, user-secret)` (user-secret is optional). The secret is generated deterministically, but unpredictable because we don't know the device-secret.
> Why not just use Diffie-Hellman? What else is this offering?
Given that there exists an "identity", which is the same every time the program loads, this identity can be used for authentication. The identity is different for every program, but after acquiring it once, a client application can perform a key-exchange that finishes with the signature proving the authenticity.
If 'device' or 'program-binary' or 'user-secret' changes, the secret changes. So if the secret is the same, you have quite strong guarantees that nobody screwed around with your device or program.
Ok, I think this is still a fairly standard situation. I understand it that the above quoted text represents the device's long term private key? If so...
You can do this:
- device derives a long-term public device key from the long-term private key
- client generates a fresh public/private session keypair
- client and server perform a Diffie-Hellman exchange, resulting in shared_session_key
- client also verifies device's long-term public key is correct (a simple equality check)
At this point the client and server now have a shared_session_key, and you're in standard territory.
Next problems are replay attack prevention and forward secrecy. The two-birds-with-one-stone for that is for each side to:
- generate fresh a ephemeral keypair
- encrypt using the shared_session_key (with a random nonce)
- perform another Diffie-Hellman exchange
This results in a shared_ephemeral_key. This key can now be used to communicate securely, but you'll need to use incrementing integers as nonces for each message in the ephemeral session to prevent replay attacks. None of this needs storage.
https://noiseprotocol.org/noise.html#interactive-handshake-p...
I encourage you to use their hashing details. They're battle-tested.
Wireguard uses Noise IK, which is NK plus a static public key for the initiator which is encrypted to the agreed-upon-session-key without adding additional round trips. Your protocol and Noise NK omit the parts related to the initiator's static public key, because it has none.
Exchanges above the dotted line are one-time key distributions; see this link: https://archive.li/bU5Me#selection-3667.0-3671.36
Given that this is a person interested in cryptography trying something for an experiment, I don't think it deserves the "don't roll your own" hammer.