Closed Razumain closed 5 months ago
for previous discussion on this see #238
for previous discussion on this see #238
It seems to me that these discussions both adress HSM usage, but adress very different issues.
NIST SP 800-56A establishes that the shared secret from Diffie-Hellman Z = xP where xP is the x-coordinate of P. This is not in harmony with how Diffie-Hellman shared secret is specified in Opaque and effectively blocks performing Diffie-Hellman operations in a HSM that operates according to SP 800-56A.
In addition to this. I see a lost opportunity to use a HSM Diffie-Hellman operation to evaluate the blinded password
This does work at least for P256 and it seems to work also for 25519, but I have to verify that better in tests.
It is all made available by discarding the Y component in 2 places of the spec:
That is if:
hashInput = I2OSP(len(input), 2) || input || I2OSP(len(unblindedElement), 2) || unblindedElement || "Finalize"
Instead would be:
hashInput = I2OSP(len(input), 2) || input || I2OSP(len(xP of unblindedElement), 2) || xP of unblindedElement || "Finalize"
I know this is a big ask, that quite possibly is too much of a change to accommodate. But If there would be any clever way to at least allow this us of a HSM without breaking the standard, that would be very valuable.
Adding an illustration from my implementation that shows that this works just fine:
Lets first derive the client secret without blinding, using both the oprf private key AND the HSM protected server key ks
Password inputElement point (Size: 33) 03 D1 02 3A DC 03 FC AD AF D2 29 9C 2D 59 17 01 AD C7 5B 0E 2D 0D 84 ED 8D D0 2D 04 15 A0 52 5B 7A InputElement oprfKey (Size: 33) 03 80 22 CD 98 28 8A C2 7E A1 5A 08 CC A9 A0 D3 43 C9 94 8A 1F E2 8D 05 A8 E8 8C 1F F3 B2 82 15 ED Client secret = DiffieHellman(sk, (InputElement oprfKey) (Size: 32) 11 B0 5C 21 3B 73 CA E5 DD A0 8A B0 5B 31 DD CC D7 16 DE 76 A2 4A 74 16 A6 C1 AC 31 FA 2D 7C EB
The real EC point used to derive the DH shared secret (Size: 33) 02 11 B0 5C 21 3B 73 CA E5 DD A0 8A B0 5B 31 DD CC D7 16 DE 76 A2 4A 74 16 A6 C1 AC 31 FA 2D 7C EB
Note the dropped Y coordinate compressed value = 02
Now do with with blinding
Blinded input element (Size: 33) 02 3C E0 68 E9 BB DA B7 7C 73 7D 26 1F DD AB D9 78 7A 30 D1 C7 01 1D 79 4E 52 09 6F 48 43 41 EF 85 OPRF evaluate = blinded element oprfKey (Size: 33) 02 3B 75 57 05 9D A6 E5 BF 63 3A 60 05 64 DC 7A 24 4D C5 08 02 B9 BD DA 54 5C 54 DC C6 DB 23 8D F1 HSM Server evaluate = DiffieHellman(ks, (blinded element oprfKey) (Size: 32) 41 6C 6B 36 F3 EB 06 59 CB D8 6D 50 5F 98 EA 22 E5 25 D7 DB 83 D4 C5 39 40 A5 A0 42 D6 19 DA EC ECPoint(HSM Server evaluate) = 0x02 | HSM Server evaluate (Size: 33) 02 41 6C 6B 36 F3 EB 06 59 CB D8 6D 50 5F 98 EA 22 E5 25 D7 DB 83 D4 C5 39 40 A5 A0 42 D6 19 DA EC Client unblind = ECPoint(HSM Server evaluate) * 1/b (Size: 33) 03 11 B0 5C 21 3B 73 CA E5 DD A0 8A B0 5B 31 DD CC D7 16 DE 76 A2 4A 74 16 A6 C1 AC 31 FA 2D 7C EB
Note that we actually guessed wrong here on the HSM evaluate output. We added 02 but this was clearly wrong as we distorted the Y coordinate result to be 03, compared with 02 above
Derived shared secret (Size: 32) 11 B0 5C 21 3B 73 CA E5 DD A0 8A B0 5B 31 DD CC D7 16 DE 76 A2 4A 74 16 A6 C1 AC 31 FA 2D 7C EB
Bu as we only use the X coordinate, the client secret matches anyway.
I would like to revert my proposal here.
Mathematically and conceptually it works wonders, but given that this is build into OPRF, I think the right way to go, if you use HSM is to recover the missing Y.
Illary provided a great solution for how to do that with the cost of en extra DH operation with the HSM:
- Have HSM output x(aB) and x(a(B+G)).
- Guess Z=aB from first HSM output.
- Calculate x coordinate of Z+A, where A is your public key.
- Check if that is consistent with the second HSM output.
So we should not do this for OPRF. If you want to do this in OPRF you simply have to do this trick to recover Y.
For the use of DH in 3DH AKE it might still be worth considering only using the X coordinate to be compatible with off the shelf DiffieHellman operations based on PrivateKey objects (rather than raw scalar multiplication).
Finally, a note about this would be great in the OPAQUE draft to point out that the solution above is possible if you want to extend the security of the OPRF with an HSM protected scalar.
Hi @Razumain, after reading through the context here, I'm glad to hear that there is a way to make this work, but am currently not seeing a good way to reference this in the draft. Am I also understanding correctly that this is specific to the curve point representation and would not apply to ristretto255 points (or would it)?
If you have any recommended language that you would like to add to the draft, it would be great if you could take a stab at it :)
Closing this as it seems to have been resolved.
Diffie-Hellman operations using HSM protected keys can potentially be used both in the OPRF function as well as in the 3DH Key-Exchange Functions.
In OPRF a DiffieHellman operation can be used on top of the current evaluated element
The function
BlindEvaluate(oprf_key, blinded_element)
can be voluntarily extended by the server to:DiffieHellman( ks, BlindEvaluate(oprf_key, blinded_element))
This simply adds another scalar multiplication to the evaluated element, which can be unblinded by the client blind inverse.
The only thing that stands in the way of this operation, is the inclusion of the Y coordinate in the result when the corresponding DiffieHellman only produce the X coordinate as result.
The same is true for the 3DH key Exchange Functions which could be fully compatible with HSM protected keys if the shared secret was the X coordinate only instead of a full point serialization.