Conversation
| 2. The second argument is the base-64 encdoded tag of the recipient, | ||
| consisting of the first 4 bytes of the SHA-256 hash of the | ||
| recipient: | ||
|
|
||
| tag = SHA-256(recipient)[0..4] |
There was a problem hiding this comment.
I was wondering if the tag should be salted, to hide relations between stanzas (in different files) for the same recipient and/or anonymize the recipient
There was a problem hiding this comment.
Hmm what do you have in mind?
Maybe x = CSPRNG(4); tag = x || HMAC(recipient, x)[0..4] so that only someone who knows the recipient can link files?
That is indeed a nice step forward in privacy! Might be worth making a backwards-incompatible change. @str4d, what do you think?
There was a problem hiding this comment.
I think it's pretty common to just use the x-coordinate, similar to X25519
There was a problem hiding this comment.
I think it's pretty common to just use the x-coordinate, similar to X25519
For the shared ECDH output yes, but the input is usually either a compressed or an uncompressed point, no? x-coordinate-only ECDH like in X25519 is very uncommon on P-256. (I recently surveyed a bunch of ECDH and ECIES implementations while designing the crypto/ecdh.)
There was a problem hiding this comment.
Which spec uses a SEC1-encoded point as the input?
TLS 1.3 (by way of IEEE1363) uses the x-coordinate, for example:
https://datatracker.ietf.org/doc/html/rfc8446#section-7.4.2
7.4.2. Elliptic Curve Diffie-Hellman
For secp256r1, secp384r1, and secp521r1, ECDH calculations (including
parameter and key generation as well as the shared secret
calculation) are performed according to [IEEE1363] using the
ECKAS-DH1 scheme with the identity map as the key derivation function
(KDF), so that the shared secret is the x-coordinate of the ECDH
shared secret elliptic curve point represented as an octet string.
There was a problem hiding this comment.
My bad, I was originally trying to reply to this comment
There was a problem hiding this comment.
Maybe
x = CSPRNG(4); tag = x || HMAC(recipient, x)[0..4]so that only someone who knows the recipient can link files?
That's indeed what I had in mind, except I was thinking of putting x in a separate stanza argument instead of concatenating it (to avoid a custom split)
There was a problem hiding this comment.
Is there a reason to prefer this construction instead of HMAC(recipient, ephemeral share)[0..4]?
There was a problem hiding this comment.
IANAC, but sounds nice and simple to me.
age-piv-p256.md
Outdated
| If the shared secret is all 0x00 bytes, the identity implementation MUST | ||
| abort. |
There was a problem hiding this comment.
| If the shared secret is all 0x00 bytes, the identity implementation MUST | |
| abort. | |
| If the shared secret is the point at infinity, the identity implementation | |
| MUST abort. |
The infinity is going to be represented differently by different libraries, and often not as a long string of 0x00.
| salt = ephemeral share || recipient | ||
| info = "piv-p256" | ||
| shared secret = P256(ephemeral secret, recipient) | ||
| wrap key = HKDF-SHA-256(ikm = shared secret, salt, info) |
There was a problem hiding this comment.
If we make other backward-incompatible changes, we should swap salt and info here. HKDF is... very theoretically documented, and this is a mistake I made in the original design. It doesn't have practical consequences, and I think one can prove the security of the current design, but it makes applying more sophisticated proofs annoying.
| the recipient implementation as follows: | ||
|
|
||
| ephemeral secret = read(CSPRNG, 32) | ||
| ephemeral share = P256(ephemeral secret, basepoint) |
There was a problem hiding this comment.
"P256" is not a well-defined ECDH operation the way X25519 is.
We should define it somewhere as scalar multiplication over P-256, with SEC 1 point decoding and encoding. (Assuming that's what we are doing? But then why is the third argument 32 bytes?)
There was a problem hiding this comment.
My comments about using the x-coordinate for ECDH with P-256 (and really all the NIST P-curves) were supposed to be in reply to this comment. I guess I must've clicked the wrong one in my previous replies.
There was a problem hiding this comment.
Replying to #31 (comment).
The ECDH output is the x-coordinate. The ECDH input (that is, the third stanza argument here) is 0x04 || x || y, which is SEC 1.
https://datatracker.ietf.org/doc/html/rfc8446#section-4.2.8.2
| 2. The second argument is the base-64 encdoded tag of the recipient, | ||
| consisting of the first 4 bytes of the SHA-256 hash of the | ||
| recipient: | ||
|
|
||
| tag = SHA-256(recipient)[0..4] |
There was a problem hiding this comment.
Hmm what do you have in mind?
Maybe x = CSPRNG(4); tag = x || HMAC(recipient, x)[0..4] so that only someone who knows the recipient can link files?
That is indeed a nice step forward in privacy! Might be worth making a backwards-incompatible change. @str4d, what do you think?
|
|
||
| ## Recipient stanza | ||
|
|
||
| A piv-p256 recipient stanza has three arguments. |
There was a problem hiding this comment.
If we make other changes, we should drop "piv" from the name.
Maybe tagged-p256? Or hw-p256? Or just p256?
I assume @Foxboron could use it for age-plugin-tpm, too.
I wonder if we should standardize the recipient (not identity) format, and add native support to age(1) so that one doesn't need the plugin to encrypt to PIV/TPM/SE/any other P-256 identity.
/cc @str4d
There was a problem hiding this comment.
I can probably use this, I wasn't aware of this PR work when I originally wrote age-plugin-tpm.
There was a problem hiding this comment.
Native support sounds neat.
- You don't need to install a plugin to encrypt to these plugins. For encrypting to a different person, it feels odd that you need to install
age-plugin-seeven if you don't have an Apple device. It also avoids the plugin discovery problem where you need to explain which plugin people have to download to encrypt a message to you. - For
age-plugin-se, I could drop all cross-platform support, since the parts that don't involve encryption are only useful on macOS. In my case, it would for example avoid all the trouble I have because my plugin is written in Swift, which doesn't support musl-based Linux systems. I can imagine there are other hardware encryption plugins that don't make sense on all platforms. - It hides information about which type of token corresponds to a certain recipient
- If there's a backwards-incompatible change now, only half of the existing state machines need to be updated
|
How can we move this forward? It would be nice to have a generic implementation on the I'm contemplating implementing the spec as is into |
I was hoping @str4d could give some input on the document and the change suggestions, before I started incorporating the changes (and editorial fixes). The following backwards-incompatible changes for the recipient stanza format are on the table:
One possible way forward is to keep piv-p256 as-is, use the current version of this document (with the suggested editorial changes) as a historical description of the spec, and incorporate the changes into a different recipient format under a different recipient name (tagged-p256, hw-p256, p256), which new implementations should use. Then there is the suggestion to standardise the recipient format and implement it in age. Age could decide to (only) implement the new recipient stanza as described above, and existing implementations then don't need to bother with implementing the encryption side of the new recipient stanza, and just need to switch to generating the new recipient when supported in age. |
|
I think it would make sense to leave the current |
|
Thank you for getting this started. I think it's becoming clear that a standard tagged P-256 recipient type would be valuable across multiple plugins. I propose we
Plugins might choose to provide a recipient-only |
|
I think this sounds great! |
|
Actually, do we need a new spec for this? Why not add a section to c2sp.org/age? |
|
Considering we have two other "native recipient types" I don't think a separate standard is required really. It might be nicer to ensure the age spec doesn't become super long? |
Works for me. How do you suggest to proceed with this spec: It can be released as a 'historical' spec for documenting existing behavior of plugins, with a note forwarding to the new recipient type and recommend to implement that. Or is it not worth the trouble (and the risk of people implementing the wrong spec), and we drop it altogether, and not document anything? |
FYI, the current HEAD of age-plugin-se ( |
|
@FiloSottile are you going to propose the addition to the age spec or would it be useful if someone else finds the time to draft it? |
If anyone finds the time to make a PR against the age spec, that would be awesome! |
That's a good question, it would be nice for future-proofing to have the spec somewhere I guess. @C2SP/stewards how do you feel about "historical" specs? |
The PR can be found here: #96 |
Based on a previous proposal by @remko, with the tag design suggested by @erincandescent. Closes #96 Closes #31
Based on a previous proposal by @remko, with the tag design suggested by @erincandescent. Closes #96 Closes #31 Co-authored-by: Jack Grigg <thestr4d@gmail.com>
Based on a previous proposal by @remko, with the tag design suggested by @erincandescent. Closes #96 Closes #31 Co-authored-by: Jack Grigg <thestr4d@gmail.com>
Based on a previous proposal by @remko, with the tag design suggested by @erincandescent. Closes #96 Closes #31 Co-authored-by: Jack Grigg <thestr4d@gmail.com>
Based on a previous proposal by @remko, with the tag design suggested by @erincandescent. Closes #96 Closes #31 Co-authored-by: Jack Grigg <thestr4d@gmail.com>
This is an initial draft of a specification for the age piv-p256 recipient stanza, as used by age-plugin-yubikey and age-plugin-se.