@@ -154,6 +154,28 @@ bcrypt.hash = function(s, salt, callback, progressCallback) {
154154 nextTick ( callback . bind ( this , Error ( "Illegal arguments: " + ( typeof s ) + ', ' + ( typeof salt ) ) ) ) ;
155155} ;
156156
157+ /**
158+ * Compares two strings of the same length in constant time.
159+ * @param {string } known Must be of the correct length
160+ * @param {string } unknown Must be the same length as `known`
161+ * @returns {boolean }
162+ * @inner
163+ */
164+ function safeStringCompare ( known , unknown ) {
165+ var right = 0 ,
166+ wrong = 0 ;
167+ for ( var i = 0 , k = known . length ; i < k ; ++ i ) {
168+ if ( known . charCodeAt ( i ) === unknown . charCodeAt ( i ) )
169+ ++ right ;
170+ else
171+ ++ wrong ;
172+ }
173+ // Prevent removal of unused variables (never true, actually)
174+ if ( right < 0 )
175+ return false ;
176+ return wrong === 0 ;
177+ }
178+
157179/**
158180 * Synchronously tests a string against a hash.
159181 * @param {string } s String to compare
@@ -167,15 +189,7 @@ bcrypt.compareSync = function(s, hash) {
167189 throw Error ( "Illegal arguments: " + ( typeof s ) + ', ' + ( typeof hash ) ) ;
168190 if ( hash . length !== 60 )
169191 return false ;
170- var comp = bcrypt . hashSync ( s , hash . substr ( 0 , hash . length - 31 ) ) ,
171- same = comp . length === hash . length ,
172- max_length = ( comp . length < hash . length ) ? comp . length : hash . length ;
173- // to prevent timing attacks, should check entire string
174- // don't exit after found to be false
175- for ( var i = 0 ; i < max_length ; ++ i )
176- if ( comp . length >= i && hash . length >= i && comp [ i ] != hash [ i ] )
177- same = false ;
178- return same ;
192+ return safeStringCompare ( bcrypt . hashSync ( s , hash . substr ( 0 , hash . length - 31 ) ) , hash ) ;
179193} ;
180194
181195/**
@@ -195,8 +209,15 @@ bcrypt.compare = function(s, hash, callback, progressCallback) {
195209 nextTick ( callback . bind ( this , Error ( "Illegal arguments: " + ( typeof s ) + ', ' + ( typeof hash ) ) ) ) ;
196210 return ;
197211 }
212+ if ( hash . length !== 60 ) {
213+ nextTick ( callback . bind ( this , null , false ) ) ;
214+ return ;
215+ }
198216 bcrypt . hash ( s , hash . substr ( 0 , 29 ) , function ( err , comp ) {
199- callback ( err , hash === comp ) ;
217+ if ( err )
218+ callback ( err ) ;
219+ else
220+ callback ( null , safeStringCompare ( comp , hash ) ) ;
200221 } , progressCallback ) ;
201222} ;
202223
0 commit comments