Skip to content
This repository was archived by the owner on Apr 22, 2023. It is now read-only.

Conversation

seishun
Copy link

@seishun seishun commented May 5, 2014

Continuing from #7359.

Just public encryption for now, since this is my personal use case that I can test in real life (and it works fine). I would like to receive feedback on this part before I continue.

The API is simple: crypto.publicEncrypt(key, buf) returns an encrypted buffer, where buf is the buffer to encrypt and key is the public key in PEM format.

@Nodejs-Jenkins
Copy link

Thank you for contributing this pull request! Here are a few pointers to make sure your submission will be considered for inclusion.

The following commiters were not found in the CLA:

  • seishun

You can fix all these things without opening another issue.

Please see CONTRIBUTING.md for more information

@sam-github
Copy link

There is no control over encryption algorithm? It doesn't even support the various RSA PKCS#1 algorithms, much less any DH/ECDH.

@seishun
Copy link
Author

seishun commented May 5, 2014

@sam-github not sure what you mean by "encryption algorithm". If you mean padding, which is the only configurable thing in RSA encryption, then yes, it's currently hard-coded to RSA_PKCS1_OAEP_PADDING. As for DH/ECDH, I am not sure how that fits with public encryption, some examples would be welcome.

lib/crypto.js Outdated
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact it works only with RSA, right? Why not just name it explicitly?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there anything other than RSA that you can public-encrypt with? If yes, then this function should support that as well. If not, then there is no ambiguity.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, you have a point. Please continue and add tests.

@indutny
Copy link
Member

indutny commented May 7, 2014

Seems to be looking good otherwise!

@seishun
Copy link
Author

seishun commented May 9, 2014

Added privateDecrypt and tests.

@seishun
Copy link
Author

seishun commented May 9, 2014

By the way, I'm open to suggestions regarding the API, since now would be the best time to discuss these things. If there aren't any, I'll add docs.

@sam-github
Copy link

@seishun, you are correct, I forgot DH crypto-systems don't support encryption as directly as RSA.

And yes, I mean padding, or schemes as PKCS#1 calls them. There are two RSA encryption schemes (RSAES-OAEP and RSAES-PKCS1-v1_5) defined by PKCS#1, and an API that doesn't support both is a problem waiting to happen, IMO. And while OAEP should probably be default, if there is a default, the v1.5 support should be there, too.

Putting RSA in the function name, since it will only ever support RSA, might help prevent bug reports about the API not working with DH/ECDH keys.

I'd also suggest adding a negative test to 05b2cf4 with a DH key... it should return some useful message (and not abort).

@sam-github
Copy link

A negative test with input larger than allowed might be useful, too. Again, I'm anticipating users not knowing that naive use of RSA encryption is probably not what they want to be using, and trying to encrypt with data larger than the padding/key size allows.

@seishun
Copy link
Author

seishun commented May 10, 2014

And while OAEP should probably be default, if there is a default, the v1.5 support should be there, too.

Do you have an idea for the API to set the padding?

Putting RSA in the function name, since it will only ever support RSA, might help prevent bug reports about the API not working with DH/ECDH keys.

"RSAPublicEncrypt"? We could just document that publicEncrypt currently only works with RSA keys, in case some other algorithm starts supporting it.

I'd also suggest adding a negative test to 05b2cf4 with a DH key... it should return some useful message (and not abort).

A negative test with input larger than allowed might be useful, too. Again, I'm anticipating users not knowing that naive use of RSA encryption is probably not what they want to be using, and trying to encrypt with data larger than the padding/key size allows.

Currently it throws with an OpenSSL error in both cases. I'm not sure if we need tests for that though, I don't see tests for trying to sign with a public key for example.

@indutny
Copy link
Member

indutny commented May 13, 2014

I don't really enjoy two things about it:

  • Fixed padding scheme
  • Parsing keys on every API call

I understand that key parsing has probably neglectable performance impact, considering the heaviness of the encryption/decryption phases, but still wasting time on every call is not something that I would wish crypto would do.

@seishun
Copy link
Author

seishun commented May 13, 2014

Parsing keys on every API call

Well, Sign and Verify do the same – if you want to sign or verify multiple chunks of data, it will have to parse the same key each time.

If we do deviate from this for RSA encryption, do you have an idea for the API? We could have a pair of classes like PublicEncrypt/PrivateDecrypt, but that again would be inconsistent with Sign/Verify since the latter are not reusable.

