From 6adf3ecebb42c05662f7c6a792953589ffdfd4dc Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Sat, 23 Aug 2014 17:38:32 +0400 Subject: [PATCH] crypto: allow padding in RSA methods Reviewed-By: Trevor Norris --- doc/api/crypto.markdown | 23 +++++++++++++++++++++-- lib/crypto.js | 9 ++++++--- src/node_constants.cc | 24 ++++++++++++++++++++++++ src/node_crypto.cc | 9 +++++++-- src/node_crypto.h | 1 + test/simple/test-crypto.js | 24 ++++++++++++++++++++++++ 6 files changed, 83 insertions(+), 7 deletions(-) diff --git a/doc/api/crypto.markdown b/doc/api/crypto.markdown index d1ed683..cc13aca 100644 --- a/doc/api/crypto.markdown +++ b/doc/api/crypto.markdown @@ -597,17 +597,36 @@ Exports the encoded challenge associated with the SPKAC. Encrypts `buffer` with `public_key`. Only RSA is currently supported. +`public_key` can be an object or a string. If `public_key` is a string, it is +treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`. + +`public_key`: + +* `key` : A string holding the PEM encoded private key +* `padding` : An optional padding value, one of the following: + * `constants.RSA_NO_PADDING` + * `constants.RSA_PKCS1_PADDING` + * `constants.RSA_PKCS1_OAEP_PADDING` + +NOTE: All paddings are defined in `constants` module. + ## crypto.privateDecrypt(private_key, buffer) Decrypts `buffer` with `private_key`. `private_key` can be an object or a string. If `private_key` is a string, it is -treated as the key with no passphrase. +treated as the key with no passphrase and will use `RSA_PKCS1_OAEP_PADDING`. `private_key`: * `key` : A string holding the PEM encoded private key -* `passphrase` : A string of passphrase for the private key +* `passphrase` : An optional string of passphrase for the private key +* `padding` : An optional padding value, one of the following: + * `constants.RSA_NO_PADDING` + * `constants.RSA_PKCS1_PADDING` + * `constants.RSA_PKCS1_OAEP_PADDING` + +NOTE: All paddings are defined in `constants` module. ## crypto.DEFAULT_ENCODING diff --git a/lib/crypto.js b/lib/crypto.js index 16a3e38..828c0f4 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -355,14 +355,17 @@ Verify.prototype.verify = function(object, signature, sigEncoding) { return this._handle.verify(toBuf(object), toBuf(signature, sigEncoding)); }; -exports.publicEncrypt = function(object, buffer) { - return binding.publicEncrypt(toBuf(object), buffer); +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); }; exports.privateDecrypt = function(options, buffer) { var key = options.key || options; var passphrase = options.passphrase || null; - return binding.privateDecrypt(toBuf(key), buffer, passphrase); + var padding = options.padding || constants.RSA_PKCS1_OAEP_PADDING; + return binding.privateDecrypt(toBuf(key), buffer, padding, passphrase); }; diff --git a/src/node_constants.cc b/src/node_constants.cc index dc7dc80..430a09c 100644 --- a/src/node_constants.cc +++ b/src/node_constants.cc @@ -950,6 +950,30 @@ void DefineOpenSSLConstants(Handle target) { #define NPN_ENABLED 1 NODE_DEFINE_CONSTANT(target, NPN_ENABLED); #endif + +#ifdef RSA_PKCS1_PADDING + NODE_DEFINE_CONSTANT(target, RSA_PKCS1_PADDING); +#endif + +#ifdef RSA_SSLV23_PADDING + NODE_DEFINE_CONSTANT(target, RSA_SSLV23_PADDING); +#endif + +#ifdef RSA_NO_PADDING + NODE_DEFINE_CONSTANT(target, RSA_NO_PADDING); +#endif + +#ifdef RSA_PKCS1_OAEP_PADDING + NODE_DEFINE_CONSTANT(target, RSA_PKCS1_OAEP_PADDING); +#endif + +#ifdef RSA_X931_PADDING + NODE_DEFINE_CONSTANT(target, RSA_X931_PADDING); +#endif + +#ifdef RSA_PKCS1_PSS_PADDING + NODE_DEFINE_CONSTANT(target, RSA_PKCS1_PSS_PADDING); +#endif } void DefineSystemConstants(Handle target) { diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 9fa1e2c..6085a18 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -3552,6 +3552,7 @@ template & args) { char* buf = Buffer::Data(args[1]); ssize_t len = Buffer::Length(args[1]); - String::Utf8Value passphrase(args[2]); + int padding = args[2]->Uint32Value(); + + String::Utf8Value passphrase(args[3]); unsigned char* out_value = NULL; size_t out_len = -1; @@ -3658,6 +3662,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo& args) { kbuf, klen, args.Length() >= 3 && !args[2]->IsNull() ? *passphrase : NULL, + padding, reinterpret_cast(buf), len, &out_value, diff --git a/src/node_crypto.h b/src/node_crypto.h index 9531df0..2a02c89 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -577,6 +577,7 @@ class PublicKeyCipher { static bool Cipher(const char* key_pem, int key_pem_len, const char* passphrase, + int padding, const unsigned char* data, int len, unsigned char** out, diff --git a/test/simple/test-crypto.js b/test/simple/test-crypto.js index fd98966..74baaa7 100644 --- a/test/simple/test-crypto.js +++ b/test/simple/test-crypto.js @@ -857,6 +857,30 @@ assert.equal(bad_dh.verifyError, constants.DH_NOT_SUITABLE_GENERATOR); }); })(); +function test_rsa(padding) { + var input = new Buffer(padding === 'RSA_NO_PADDING' ? 1024 / 8 : 32); + for (var i = 0; i < input.length; i++) + input[i] = (i * 7 + 11) & 0xff; + var bufferToEncrypt = new Buffer(input); + + padding = constants[padding]; + + var encryptedBuffer = crypto.publicEncrypt({ + key: rsaPubPem, + padding: padding + }, bufferToEncrypt); + + var decryptedBuffer = crypto.privateDecrypt({ + key: rsaKeyPem, + padding: padding + }, encryptedBuffer); + assert.equal(input, decryptedBuffer.toString()); +} + +test_rsa('RSA_NO_PADDING'); +test_rsa('RSA_PKCS1_PADDING'); +test_rsa('RSA_PKCS1_OAEP_PADDING'); + // Test RSA key signing/verification var rsaSign = crypto.createSign('RSA-SHA1'); var rsaVerify = crypto.createVerify('RSA-SHA1'); -- 2.7.4