How to do 1-of-X or Y-of-X public key based encrypt/ decrypt in NodeJs?
I would like to be able to encrypt data using public keys, and decrypt the encrypted data using private keys.
Encryption essentially needs to accept inputs:
- Clear data to be encrypted
- A list of several public keys
- The minimum number of private keys corresponding to those public keys that are needed to decrypt the encrypted
How can this be done in NodeJs?
Scenarios
By way of concrete scenarios, where there are 5 users (A - E) with crypto key pairs in the system.
A 1-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey], 1)(1-of-2)
decrypted = crypto_decrypt(encrypted, [A.privateKey])
success:decrypted === clearText
- because
A.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey])
failure: unable to decrypt- because
C.publicKeywas not used in encryption
A Y-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey, C.publicKey], 2)(2-of-3)
decrypted = crypto_decrypt(encrypted, [A.privateKey, C.privateKey])
success:decrypted === clearText
- because both
A.publicKeyandC.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey, E.privateKey])
failure: unable to decrypt- because while
C.publicKeywas used in encryption,E.publicKeywas not
Ideally...
- At minimum I need to be able to support the 1-of-X scenario, but if Y-of-X is also possible, that would be better
- What the actual key pairs are is not so important here, could be RSA, could be any of the elliptic curves. If the method supports a number of different ones, and allows one to pick, that would be better
- Preferably not tied to the use of any particular toolset or framework
node.js encryption cryptography public-key-encryption
add a comment |
I would like to be able to encrypt data using public keys, and decrypt the encrypted data using private keys.
Encryption essentially needs to accept inputs:
- Clear data to be encrypted
- A list of several public keys
- The minimum number of private keys corresponding to those public keys that are needed to decrypt the encrypted
How can this be done in NodeJs?
Scenarios
By way of concrete scenarios, where there are 5 users (A - E) with crypto key pairs in the system.
A 1-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey], 1)(1-of-2)
decrypted = crypto_decrypt(encrypted, [A.privateKey])
success:decrypted === clearText
- because
A.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey])
failure: unable to decrypt- because
C.publicKeywas not used in encryption
A Y-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey, C.publicKey], 2)(2-of-3)
decrypted = crypto_decrypt(encrypted, [A.privateKey, C.privateKey])
success:decrypted === clearText
- because both
A.publicKeyandC.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey, E.privateKey])
failure: unable to decrypt- because while
C.publicKeywas used in encryption,E.publicKeywas not
Ideally...
- At minimum I need to be able to support the 1-of-X scenario, but if Y-of-X is also possible, that would be better
- What the actual key pairs are is not so important here, could be RSA, could be any of the elliptic curves. If the method supports a number of different ones, and allows one to pick, that would be better
- Preferably not tied to the use of any particular toolset or framework
node.js encryption cryptography public-key-encryption
1
Library recommendations are off-topic. Look at Shamirs Secret Sharing Algorithm. Not inherently asymmetric but you could make it so.
– Luke Joshua Park
Nov 13 '18 at 18:03
@LukeJoshuaPark Yup I have skimmed several papers, and it looks like this should be possible using many different types of schemes. However, there appears to be a gap between theoretically possible and concretely possible, which I am trying to fill.
– bguiz
Nov 13 '18 at 23:49
@LukeJoshuaPark speaking to your comment that "Library recommendations are off-topic", I'll amend the question to ask "how to do this" instead of "what libraries can be used to do this" - hopefully this falls within the purview of S/O. Otherwise LMK how else I should rephrase this question?
– bguiz
Nov 13 '18 at 23:50
add a comment |
I would like to be able to encrypt data using public keys, and decrypt the encrypted data using private keys.
Encryption essentially needs to accept inputs:
- Clear data to be encrypted
- A list of several public keys
- The minimum number of private keys corresponding to those public keys that are needed to decrypt the encrypted
How can this be done in NodeJs?
Scenarios
By way of concrete scenarios, where there are 5 users (A - E) with crypto key pairs in the system.
A 1-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey], 1)(1-of-2)
decrypted = crypto_decrypt(encrypted, [A.privateKey])
success:decrypted === clearText
- because
A.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey])
failure: unable to decrypt- because
C.publicKeywas not used in encryption
A Y-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey, C.publicKey], 2)(2-of-3)
decrypted = crypto_decrypt(encrypted, [A.privateKey, C.privateKey])
success:decrypted === clearText
- because both
A.publicKeyandC.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey, E.privateKey])
failure: unable to decrypt- because while
C.publicKeywas used in encryption,E.publicKeywas not
Ideally...
- At minimum I need to be able to support the 1-of-X scenario, but if Y-of-X is also possible, that would be better
- What the actual key pairs are is not so important here, could be RSA, could be any of the elliptic curves. If the method supports a number of different ones, and allows one to pick, that would be better
- Preferably not tied to the use of any particular toolset or framework
node.js encryption cryptography public-key-encryption
I would like to be able to encrypt data using public keys, and decrypt the encrypted data using private keys.
Encryption essentially needs to accept inputs:
- Clear data to be encrypted
- A list of several public keys
- The minimum number of private keys corresponding to those public keys that are needed to decrypt the encrypted
How can this be done in NodeJs?
Scenarios
By way of concrete scenarios, where there are 5 users (A - E) with crypto key pairs in the system.
A 1-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey], 1)(1-of-2)
decrypted = crypto_decrypt(encrypted, [A.privateKey])
success:decrypted === clearText
- because
A.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey])
failure: unable to decrypt- because
C.publicKeywas not used in encryption
A Y-of-X scenario:
encrypted = crypto_encrypt(clearText, [A.publicKey, B.publicKey, C.publicKey], 2)(2-of-3)
decrypted = crypto_decrypt(encrypted, [A.privateKey, C.privateKey])
success:decrypted === clearText
- because both
A.publicKeyandC.publicKeywas used in encryption
decrypted = crypto_decrypt(encrypted, [C.privateKey, E.privateKey])
failure: unable to decrypt- because while
C.publicKeywas used in encryption,E.publicKeywas not
Ideally...
- At minimum I need to be able to support the 1-of-X scenario, but if Y-of-X is also possible, that would be better
- What the actual key pairs are is not so important here, could be RSA, could be any of the elliptic curves. If the method supports a number of different ones, and allows one to pick, that would be better
- Preferably not tied to the use of any particular toolset or framework
node.js encryption cryptography public-key-encryption
node.js encryption cryptography public-key-encryption
edited Nov 13 '18 at 23:52
bguiz
asked Nov 13 '18 at 15:55
bguizbguiz
12.6k29115193
12.6k29115193
1
Library recommendations are off-topic. Look at Shamirs Secret Sharing Algorithm. Not inherently asymmetric but you could make it so.
– Luke Joshua Park
Nov 13 '18 at 18:03
@LukeJoshuaPark Yup I have skimmed several papers, and it looks like this should be possible using many different types of schemes. However, there appears to be a gap between theoretically possible and concretely possible, which I am trying to fill.
– bguiz
Nov 13 '18 at 23:49
@LukeJoshuaPark speaking to your comment that "Library recommendations are off-topic", I'll amend the question to ask "how to do this" instead of "what libraries can be used to do this" - hopefully this falls within the purview of S/O. Otherwise LMK how else I should rephrase this question?
– bguiz
Nov 13 '18 at 23:50
add a comment |
1
Library recommendations are off-topic. Look at Shamirs Secret Sharing Algorithm. Not inherently asymmetric but you could make it so.
– Luke Joshua Park
Nov 13 '18 at 18:03
@LukeJoshuaPark Yup I have skimmed several papers, and it looks like this should be possible using many different types of schemes. However, there appears to be a gap between theoretically possible and concretely possible, which I am trying to fill.
– bguiz
Nov 13 '18 at 23:49
@LukeJoshuaPark speaking to your comment that "Library recommendations are off-topic", I'll amend the question to ask "how to do this" instead of "what libraries can be used to do this" - hopefully this falls within the purview of S/O. Otherwise LMK how else I should rephrase this question?
– bguiz
Nov 13 '18 at 23:50
1
1
Library recommendations are off-topic. Look at Shamirs Secret Sharing Algorithm. Not inherently asymmetric but you could make it so.
– Luke Joshua Park
Nov 13 '18 at 18:03
Library recommendations are off-topic. Look at Shamirs Secret Sharing Algorithm. Not inherently asymmetric but you could make it so.
– Luke Joshua Park
Nov 13 '18 at 18:03
@LukeJoshuaPark Yup I have skimmed several papers, and it looks like this should be possible using many different types of schemes. However, there appears to be a gap between theoretically possible and concretely possible, which I am trying to fill.
– bguiz
Nov 13 '18 at 23:49
@LukeJoshuaPark Yup I have skimmed several papers, and it looks like this should be possible using many different types of schemes. However, there appears to be a gap between theoretically possible and concretely possible, which I am trying to fill.
– bguiz
Nov 13 '18 at 23:49
@LukeJoshuaPark speaking to your comment that "Library recommendations are off-topic", I'll amend the question to ask "how to do this" instead of "what libraries can be used to do this" - hopefully this falls within the purview of S/O. Otherwise LMK how else I should rephrase this question?
– bguiz
Nov 13 '18 at 23:50
@LukeJoshuaPark speaking to your comment that "Library recommendations are off-topic", I'll amend the question to ask "how to do this" instead of "what libraries can be used to do this" - hopefully this falls within the purview of S/O. Otherwise LMK how else I should rephrase this question?
– bguiz
Nov 13 '18 at 23:50
add a comment |
2 Answers
2
active
oldest
votes
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
- for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
- supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
add a comment |
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
- Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
- Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
- Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
- Encrypt each share using a different user's public key.
- Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:5. Send each user their encrypted share and a copy of the AES-encrypted data.The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).
– bguiz
Nov 15 '18 at 3:57
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
|
show 2 more comments
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53284796%2fhow-to-do-1-of-x-or-y-of-x-public-key-based-encrypt-decrypt-in-nodejs%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
- for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
- supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
add a comment |
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
- for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
- supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
add a comment |
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
- for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
- supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
PGP can do this.
Specifically for node, openpgpjs has a section in the README - https://github.com/openpgpjs/openpgpjs#encrypt-and-decrypt-string-data-with-pgp-keys - which could be condensed into:
const encryptedText = await openpgp.encrypt({ message: clearText, publicKeys });
const decryptedText = await openpgp.decrypt({ message: encryptedText, privateKeys });
However:
- for number of keys required to decrypt, it only supports the 1 of many scenario, not the more general some of many scenario you'd ideally want
- supports both RSA and many elliptic curve based keys, but the key format is designed for use by PGP, as the name of the library implies (so it is specific to the PGP toolchain)
answered Nov 14 '18 at 1:51
bojanglebojangle
353213
353213
add a comment |
add a comment |
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
- Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
- Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
- Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
- Encrypt each share using a different user's public key.
- Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:5. Send each user their encrypted share and a copy of the AES-encrypted data.The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).
– bguiz
Nov 15 '18 at 3:57
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
|
show 2 more comments
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
- Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
- Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
- Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
- Encrypt each share using a different user's public key.
- Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:5. Send each user their encrypted share and a copy of the AES-encrypted data.The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).
– bguiz
Nov 15 '18 at 3:57
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
|
show 2 more comments
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
- Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
- Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
- Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
- Encrypt each share using a different user's public key.
- Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.
As noted by Luke Joshua Park in the comments, this sounds like a textbook use case for a secret sharing scheme. Specifically, I would recommend that you:
- Generate a random AES (or other symmetric cipher) key. Make sure to use a cryptographically secure RNG (such as Crypto.randomBytes()) for this, since an attacker who can guess this key can also break the entire scheme!
- Encrypt the data with this key, using an authenticated encryption mode such as AES-SIV (as provided e.g. by miscreant).
- Split the AES key into multiple shares using Shamir's secret sharing scheme with the desired reconstruction threshold. (Some JS implementations I found with a quick Google search include secrets.js, jsss and ThresholdJS.)
- Encrypt each share using a different user's public key.
- Send each user their encrypted share and a copy of the AES-encrypted data.
Disclaimer: I have not reviewed the security or correctness of any of the APIs or libraries linked above. The cryptographic techniques they claim to use appear to be sound and suitable for this task, but I cannot guarantee that they have been implemented safely and correctly. Caveat emptor.
To decrypt the data, each user can first decrypt their share of the AES key using their private key, and a sufficient number of the decrypted shares can then be combined (using the same implementation of Shamir's secret sharing as used to create them) to reconstruct the original AES key, which can then be used to decrypt (and verify the integrity of) the data.
Note that Shamir's secret sharing implicitly assumes that the users who combine their shares to reconstruct the secret will trust each other and not lie about their shares or otherwise misbehave. If that's not necessarily true, there are various ways for a malicious user to trick the others — perhaps most simply by waiting for everyone else to reveal their share to them and then refusing to reveal their own share to the others. In general, preventing such attacks is all but impossible without the help of some kind of a mutually trusted party.
At the very least, though, using an encryption mode like AES-SIV with built-in authentication should ensure that users will detect if the reconstructed AES key is incorrect, since the decryption will then fail. If you want to be extra sure of this, you may wish to also send each of the users a secure cryptographic hash (e.g. SHA-512) of the AES key, so that they can verify its correctness before attempting decryption.
answered Nov 14 '18 at 17:41
Ilmari KaronenIlmari Karonen
37.2k566127
37.2k566127
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:5. Send each user their encrypted share and a copy of the AES-encrypted data.The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).
– bguiz
Nov 15 '18 at 3:57
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
|
show 2 more comments
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:5. Send each user their encrypted share and a copy of the AES-encrypted data.The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).
– bguiz
Nov 15 '18 at 3:57
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:
5. Send each user their encrypted share and a copy of the AES-encrypted data. The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).– bguiz
Nov 15 '18 at 3:57
Thanks for such a comprehensive answer Ilmari! Unfortunately SSS does not look like it will work for my use case - for non-cryptographic reasons - because I cannot do this:
5. Send each user their encrypted share and a copy of the AES-encrypted data. The architecture does not support a means for the server to "push" shares to each client, rather the clients need to be able to retrieve the encrypted data, and be able to decrypt it using their own private key(s) - hence I've asked for a means to do this using public key encryption (and not secret key encryption).– bguiz
Nov 15 '18 at 3:57
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
@bguiz: Does your server know the public keys of the clients in advance? If yes, you can just generate and encrypt the shares for each client, and store them on the server until the client connects and requests them. If not, you could still pre-generate the shares but store them unencrypted on the server until the client requests them; of course, this means that you'd be storing unencrypted shares on the server, which could be an issue if the server might get compromised.
– Ilmari Karonen
Nov 15 '18 at 13:31
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
It's also technically possible to dynamically create new shares on demand with SSS, but not all implementations may support it. Also, it requires storing the SSS polynomial coefficients, which include the secret itself (so, again, compromising the server could then compromise the data). And, of course, if the server doesn't have some way to reliably identify the clients (like, say, a public key for each of them), then you'd have to worry about the possibility of a malicious or compromised client tricking the server into giving it multiple shares.
– Ilmari Karonen
Nov 15 '18 at 13:35
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
Ah thanks for the suggestions Ilmari, but neither storing unencrypted shares on the server, nor sending private keys to the server are feasible options here. That's why I think a public key based encryption system is necessary here. Something similar to the PGP option presented in the other answer, but also supporting Y-of-X encryption would be great.
– bguiz
Nov 17 '18 at 2:42
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
@bguiz: I think there's some kind of a misunderstanding here. In the scheme I proposed above, there's no need for the server to know the clients' private keys. All it needs is the public keys, so that it can encrypt the shares.
– Ilmari Karonen
Nov 17 '18 at 10:54
|
show 2 more comments
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53284796%2fhow-to-do-1-of-x-or-y-of-x-public-key-based-encrypt-decrypt-in-nodejs%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Library recommendations are off-topic. Look at Shamirs Secret Sharing Algorithm. Not inherently asymmetric but you could make it so.
– Luke Joshua Park
Nov 13 '18 at 18:03
@LukeJoshuaPark Yup I have skimmed several papers, and it looks like this should be possible using many different types of schemes. However, there appears to be a gap between theoretically possible and concretely possible, which I am trying to fill.
– bguiz
Nov 13 '18 at 23:49
@LukeJoshuaPark speaking to your comment that "Library recommendations are off-topic", I'll amend the question to ask "how to do this" instead of "what libraries can be used to do this" - hopefully this falls within the purview of S/O. Otherwise LMK how else I should rephrase this question?
– bguiz
Nov 13 '18 at 23:50