Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Signcryption" support (e.g. PSS-R) #231

Open
tarcieri opened this issue Nov 23, 2022 · 25 comments
Open

"Signcryption" support (e.g. PSS-R) #231

tarcieri opened this issue Nov 23, 2022 · 25 comments

Comments

@tarcieri
Copy link
Member

tarcieri commented Nov 23, 2022

We've had a few requests (#86, #186, #230) to support decrypting messages using a public key. Though this should be straightforward using any encryption padding as it's the reciprocal operation to public-key encryption, the desired operation in this case seems to be "signcryption", i.e. the public-key equivalent to authenticated encryption. See this comment for more information.

Bellare and Rogaway described a construction specifically for this purpose as an extension of RSASSA-PSS: Probabilistic Signature Scheme with Recovery (PSS-R) as described in Section 5 of: https://web.cs.ucdavis.edu/~rogaway/papers/exact.pdf

(it's also known as EMSR-PSS as described in section 1.2 of this paper)

There are also a few other such schemes, such as ISO/IEC 9796-1 and 9796-2.

IEEE P1363 describes a specification for PSS-R.

@tarcieri
Copy link
Member Author

tarcieri commented Nov 23, 2022

The only open source library I'm aware of which implements PSS-R is Crypto++. We can potentially use it for interop testing:

https://github.com/weidai11/cryptopp/blob/master/pssr.h

However, I'm not sure what "flavor" of PSS-R it implements offhand or if it's remotely standard. If Crypto++ provides a nonstandard implementation, perhaps we should attempt to implement the IEEE P1363 flavor.

See also: http://www.weidai.com/scan-mirror/sig.html#sem_PSSR-MGF1

That mentions patents over PSS but to my knowledge those patents have expired, and if they hadn't would probably apply to our implementation of PSS as well.

@bajie-git
Copy link

Hello, are there any plans to support public key decryption and private key encryption now? Recently, I was doing data interaction with Java. The Standard library of Java provides the rsa public key decryption private key encryption scheme by default. It seems difficult to do this in Trust

@tarcieri
Copy link
Member Author

@bajie-git is there a specific construction you're interested in?

@bajie-git
Copy link

bajie-git commented Jul 20, 2023

@bajie-git is there a specific construction you're interested in?

Sorry, my English is not very good. I understand that you are asking me about API design. I hope it is better to provide corresponding encryption and decryption methods for both public and private keys.

    pub_key.encrypt(..);
    pub_key.decrypt(..);
    
    priv_key.encrypt(..);
    priv_key.decrypt(..);

I have tried to implement it myself based on source code, but I have failed. I am not very proficient in both rust and rsa algorithms

@tarcieri
Copy link
Member Author

tarcieri commented Jul 20, 2023

Sorry, that’s not what I was asking.

What algorithm or construction are you actually trying to implement? What goal are you trying to accomplish? At a high level, not “I want to encrypt with a public key”

Would PSS-R work for your use case, or are you trying to roll your own crypto?

@bajie-git
Copy link

Here is a simple implementation of using rsa to encrypt the returned data. Only the server saves a private key, and the public key is distributed across different clients. The server encrypts the data using the private key and returns it to the client.

@tarcieri
Copy link
Member Author

In such a case you can give the server a public key, and then distribute the private keys to the clients, which would be the typical RSA workflow

@bajie-git
Copy link

Okay, I understand what you mean, but the private key can be derived from the public key, and the client is not trusted here, so this is also a problem for us. Overall, the method I use here is not the standard method for rsa. I will think of another way. Thank you for your reply

@Antosser
Copy link

The problem is that this is the only Rust library for RSA (thanks for that), which doesn't support private key encryption, while almost every other language does

@bajie-git
Copy link

The problem is that this is the only Rust library for RSA (thanks for that), which doesn't support private key encryption, while almost every other language does

I have the same feeling as you, especially when Wasm compilation requires this pure rust library. But I am not proficient in rust and rsa and cannot provide any effective code assistance.

@tarcieri
Copy link
Member Author

The problem is that this is the only Rust library for RSA (thanks for that), which doesn't support private key encryption, while almost every other language does

There's a term for replicating features/functionality simply because others do: cargo culting. That is very much what I'm trying to avoid here, which is why I'm asking for specific use cases and constructions, so I can ascertain whether people are requesting this feature due to legitimate use cases or misuses and confusion about how the RSA cryptosystem should be deployed.

Furthermore, so far I believe only Java and Node.js have been cited as as examples, and let me make very clear that the cryptographic APIs these environments provide are full of misuse potential and very much not something we want to copy outright. In designing cryptographic APIs, we have 20/20 hindsight on mistakes made in other environments and avoid repeating them as we design misuse resistant APIs.

Beyond just not wanting to copy other people's APIs without justification, simply slapping an encrypt method on RsaPrivateKey and a decrypt method makes it less clear which key is intended to be used in each role, as either key can now be used in either role as you proposed earlier.

That is an API which invites misuses. For a user who is unfamiliar with the RSA cryptosystem, it's unclear which key is intended for the decryption role and which key is intended for the encryption role. And indeed that sort of role confusion seems like a potential source of these API requests.

And furthermore, as I explained in the toplevel description, these are use cases better served by using a signcryption construction like PSS-R rather than using the RSA cryptosystem "backwards" by using the d exponent for encryption and the e exponent for decryption.

the private key can be derived from the public key, and the client is not trusted here

@bajie-git I think you meant to say "the public key can be derived from the private key", and let me note you are definitely trusting the client with the ability to decrypt ciphertext, which is the only function the RSA cryptosystem provides when used with encryption-oriented padding modes.

It sounds like you care about authentication though, and would potentially benefit from something like PSS-R. Alternatively it sounds like you want broadcast encryption of signed data, for which there are specific protocols.

@bajie-git
Copy link

“Alternatively it sounds like you want broadcast encryption of signed data, for which there are specific protocols.”

This summary is very accurate. I just want to implement a simple encryption method. At the same time, I think your answer is very reasonable, as it can indeed lead to abuse. But if public key decryption is implemented, it will indeed be helpful for some simple encryption scenarios. Perhaps this was not considered by rsa in its design, and perhaps we can provide some options through features.

@Irene-123
Copy link

Hii I'm looking to contribute here, trying to understand the things first

@tarcieri
Copy link
Member Author

@Irene-123 for starters you might take a look at the existing PSS implementation: https://github.com/RustCrypto/RSA/blob/master/src/algorithms/pss.rs

@Irene-123
Copy link

Hii I was wondering if you guys could have a Contributing.md file which shows how to run the project files & tests for any specific case? Shall I open a new issue for this?

@tarcieri
Copy link
Member Author

tarcieri commented Aug 4, 2023

Sure, that sounds good to me. Really it's just $ cargo test to run tests (or $ cargo test --all-features to test everything)

@tarcieri
Copy link
Member Author

tarcieri commented Aug 5, 2023

I'd like to expound upon this from the original description and explain why a simple repurposing of PKCS#1v1.5 encryption is inappropriate/insecure in this case:

Though this should be straightforward using any encryption padding as it's the reciprocal operation to public-key encryption, the desired operation in this case seems to be "signcryption", i.e. the public-key equivalent to authenticated encryption.

PKCS#1v1.5 does not provide this property. Anyone who holds the public key can perform offline chosen ciphertext attacks (CCAs) using a brute force attack based on trial decryption. Through such an attack they may discover a decrypted plaintext with desirable properties.

This is where the "sign" part of signcryption comes in. We want the encrypted message to also prove knowledge of the private key, so a holder of a public key can't produce forgeries using an offline CCA. Signcryption includes forgery detection and prevents this class of attack.

@Antosser
Copy link

Antosser commented Aug 5, 2023

I'm not sure what about "we don't currently implement it" is unclear. You are asking for a feature we don't have yet. The solution is for someone to implement #231. Until that happens, the feature doesn't exist, and if it does't exist you can't use it yet.

I understand that signcryption is not a thing yet, but is it possible to sign an encrypted message with a private key which can be encrypted with the public key? I have seen the singing code in the docs but didn't understand why the verifying key is derived from the private key instead of the public key.

@tarcieri
Copy link
Member Author

tarcieri commented Aug 5, 2023

If you mean "sign an encrypted message with a private key which can be decrypted with the public key", that's exactly what signcryption is.

didn't understand why the verifying key is derived from the private key instead of the public key.

The verifying key is always a public key in digital signature systems.

@sosaucily
Copy link

Hi @tarcieri I was looking at SRPs recently, but am thinking PSS sigs might solve my need, which I think is also related to this thread. I'll list my use-case below.

I have a client app which has a private key (bitcoin), and a server with an API in front of a database. The client should be able to publically register with it's derived pub key, and then create database entries via the API. A user should be able to edit their db rows, but obviously only the ones they own.

The user would sign a message with their private key, and submit the API call with encrypted message and their pub key. They pub key acts as the 'user-id' in the database. The server ensures it can decrypt the message with the pub key, to authenticate, and then allow the user to update the database.

For completeness of the example, to thwart replay attacks, the server would provide the client with a random nonce, which the client would have to include in it's encrypted message.

I believe this is the same use case others in this thread are describing.

It seems like PSS would solve this, as the client would hand the verifying_key to the server, and that is used to authenticate and decrypt.

Thanks for your thoughts!

@tarcieri
Copy link
Member Author

tarcieri commented Nov 2, 2023

@sosaucily a simpler approach for that particular use case is to use TLS to encrypt the client/server connection and have the client send a signed message over a TLS encrypted channel

@sosaucily
Copy link

@sosaucily a simpler approach for that particular use case is to use TLS to encrypt the client/server connection and have the client send a signed message over a TLS encrypted channel

@tarcieri I'm not sure how TLS allows for authentication, to ensure that the user can only edit data that they own. Would a cert need to be issued and stored on the server for their private key?

@tarcieri
Copy link
Member Author

tarcieri commented Nov 3, 2023

Well first, the client is providing you a signed message, so the easiest thing to verify is the signature.

But also, TLS supports mutual authentication (mTLS) where the client can also present a certificate in the TLS handshake, if you so desire.

A bearer credential a.k.a. "cookie" is also a common way to authenticate TLS clients.

@sosaucily
Copy link

Thank you, yes I see how simple signed-message verification can work here. Is there a library in the RustCrypto org that would provide this out-of-the-box, in particular with things like replay-attacks handled? If possible, i'm looking for a package that uses ECDSA

@tarcieri
Copy link
Member Author

tarcieri commented Nov 5, 2023

ECDSA is supported by the elliptic curve implementations at:

https://github.com/rustcrypto/elliptic-curves

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants