@@ -357,16 +357,16 @@ final class PSQLChannelHandler: ChannelDuplexHandler {
357
357
switch mode {
358
358
case . md5( let salt) :
359
359
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
+
362
362
var hash2 = [ UInt8] ( )
363
363
hash2. reserveCapacity ( pwdhash. count + 4 )
364
- hash2. append ( contentsOf: pwdhash. utf8 )
364
+ hash2. append ( contentsOf: pwdhash)
365
365
hash2. append ( salt. 0 )
366
366
hash2. append ( salt. 1 )
367
367
hash2. append ( salt. 2 )
368
368
hash2. append ( salt. 3 )
369
- let hash = " md5 " + Insecure. MD5. hash ( data: hash2) . hexdigest ( )
369
+ let hash = Insecure . MD5. hash ( data: hash2) . md5PrefixHexdigest ( )
370
370
371
371
try ! self . encoder. encode ( . password( . init( value: hash) ) )
372
372
context. writeAndFlush ( self . wrapOutboundOut ( self . encoder. flush ( ) !) , promise: nil )
@@ -552,3 +552,40 @@ extension AuthContext {
552
552
replication: . false )
553
553
}
554
554
}
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