From cc4be6178e153ea165b7bad0fa78b05fa36b7f07 Mon Sep 17 00:00:00 2001 From: Brian Floersch Date: Sat, 25 Nov 2023 19:20:28 -0500 Subject: [PATCH 1/2] fix arithmetic overflow --- Sources/sqids/Sqids.swift | 2 +- Tests/sqidsTests/EncodeTests.swift | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/Sources/sqids/Sqids.swift b/Sources/sqids/Sqids.swift index 0064970..aec4b8a 100644 --- a/Sources/sqids/Sqids.swift +++ b/Sources/sqids/Sqids.swift @@ -217,7 +217,7 @@ public struct Sqids { let count = Id(alphabet.count) return id.reduce(0) { - $0 * count + Id(alphabet.firstIndex(of: $1) ?? -1) + $0 &* count &+ Id(alphabet.firstIndex(of: $1) ?? -1) } } diff --git a/Tests/sqidsTests/EncodeTests.swift b/Tests/sqidsTests/EncodeTests.swift index e78993e..463f609 100644 --- a/Tests/sqidsTests/EncodeTests.swift +++ b/Tests/sqidsTests/EncodeTests.swift @@ -145,4 +145,10 @@ final class EncodeTests: XCTestCase { XCTAssertEqual(-1, id) } } + + func testDecodeOfUntrustedInput() throws { + let sqids = Sqids() + let badInput = try sqids.encode([Int64.max]) + "a" + _ = try sqids.decode(badInput) // Should not crash + } } From bbf6097f90373a4fd79d3ff31390adf978e3780f Mon Sep 17 00:00:00 2001 From: Brian Floersch Date: Sat, 25 Nov 2023 19:33:20 -0500 Subject: [PATCH 2/2] fix arithmetic overflow by throwing --- Sources/sqids/Sqids.swift | 15 +++++++++++---- Tests/sqidsTests/EncodeTests.swift | 5 ++++- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/Sources/sqids/Sqids.swift b/Sources/sqids/Sqids.swift index aec4b8a..66311e8 100644 --- a/Sources/sqids/Sqids.swift +++ b/Sources/sqids/Sqids.swift @@ -32,6 +32,7 @@ public struct Sqids { case invalidMinLength(Int) case valueError(Id) case maximumAttemptsReached + case overflow } public static let defaultAlphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" public static let minAlphabetLength = 3 @@ -160,7 +161,7 @@ public struct Sqids { break } else { - let number = toNumber( + let number = try toNumber( id: chunks[0], alphabet: Array(alphabet.suffix(from: 1)) ) @@ -213,11 +214,17 @@ public struct Sqids { return characters } - func toNumber(id: String, alphabet: [Character]) -> Id { + func toNumber(id: String, alphabet: [Character]) throws -> Id { let count = Id(alphabet.count) - return id.reduce(0) { - $0 &* count &+ Id(alphabet.firstIndex(of: $1) ?? -1) + return try id.reduce(0) { + let (product, productOverflow) = $0.multipliedReportingOverflow(by: count) + guard !productOverflow else { throw Error.overflow } + + let (sum, sumOverflow) = product.addingReportingOverflow(Id(alphabet.firstIndex(of: $1) ?? -1)) + guard !sumOverflow else { throw Error.overflow } + + return sum } } diff --git a/Tests/sqidsTests/EncodeTests.swift b/Tests/sqidsTests/EncodeTests.swift index 463f609..5986913 100644 --- a/Tests/sqidsTests/EncodeTests.swift +++ b/Tests/sqidsTests/EncodeTests.swift @@ -149,6 +149,9 @@ final class EncodeTests: XCTestCase { func testDecodeOfUntrustedInput() throws { let sqids = Sqids() let badInput = try sqids.encode([Int64.max]) + "a" - _ = try sqids.decode(badInput) // Should not crash + do { + _ = try sqids.decode(badInput) // Should not crash + } + catch Sqids.Error.overflow { } } }