Skip to content

Commit c5eda6c

Browse files
authored
Make password hashing fast (#189)
1 parent 046d3ba commit c5eda6c

File tree

1 file changed

+41
-4
lines changed

1 file changed

+41
-4
lines changed

Sources/PostgresNIO/New/PSQLChannelHandler.swift

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)