Maybe we should change the API of Sign/Verify to allow specifying the key at the construction, and allow reusing them?

@indutny
Copy link
Member

indutny commented May 13, 2014

One step at the time, let's see what we could do with RSA thing. Perhaps the classes should be named PublicKey and PrivateKey instead.

@seishun
Copy link
Author

seishun commented May 14, 2014

I think if we call them PublicKey and PrivateKey, people might erroneously assume you can pass their instances to sign.sign and verifier.verify instead of PEM strings.

@indutny
Copy link
Member

indutny commented May 15, 2014

Yeah... @tjfontaine and @trevnorris I really need to know your opinion on it guys. Perhaps it would be fine if crypto will accept PublicKey and PrivateKey instances to sign and verify too? Or should we just ignore and parse keys on every API call?

@seishun
Copy link
Author

seishun commented May 17, 2014

Perhaps it would be fine if crypto will accept PublicKey and PrivateKey instances to sign and verify too?

I don't like this either. I feel like it would make things inconsistent and confusing: to verify something, you have to pass a PEM string or a PublicKey instance as an argument, but to encrypt something, you have to call a method on a PublicKey instance.

@indutny
Copy link
Member

indutny commented May 17, 2014

Ok, let's just make it accept strings for now, you are right now.

@indutny
Copy link
Member

indutny commented May 17, 2014

I guess it is LGTM then, @tjfontaine LGTY?

@b1rdex
Copy link

b1rdex commented Aug 4, 2014

@indutny will this become merged? v13 or earlier?

@indutny
Copy link
Member

indutny commented Aug 5, 2014

@seishun could you please add some docs?

@seishun
Copy link
Author

seishun commented Aug 5, 2014

@indutny done!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could these functions be generic templates? I think we could use 2 functions instead of 4 here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@indutny I'm confused, which functions do you propose to combine?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PublicEncrypt and PublicDecrypt both forms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

err PrivateDecrypt.

@indutny
Copy link
Member

indutny commented Aug 7, 2014

@seishun does it makes sense? Also, feel free to ask me anything :) I'd like to get this landed before v0.12!

@seishun
Copy link
Author

seishun commented Aug 7, 2014

@indutny yes, it makes sense, and I have a question. Does publicEncrypt need to support keys encoded using a RSAPublicKey structure (the PEM header is "BEGIN RSA PUBLIC KEY"), or is it enough to just support keys encoded using a SubjectPublicKeyInfo structure (the PEM header is "BEGIN PUBLIC KEY")? Currently it supports both, but it makes it harder to combine the PublicEncrypt and PrivateDecrypt functions. OpenSSL generates SubjectPublicKeyInfo keys by default, and it's trivial to convert between the two formats.

@indutny
Copy link
Member

indutny commented Aug 7, 2014

It'd be better to support both keys.

@seishun
Copy link
Author

seishun commented Aug 9, 2014

Done. I couldn't think of a way to combine the rest of PublicEncrypt and PrivateDecrypt due to the aforementioned difference in PEM handling. Also let me know if you have a better idea for the name of the combined function.

Another idea was to read both public and private keys in PKEYCipher. However, it turned out that OpenSSL segfaults when attempting to use EVP_PKEY_decrypt with a public key, rather than return an error code.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please declare this type in a typedef right above this line?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Which type, of EVP_PKEY_cipher_init or EVP_PKEY_cipher?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Both.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now, to make it even better, let's create a class in node_crypto.h called PublicKeyCipher and move these types and functions to it ;) You could remove PKEY prefix after that.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, hope I got it right.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not move it to a class declaration?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move what, the template definition?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, type declaration. But if you'll merge two functions above, this won't be needed.

@indutny
Copy link
Member

indutny commented Aug 9, 2014

I like it, thank you very much! :) It is going to be even more awesome if you'll fix the rest of the issues ;)

@seishun
Copy link
Author

seishun commented Aug 10, 2014

Done, hope I didn't miss anything.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please move the strncmp to the next line.

@indutny
Copy link
Member

indutny commented Aug 11, 2014

@seishun thank you! :) This is totally becoming a very nice thing

@seishun
Copy link
Author

seishun commented Aug 11, 2014

Done!

@indutny
Copy link
Member

indutny commented Aug 11, 2014

LGTM, thank you!

@indutny
Copy link
Member

indutny commented Aug 11, 2014

Landed with some minor style fixes in 42bda05 . @seishun you should learn to run make cpplint before submitting ;)

Thank you!

@indutny indutny closed this Aug 11, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants