@@ -357,16 +357,16 @@ final class PSQLChannelHandler: ChannelDuplexHandler {
357357 switch mode {
358358 case . md5( let salt) :
359359 let hash1 = ( authContext. password ?? " " ) + authContext. username
360- let pwdhash = Insecure . MD5. hash ( data: [ UInt8] ( hash1. utf8) ) . hexdigest ( )
361-
360+ let pwdhash = Insecure . MD5. hash ( data: [ UInt8] ( hash1. utf8) ) . asciiHexDigest ( )
361+
362362 var hash2 = [ UInt8] ( )
363363 hash2. reserveCapacity ( pwdhash. count + 4 )
364- hash2. append ( contentsOf: pwdhash. utf8 )
364+ hash2. append ( contentsOf: pwdhash)
365365 hash2. append ( salt. 0 )
366366 hash2. append ( salt. 1 )
367367 hash2. append ( salt. 2 )
368368 hash2. append ( salt. 3 )
369- let hash = " md5 " + Insecure. MD5. hash ( data: hash2) . hexdigest ( )
369+ let hash = Insecure . MD5. hash ( data: hash2) . md5PrefixHexdigest ( )
370370
371371 try ! self . encoder. encode ( . password( . init( value: hash) ) )
372372 context. writeAndFlush ( self . wrapOutboundOut ( self . encoder. flush ( ) !) , promise: nil )
@@ -552,3 +552,40 @@ extension AuthContext {
552552 replication: . false )
553553 }
554554}
555+
556+ private extension Insecure . MD5 . Digest {
557+
558+ private static let lowercaseLookup : [ UInt8 ] = [
559+ UInt8 ( ascii: " 0 " ) , UInt8 ( ascii: " 1 " ) , UInt8 ( ascii: " 2 " ) , UInt8 ( ascii: " 3 " ) ,
560+ UInt8 ( ascii: " 4 " ) , UInt8 ( ascii: " 5 " ) , UInt8 ( ascii: " 6 " ) , UInt8 ( ascii: " 7 " ) ,
561+ UInt8 ( ascii: " 8 " ) , UInt8 ( ascii: " 9 " ) , UInt8 ( ascii: " a " ) , UInt8 ( ascii: " b " ) ,
562+ UInt8 ( ascii: " c " ) , UInt8 ( ascii: " d " ) , UInt8 ( ascii: " e " ) , UInt8 ( ascii: " f " ) ,
563+ ]
564+
565+ func asciiHexDigest( ) -> [ UInt8 ] {
566+ var result = [ UInt8] ( )
567+ result. reserveCapacity ( 2 * Insecure. MD5Digest. byteCount)
568+ for byte in self {
569+ result. append ( Self . lowercaseLookup [ Int ( byte >> 4 ) ] )
570+ result. append ( Self . lowercaseLookup [ Int ( byte & 0x0F ) ] )
571+ }
572+ return result
573+ }
574+
575+ func md5PrefixHexdigest( ) -> String {
576+ // TODO: The array should be stack allocated in the best case. But we support down to 5.2.
577+ // Given that this method is called only on startup of a new connection, this is an
578+ // okay tradeoff for now.
579+ var result = [ UInt8] ( )
580+ result. reserveCapacity ( 3 + 2 * Insecure. MD5Digest. byteCount)
581+ result. append ( UInt8 ( ascii: " m " ) )
582+ result. append ( UInt8 ( ascii: " d " ) )
583+ result. append ( UInt8 ( ascii: " 5 " ) )
584+
585+ for byte in self {
586+ result. append ( Self . lowercaseLookup [ Int ( byte >> 4 ) ] )
587+ result. append ( Self . lowercaseLookup [ Int ( byte & 0x0F ) ] )
588+ }
589+ return String ( decoding: result, as: Unicode . UTF8. self)
590+ }
591+ }
0 commit comments