Open szszszsz opened 2 years ago
Hi! @tomholub @twiss @onlykey
I would like to implement support for Nitrokey Webcrypt inside OpenPGP.js as a POC, so the key management and private key operations could be realized on the USB stick, instead of the PC. See ticket's description for more information.
In the past conversation there was a request for a session key decryption operation. Can you suggest how this could be done given OpenPGP.js current internals?
The way its done in the OpenPGP card specification is, that only the shared secret is calculated from the given ECC session public key of the sender. This should be enough to continue with the process on the OpenPGP.js side. Then this would be a function of a public key and algorithm OID, which could be injected inside the current session key decryption process. What do you think?
Relevant excerpt:
PS We plan to introduce RSA after we have ECC support working.
Hey :wave:
Just to confirm, the USB key only performs (in the case of ECC) the ECDH key derivation (i.e. the equivalent of this line of code), not the KDF and key unwrapping done afterwards, correct? (Or can it also do the latter? If so, it would simplify things, and you can ignore most of this comment :))
OpenPGP.js does not export those low-level operations, however, if you're making a fork you do of course have access to them. Or, you could simply replace the linked line with one that calls out to the USB key to do the key derivation.
That would make it a bit difficult to merge back the functionality into OpenPGP.js, though, if we want to do so at some point. But, one way I could see that might be feasible would be to add a function / hook to the config
object, which OpenPGP.js could call out to to do the decryption operation. Something like:
await openpgp.decrypt({ // or decryptSessionKeys
message,
decryptionKeys,
config: { deriveSharedKey }
});
async function deriveSharedKey(fingerprint, oid, publicEphemeral) {
// Call out to the USB key...
return sharedKey;
}
Where deriveSharedKey
(or an object containing multiple hooks / functions) could be imported from elsewhere, e.g. a plugin.
And decryptionKeys
would be OpenPGP.js key objects with GNU-dummy private keys for the subkeys that are stored on the USB key (I believe that's what GnuPG does as well). This approach would have the advantage that OpenPGP.js can handle looking for the relevant subkey, and call deriveSharedKey
multiple times if it's unknown which subkey the message was encrypted with (each time with the fingerprint of a different subkey). The downside might be that, in that case, it might be less efficient than having this handled elsewhere, especially if you anyway need to fetch all keys to match them to the given fingerprint? I'm not sure about this part. (If we go this route, we'd need to modify this code.)
One slightly annoying thing (if my understanding above is correct) is that the KDF and AES-KW operations are specific to ECDH, RSA doesn't do them. So we'd need separate helper functions for RSA and ECC. But maybe that's livable / just the way it is.
Indeed - what Daniel describes is a more specific proposal of what I hinted at here https://github.com/Nitrokey/nitrokey-webcrypt-openpgpjs/issues/8
Hey! Thank you for the pointers and sorry for being silent for the last weeks!
I have published a potential plugin solution at https://github.com/openpgpjs/openpgpjs/pull/1567. Please take a look.
Support session packet decryption through Nitrokey Webcrypt.
Previous discussions:
See below for the details: