Skip to content

Commit

Permalink
crypto: implement privateEncrypt/publicDecrypt
Browse files Browse the repository at this point in the history
PR-URL: #625
Reviewed-By: Ben Noordhuis <[email protected]>
Fix #477
  • Loading branch information
indutny committed Jan 27, 2015
1 parent b50fea4 commit 87e62bd
Show file tree
Hide file tree
Showing 5 changed files with 51 additions and 18 deletions.
8 changes: 8 additions & 0 deletions doc/api/crypto.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -707,6 +707,14 @@ treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`.

NOTE: All paddings are defined in `constants` module.

## crypto.privateEncrypt(private_key, buffer)

See above for details. Has the same API as `crypto.privateDecrypt`.

## crypto.publicDecrypt(public_key, buffer)

See above for details. Has the same API as `crypto.publicEncrypt`.

## crypto.DEFAULT_ENCODING

The default encoding to use for functions that can take either strings
Expand Down
34 changes: 23 additions & 11 deletions lib/crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -337,19 +337,31 @@ Verify.prototype.verify = function(object, signature, sigEncoding) {
return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding));
};

exports.publicEncrypt = function(options, buffer) {
var key = options.key || options;
var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING;
return binding.publicEncrypt(toBuf(key), buffer, padding);
};
function rsaPublic(method, defaultPadding) {
return function(options, buffer) {
var key = options.key || options;
var padding = options.padding || defaultPadding;
return method(toBuf(key), buffer, padding);
};
}

exports.privateDecrypt = function(options, buffer) {
var key = options.key || options;
var passphrase = options.passphrase || null;
var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING;
return binding.privateDecrypt(toBuf(key), buffer, padding, passphrase);
};
function rsaPrivate(method, defaultPadding) {
return function(options, buffer) {
var key = options.key || options;
var passphrase = options.passphrase || null;
var padding = options.padding || defaultPadding;
return method(toBuf(key), buffer, padding, passphrase);
};
}

exports.publicEncrypt = rsaPublic(binding.publicEncrypt,
constants.RSA_PKCS1_OAEP_PADDING);
exports.publicDecrypt = rsaPublic(binding.publicDecrypt,
constants.RSA_PKCS1_PADDING);
exports.privateEncrypt = rsaPrivate(binding.privateEncrypt,
constants.RSA_PKCS1_PADDING);
exports.privateDecrypt = rsaPrivate(binding.privateDecrypt,
constants.RSA_PKCS1_OAEP_PADDING);


exports.createDiffieHellman = exports.DiffieHellman = DiffieHellman;
Expand Down
18 changes: 13 additions & 5 deletions src/node_crypto.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3561,12 +3561,12 @@ bool PublicKeyCipher::Cipher(const char* key_pem,

// Check if this is a PKCS#8 or RSA public key before trying as X.509 and
// private key.
if (operation == kEncrypt &&
if (operation == kPublic &&
strncmp(key_pem, PUBLIC_KEY_PFX, PUBLIC_KEY_PFX_LEN) == 0) {
pkey = PEM_read_bio_PUBKEY(bp, nullptr, nullptr, nullptr);
if (pkey == nullptr)
goto exit;
} else if (operation == kEncrypt &&
} else if (operation == kPublic &&
strncmp(key_pem, PUBRSA_KEY_PFX, PUBRSA_KEY_PFX_LEN) == 0) {
RSA* rsa = PEM_read_bio_RSAPublicKey(bp, nullptr, nullptr, nullptr);
if (rsa) {
Expand All @@ -3577,7 +3577,7 @@ bool PublicKeyCipher::Cipher(const char* key_pem,
}
if (pkey == nullptr)
goto exit;
} else if (operation == kEncrypt &&
} else if (operation == kPublic &&
strncmp(key_pem, CERTIFICATE_PFX, CERTIFICATE_PFX_LEN) == 0) {
x509 = PEM_read_bio_X509(bp, nullptr, CryptoPemCallback, nullptr);
if (x509 == nullptr)
Expand Down Expand Up @@ -5038,13 +5038,21 @@ void InitCrypto(Handle<Object> target,
env->SetMethod(target, "getCiphers", GetCiphers);
env->SetMethod(target, "getHashes", GetHashes);
env->SetMethod(target, "publicEncrypt",
PublicKeyCipher::Cipher<PublicKeyCipher::kEncrypt,
PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
EVP_PKEY_encrypt_init,
EVP_PKEY_encrypt>);
env->SetMethod(target, "privateDecrypt",
PublicKeyCipher::Cipher<PublicKeyCipher::kDecrypt,
PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate,
EVP_PKEY_decrypt_init,
EVP_PKEY_decrypt>);
env->SetMethod(target, "privateEncrypt",
PublicKeyCipher::Cipher<PublicKeyCipher::kPrivate,
EVP_PKEY_sign_init,
EVP_PKEY_sign>);
env->SetMethod(target, "publicDecrypt",
PublicKeyCipher::Cipher<PublicKeyCipher::kPublic,
EVP_PKEY_verify_recover_init,
EVP_PKEY_verify_recover>);
}

} // namespace crypto
Expand Down
4 changes: 2 additions & 2 deletions src/node_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -553,8 +553,8 @@ class PublicKeyCipher {
const unsigned char *in, size_t inlen);

enum Operation {
kEncrypt,
kDecrypt
kPublic,
kPrivate
};

template <Operation operation,
Expand Down
5 changes: 5 additions & 0 deletions test/parallel/test-crypto.js
Original file line number Diff line number Diff line change
Expand Up @@ -841,6 +841,11 @@ assert.equal(bad_dh.verifyError, constants.DH_NOT_SUITABLE_GENERATOR);
decryptedBuffer = crypto.privateDecrypt(keyPem, encryptedBuffer);
assert.equal(input, decryptedBuffer.toString());

encryptedBuffer = crypto.privateEncrypt(keyPem, bufferToEncrypt);

decryptedBuffer = crypto.publicDecrypt(keyPem, encryptedBuffer);
assert.equal(input, decryptedBuffer.toString());

assert.throws(function() {
crypto.privateDecrypt({
key: rsaKeyPemEncrypted,
Expand Down

0 comments on commit 87e62bd

Please sign in to comment.