11/*!
22 * Fast "async" scrypt implementation in JavaScript.
3- * Copyright (c) 2013-2014 Dmitry Chestnykh | BSD License
3+ * Copyright (c) 2013-2015 Dmitry Chestnykh | BSD License
44 * https://github.com/dchest/scrypt-async-js
55 */
66
99 */
1010
1111/**
12- * scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encoding)
12+ * scrypt(password, salt, logN, r, dkLen, [ interruptStep] , callback, [ encoding] )
1313 *
1414 * Derives a key from password and salt and calls callback
1515 * with derived key as the only argument.
1616 *
17+ * Calculations are interrupted with zero setTimeout at the given
18+ * interruptSteps to avoid freezing the browser. If interruptStep is not given,
19+ * it defaults to 1000. If it's zero, the callback is called immediately after
20+ * calculation, avoiding setTimeout.
21+ *
1722 * @param {string|Array.<number> } password Password.
1823 * @param {string|Array.<number> } salt Salt.
19- * @param {number } logN CPU/memory cost parameter (1 to 31).
20- * @param {number } r Block size parameter.
21- * @param {number } dkLen Length of derived key.
22- * @param {number } interruptStep Steps to split calculation with timeouts (default 1000).
23- * @param {function(string) } callback Callback function.
24- * @param {string? } encoding Result encoding ("base64", "hex", or null).
24+ * @param {number } logN CPU/memory cost parameter (1 to 31).
25+ * @param {number } r Block size parameter.
26+ * @param {number } dkLen Length of derived key.
27+ * @param {number? } interruptStep (optional) Steps to split calculation with timeouts (default 1000).
28+ * @param {function(string|Array.<number>) } callback Callback function.
29+ * @param {string? } encoding (optional) Result encoding ("base64", "hex", or null).
30+ *
2531 */
2632function scrypt ( password , salt , logN , r , dkLen , interruptStep , callback , encoding ) {
2733 'use strict' ;
@@ -333,7 +339,7 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
333339 }
334340 if ( len % 3 > 0 ) {
335341 arr [ arr . length - 1 ] = '=' ;
336- if ( len % 3 == 1 ) arr [ arr . length - 2 ] = '=' ;
342+ if ( len % 3 === 1 ) arr [ arr . length - 2 ] = '=' ;
337343 }
338344 return arr . join ( '' ) ;
339345 }
@@ -355,9 +361,9 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
355361 throw new Error ( 'scrypt: parameters are too large' ) ;
356362
357363 // Decode strings.
358- if ( typeof password == 'string' )
364+ if ( typeof password === 'string' )
359365 password = stringToUTF8Bytes ( password ) ;
360- if ( typeof salt == 'string' )
366+ if ( typeof salt === 'string' )
361367 salt = stringToUTF8Bytes ( salt ) ;
362368
363369 if ( typeof Int32Array !== 'undefined' ) {
@@ -427,23 +433,46 @@ function scrypt(password, salt, logN, r, dkLen, interruptStep, callback, encodin
427433 } ) ( ) ;
428434 }
429435
430- // Note: step argument for interruptedFor must be divisible by
431- // two, since smixStepX work in increments of 2.
432- if ( ! interruptStep ) interruptStep = 1000 ;
433-
434- smixStart ( ) ;
435- interruptedFor ( 0 , N , interruptStep * 2 , smixStep1 , function ( ) {
436- interruptedFor ( 0 , N , interruptStep * 2 , smixStep2 , function ( ) {
437- smixFinish ( ) ;
436+ function getResult ( enc ) {
438437 var result = PBKDF2_HMAC_SHA256_OneIter ( password , B , dkLen ) ;
439- if ( encoding == " base64" )
440- callback ( bytesToBase64 ( result ) ) ;
441- else if ( encoding == " hex" )
442- callback ( bytesToHex ( result ) ) ;
438+ if ( enc === ' base64' )
439+ return bytesToBase64 ( result ) ;
440+ else if ( enc === ' hex' )
441+ return bytesToHex ( result ) ;
443442 else
444- callback ( result ) ;
443+ return result ;
444+ }
445+
446+ if ( typeof interruptStep === 'function' ) {
447+ // Called as: scrypt(..., callback, [encoding])
448+ // shifting: scrypt(..., interruptStep, callback, [encoding])
449+ encoding = callback ;
450+ callback = interruptStep ;
451+ interruptStep = 1000 ;
452+ }
453+
454+ if ( interruptStep <= 0 ) {
455+ //
456+ // Blocking async variant, calls callback.
457+ //
458+ smixStart ( ) ;
459+ smixStep1 ( 0 , N ) ;
460+ smixStep2 ( 0 , N ) ;
461+ smixFinish ( ) ;
462+ callback ( getResult ( encoding ) ) ;
463+
464+ } else {
465+ //
466+ // Async variant with interruptions, calls callback.
467+ //
468+ smixStart ( ) ;
469+ interruptedFor ( 0 , N , interruptStep * 2 , smixStep1 , function ( ) {
470+ interruptedFor ( 0 , N , interruptStep * 2 , smixStep2 , function ( ) {
471+ smixFinish ( ) ;
472+ callback ( getResult ( encoding ) ) ;
473+ } ) ;
445474 } ) ;
446- } ) ;
475+ }
447476}
448477
449478if ( typeof module !== 'undefined' ) module . exports = scrypt ;
0 commit comments