@@ -4,10 +4,12 @@ import * as crypto from 'crypto';
44import {
55 allocateBuffer ,
66 Binary ,
7+ ByteUtils ,
78 concatBuffers ,
89 type Document ,
9- fromUTF8 ,
10- toBase64
10+ fromBase64 ,
11+ fromNumberArray ,
12+ fromUTF8
1113} from '../../bson' ;
1214import {
1315 MongoInvalidArgumentError ,
@@ -72,21 +74,21 @@ function cleanUsername(username: string) {
7274 return username . replace ( '=' , '=3D' ) . replace ( ',' , '=2C' ) ;
7375}
7476
75- function clientFirstMessageBare ( username : string , nonce : Buffer ) {
77+ function clientFirstMessageBare ( username : string , nonce : Uint8Array ) {
7678 // NOTE: This is done b/c Javascript uses UTF-16, but the server is hashing in UTF-8.
7779 // Since the username is not sasl-prep-d, we need to do this here.
7880 return concatBuffers ( [
7981 fromUTF8 ( 'n=' ) ,
8082 fromUTF8 ( username ) ,
8183 fromUTF8 ( ',r=' ) ,
82- fromUTF8 ( toBase64 ( nonce ) )
84+ fromUTF8 ( ByteUtils . toBase64 ( nonce ) )
8385 ] ) ;
8486}
8587
8688function makeFirstMessage (
8789 cryptoMethod : CryptoMethod ,
8890 credentials : MongoCredentials ,
89- nonce : Buffer
91+ nonce : Uint8Array
9092) {
9193 const username = cleanUsername ( credentials . username ) ;
9294 const mechanism =
@@ -97,9 +99,7 @@ function makeFirstMessage(
9799 return {
98100 saslStart : 1 ,
99101 mechanism,
100- payload : new Binary (
101- concatBuffers ( [ Buffer . from ( 'n,,' , 'utf8' ) , clientFirstMessageBare ( username , nonce ) ] )
102- ) ,
102+ payload : new Binary ( concatBuffers ( [ fromUTF8 ( 'n,,' ) , clientFirstMessageBare ( username , nonce ) ] ) ) ,
103103 autoAuthorize : 1 ,
104104 options : { skipEmptyExchange : true }
105105 } ;
@@ -143,7 +143,7 @@ async function continueScramConversation(
143143 const processedPassword =
144144 cryptoMethod === 'sha256' ? saslprep ( password ) : passwordDigest ( username , password ) ;
145145
146- const payload : Binary = Buffer . isBuffer ( response . payload )
146+ const payload : Binary = ByteUtils . isUint8Array ( response . payload )
147147 ? new Binary ( response . payload )
148148 : response . payload ;
149149
@@ -164,12 +164,7 @@ async function continueScramConversation(
164164
165165 // Set up start of proof
166166 const withoutProof = `c=biws,r=${ rnonce } ` ;
167- const saltedPassword = HI (
168- processedPassword ,
169- Buffer . from ( salt , 'base64' ) ,
170- iterations ,
171- cryptoMethod
172- ) ;
167+ const saltedPassword = HI ( processedPassword , fromBase64 ( salt ) , iterations , cryptoMethod ) ;
173168
174169 const clientKey = HMAC ( cryptoMethod , saltedPassword , 'Client Key' ) ;
175170 const serverKey = HMAC ( cryptoMethod , saltedPassword , 'Server Key' ) ;
@@ -188,13 +183,13 @@ async function continueScramConversation(
188183 const saslContinueCmd = {
189184 saslContinue : 1 ,
190185 conversationId : response . conversationId ,
191- payload : new Binary ( Buffer . from ( clientFinal ) )
186+ payload : new Binary ( fromUTF8 ( clientFinal ) )
192187 } ;
193188
194189 const r = await connection . command ( ns ( `${ db } .$cmd` ) , saslContinueCmd , undefined ) ;
195190 const parsedResponse = parsePayload ( r . payload ) ;
196191
197- if ( ! compareDigest ( Buffer . from ( parsedResponse . v , 'base64' ) , serverSignature ) ) {
192+ if ( ! compareDigest ( fromBase64 ( parsedResponse . v ) , serverSignature ) ) {
198193 throw new MongoRuntimeError ( 'Server returned an invalid signature' ) ;
199194 }
200195
@@ -252,35 +247,27 @@ function passwordDigest(username: string, password: string) {
252247}
253248
254249// XOR two buffers
255- function xor ( a : Buffer , b : Buffer ) {
256- if ( ! Buffer . isBuffer ( a ) ) {
257- a = Buffer . from ( a ) ;
258- }
259-
260- if ( ! Buffer . isBuffer ( b ) ) {
261- b = Buffer . from ( b ) ;
262- }
263-
250+ function xor ( a : Uint8Array , b : Uint8Array ) {
264251 const length = Math . max ( a . length , b . length ) ;
265252 const res = [ ] ;
266253
267254 for ( let i = 0 ; i < length ; i += 1 ) {
268255 res . push ( a [ i ] ^ b [ i ] ) ;
269256 }
270257
271- return Buffer . from ( res ) . toString ( 'base64' ) ;
258+ return ByteUtils . toBase64 ( fromNumberArray ( res ) ) ;
272259}
273260
274- function H ( method : CryptoMethod , text : Buffer ) {
261+ function H ( method : CryptoMethod , text : Uint8Array ) : Uint8Array {
275262 return crypto . createHash ( method ) . update ( text ) . digest ( ) ;
276263}
277264
278- function HMAC ( method : CryptoMethod , key : Buffer , text : Buffer | string ) {
265+ function HMAC ( method : CryptoMethod , key : Uint8Array , text : Uint8Array | string ) : Uint8Array {
279266 return crypto . createHmac ( method , key ) . update ( text ) . digest ( ) ;
280267}
281268
282269interface HICache {
283- [ key : string ] : Buffer ;
270+ [ key : string ] : Uint8Array ;
284271}
285272
286273let _hiCache : HICache = { } ;
@@ -295,9 +282,9 @@ const hiLengthMap = {
295282 sha1 : 20
296283} ;
297284
298- function HI ( data : string , salt : Buffer , iterations : number , cryptoMethod : CryptoMethod ) {
285+ function HI ( data : string , salt : Uint8Array , iterations : number , cryptoMethod : CryptoMethod ) {
299286 // omit the work if already generated
300- const key = [ data , salt . toString ( 'base64' ) , iterations ] . join ( '_' ) ;
287+ const key = [ data , ByteUtils . toBase64 ( salt ) , iterations ] . join ( '_' ) ;
301288 if ( _hiCache [ key ] != null ) {
302289 return _hiCache [ key ] ;
303290 }
@@ -321,7 +308,7 @@ function HI(data: string, salt: Buffer, iterations: number, cryptoMethod: Crypto
321308 return saltedData ;
322309}
323310
324- function compareDigest ( lhs : Buffer , rhs : Uint8Array ) {
311+ function compareDigest ( lhs : Uint8Array , rhs : Uint8Array ) {
325312 if ( lhs . length !== rhs . length ) {
326313 return false ;
327314 }
0 commit comments