88 */
99
1010var rsa = require ( './libs/rsa.js' ) ;
11+ var crypt = require ( 'crypto' ) ;
1112var ber = require ( 'asn1' ) . Ber ;
1213var _ = require ( 'lodash' ) ;
1314var utils = require ( './utils' ) ;
@@ -16,16 +17,21 @@ var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1';
1617
1718module . exports = ( function ( ) {
1819 /**
19- * @param arg {string|object} Key in PEM format, or data for generate key {b: bits, e: exponent}
20+ * @param key {string|object} Key in PEM format, or data for generate key {b: bits, e: exponent}
2021 * @constructor
2122 */
22- function NodeRSA ( arg ) {
23+ function NodeRSA ( key , options ) {
2324 this . keyPair = new rsa . Key ( ) ;
25+ this . $cache = { } ;
2426
25- if ( _ . isObject ( arg ) ) {
26- this . generateKeyPair ( arg . b , arg . e ) ;
27- } else if ( _ . isString ( arg ) ) {
28- this . loadFromPEM ( arg ) ;
27+ this . options = _ . merge ( {
28+ signingAlgorithm : 'RSA-SHA256'
29+ } , options || { } ) ;
30+
31+ if ( _ . isObject ( key ) ) {
32+ this . generateKeyPair ( key . b , key . e ) ;
33+ } else if ( _ . isString ( key ) ) {
34+ this . loadFromPEM ( key ) ;
2935 }
3036 }
3137
@@ -41,6 +47,7 @@ module.exports = (function() {
4147 exp = 65537 ;
4248
4349 this . keyPair . generate ( bits , exp . toString ( 16 ) ) ;
50+ this . $recalculateCache ( ) ;
4451 return this ;
4552 } ;
4653
@@ -55,6 +62,8 @@ module.exports = (function() {
5562 this . loadFromPublicPEM ( pem , 'base64' ) ;
5663 } else
5764 throw Error ( 'Invalid PEM format' ) ;
65+
66+ this . $recalculateCache ( ) ;
5867 } ;
5968
6069 /**
@@ -106,9 +115,157 @@ module.exports = (function() {
106115 } ;
107116
108117 /**
118+ * Check if keypair contains private key
119+ */
120+ NodeRSA . prototype . isPrivate = function ( ) {
121+ return this . keyPair . n && this . keyPair . e && this . keyPair . d || false ;
122+ } ;
123+
124+ /**
125+ * Check if keypair contains public key
126+ * @param strict {boolean} - public key only, return false if have private exponent
127+ */
128+ NodeRSA . prototype . isPublic = function ( strict ) {
129+ return this . keyPair . n && this . keyPair . e && ! ( strict && this . keyPair . d ) || false ;
130+ } ;
131+
132+ /**
133+ * Encrypting data method
134+ *
135+ * @param buffer {string|number|object|array|Buffer} - data for encrypting. Object and array will convert to JSON string.
136+ * @param encoding {string} - optional. Encoding for output result, may be 'buffer', 'binary', 'hex' or 'base64'. Default 'buffer'.
137+ * @param source_encoding {string} - optional. Encoding for given string. Default utf8.
138+ * @returns {string|Buffer }
139+ */
140+ NodeRSA . prototype . encrypt = function ( buffer , encoding , source_encoding ) {
141+ var res = this . keyPair . encrypt ( this . $getDataForEcrypt ( buffer , source_encoding ) ) ;
142+
143+ if ( encoding == 'buffer' || ! encoding ) {
144+ return res ;
145+ } else {
146+ return res . toString ( encoding ) ;
147+ }
148+ } ;
149+
150+ /**
151+ * Decrypting data method
152+ *
153+ * @param buffer {Buffer} - buffer for decrypting
154+ * @param encoding - encoding for result string, can also take 'json' or 'buffer' for the automatic conversion of this type
155+ * @returns {Buffer|object|string }
156+ */
157+ NodeRSA . prototype . decrypt = function ( buffer , encoding ) {
158+ buffer = _ . isString ( buffer ) ? new Buffer ( buffer , 'base64' ) : buffer ;
159+ return this . $getDecryptedData ( this . keyPair . decrypt ( buffer ) , encoding ) ;
160+ } ;
161+
162+ /**
163+ * Signing data
164+ *
165+ * @param buffer {string|number|object|array|Buffer} - data for signing. Object and array will convert to JSON string.
166+ * @param encoding {string} - optional. Encoding for output result, may be 'buffer', 'binary', 'hex' or 'base64'. Default 'buffer'.
167+ * @param source_encoding {string} - optional. Encoding for given string. Default utf8.
168+ * @returns {string|Buffer }
169+ */
170+ NodeRSA . prototype . sign = function ( buffer , encoding , source_encoding ) {
171+ if ( ! this . isPrivate ( ) ) {
172+ throw Error ( "It is not private key" ) ;
173+ }
174+
175+ encoding = ( ! encoding || encoding == 'buffer' ? null : encoding ) ;
176+ var signer = crypt . createSign ( this . options . signingAlgorithm ) ;
177+ signer . update ( this . $getDataForEcrypt ( buffer , source_encoding ) ) ;
178+ return signer . sign ( this . getPrivatePEM ( ) , encoding ) ;
179+ } ;
180+
181+ /**
182+ * Verifying signed data
183+ *
184+ * @param buffer - signed data
185+ * @param signature
186+ * @param source_encoding {string} - optional. Encoding for given string. Default utf8.
187+ * @param signature_encoding - optional. Encoding of given signature. May be 'buffer', 'binary', 'hex' or 'base64'. Default 'buffer'.
188+ * @returns {* }
189+ */
190+ NodeRSA . prototype . verify = function ( buffer , signature , source_encoding , signature_encoding ) {
191+ signature_encoding = ( ! signature_encoding || signature_encoding == 'buffer' ? null : signature_encoding ) ;
192+ var verifier = crypt . createVerify ( this . options . signingAlgorithm ) ;
193+ verifier . update ( this . $getDataForEcrypt ( buffer , source_encoding ) ) ;
194+ return verifier . verify ( this . getPublicPEM ( ) , signature , signature_encoding ) ;
195+ } ;
196+
197+ NodeRSA . prototype . getPrivatePEM = function ( ) {
198+ if ( ! this . isPrivate ( ) ) {
199+ throw Error ( "It is not private key" ) ;
200+ }
201+
202+ return this . $cache . privatePEM ;
203+ } ;
204+
205+ NodeRSA . prototype . getPublicPEM = function ( ) {
206+ if ( ! this . isPublic ( ) ) {
207+ throw Error ( "It is not public key" ) ;
208+ }
209+
210+ return this . $cache . publicPEM ;
211+ } ;
212+
213+ /**
214+ * Preparing given data for encrypting/signing. Just make new/return Buffer object.
215+ *
216+ * @param buffer {string|number|object|array|Buffer} - data for encrypting. Object and array will convert to JSON string.
217+ * @param encoding {string} - optional. Encoding for given string. Default utf8.
218+ * @returns {Buffer }
219+ */
220+ NodeRSA . prototype . $getDataForEcrypt = function ( buffer , encoding ) {
221+ if ( _ . isString ( buffer ) || _ . isNumber ( buffer ) ) {
222+ return new Buffer ( '' + buffer , encoding || 'utf8' ) ;
223+ } else if ( Buffer . isBuffer ( buffer ) ) {
224+ return buffer ;
225+ } else if ( _ . isObject ( buffer ) ) {
226+ return new Buffer ( JSON . stringify ( buffer ) ) ;
227+ } else {
228+ throw Error ( "Unexpected data type" ) ;
229+ }
230+ } ;
231+
232+ /**
233+ *
234+ * @param buffer {Buffer} - decrypted data.
235+ * @param encoding - optional. Encoding for result output. May be 'buffer', 'json' or any of Node.js Buffer supported encoding.
236+ * @returns {* }
237+ */
238+ NodeRSA . prototype . $getDecryptedData = function ( buffer , encoding ) {
239+ encoding = encoding || 'buffer' ;
240+
241+ if ( encoding == 'buffer' ) {
242+ return buffer ;
243+ } else if ( encoding == 'json' ) {
244+ return JSON . parse ( buffer . toString ( ) ) ;
245+ } else {
246+ return buffer . toString ( encoding ) ;
247+ }
248+ } ;
249+
250+
251+ /**
252+ * private
253+ * Recalculating properties
254+ */
255+ NodeRSA . prototype . $recalculateCache = function ( ) {
256+ this . $cache . privatePEM = this . $makePrivatePEM ( ) ;
257+ this . $cache . publicPEM = this . $makePublicPEM ( ) ;
258+ } ;
259+
260+ /**
261+ * private
109262 * @returns {string } private PEM string
110263 */
111- NodeRSA . prototype . toPrivatePEM = function ( ) {
264+ NodeRSA . prototype . $makePrivatePEM = function ( ) {
265+ if ( ! this . isPrivate ( ) ) {
266+ return null ;
267+ }
268+
112269 var n = this . keyPair . n . toBuffer ( ) ;
113270 var d = this . keyPair . d . toBuffer ( ) ;
114271 var p = this . keyPair . p . toBuffer ( ) ;
@@ -138,9 +295,14 @@ module.exports = (function() {
138295 } ;
139296
140297 /**
298+ * private
141299 * @returns {string } public PEM string
142300 */
143- NodeRSA . prototype . toPublicPEM = function ( ) {
301+ NodeRSA . prototype . $makePublicPEM = function ( ) {
302+ if ( ! this . isPublic ( ) ) {
303+ return null ;
304+ }
305+
144306 var n = this . keyPair . n . toBuffer ( ) ;
145307 var length = n . length + 512 ; // magic
146308
@@ -161,75 +323,10 @@ module.exports = (function() {
161323 writer . writeBuffer ( body , 3 ) ;
162324 writer . endSequence ( ) ;
163325
164- n = writer . buffer . toString ( 'hex' ) ;
165-
166326 return '-----BEGIN PUBLIC KEY-----\n' +
167327 utils . linebrk ( writer . buffer . toString ( 'base64' ) , 64 ) +
168328 '\n-----END PUBLIC KEY-----' ;
169329 } ;
170330
171- /**
172- * Check if keypair contains private key
173- */
174- NodeRSA . prototype . isPrivate = function ( ) {
175- return this . keyPair . n && this . keyPair . e && this . keyPair . d ;
176- } ;
177-
178- /**
179- * Check if keypair contains public key
180- * @param strict {boolean} - public key only, return false if have private exponent
181- */
182- NodeRSA . prototype . isPublic = function ( strict ) {
183- return this . keyPair . n && this . keyPair . e && ! ( strict && this . keyPair . d ) ;
184- } ;
185-
186- /**
187- * Encrypting data method
188- *
189- * @param buffer {string|number|object|array|Buffer} - data for encrypting. Object and array will convert to JSON string.
190- * @param source_encoding {string} - optional. Encoding for given string. Default utf8.
191- * @param output_encoding {string} - optional. Encoding for output result, can also take 'buffer' to return Buffer object. Default base64.
192- * @returns {string|Buffer }
193- */
194- NodeRSA . prototype . encrypt = function ( buffer , source_encoding , output_encoding ) {
195- var res = null ;
196-
197- if ( _ . isString ( buffer ) || _ . isNumber ( buffer ) ) {
198- res = this . keyPair . encrypt ( new Buffer ( '' + buffer , source_encoding || 'utf8' ) ) ;
199- } else if ( Buffer . isBuffer ( buffer ) ) {
200- res = this . keyPair . encrypt ( buffer ) ;
201- } else if ( _ . isObject ( buffer ) ) {
202- res = this . keyPair . encrypt ( new Buffer ( JSON . stringify ( buffer ) ) ) ;
203- }
204-
205- if ( output_encoding == 'buffer' ) {
206- return res ;
207- } else {
208- return res . toString ( output_encoding || 'base64' ) ;
209- }
210- } ;
211-
212- /**
213- * Decrypting data method
214- *
215- * @param buffer {Buffer} - buffer for decrypting
216- * @param encoding - encoding for result string, can also take 'json' or 'buffer' for the automatic conversion of this type
217- * @returns {Buffer|object|string }
218- */
219- NodeRSA . prototype . decrypt = function ( buffer , encoding ) {
220- encoding = encoding || 'utf8' ;
221-
222- buffer = _ . isString ( buffer ) ? new Buffer ( buffer , 'base64' ) : buffer ;
223- var res = this . keyPair . decrypt ( buffer ) ;
224-
225- if ( encoding == 'buffer' ) {
226- return res ;
227- } else if ( encoding == 'json' ) {
228- return JSON . parse ( res . toString ( ) ) ;
229- } else {
230- return res . toString ( encoding ) ;
231- }
232- } ;
233-
234- return NodeRSA ;
331+ return NodeRSA ;
235332} ) ( ) ;
0 commit comments