From 8262d987dea695f8f6a32050550138972fa112b8 Mon Sep 17 00:00:00 2001 From: Bouke Haarsma Date: Sat, 31 Dec 2022 09:50:01 +0100 Subject: [PATCH] Clarify endianness in integer byte accessor --- Sources/HAP/Security/Cryptographer.swift | 6 ++-- .../Utils/FixedWidthInteger+Extensions.swift | 13 ++++++++ Sources/HAP/Utils/Integer+Data.swift | 29 ----------------- .../FixedWithInteger+ExtensionsTests.swift | 32 +++++++++++++++++++ 4 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 Sources/HAP/Utils/FixedWidthInteger+Extensions.swift delete mode 100644 Sources/HAP/Utils/Integer+Data.swift create mode 100644 Tests/HAPTests/FixedWithInteger+ExtensionsTests.swift diff --git a/Sources/HAP/Security/Cryptographer.swift b/Sources/HAP/Security/Cryptographer.swift index a0db0c46..fd8ec603 100644 --- a/Sources/HAP/Security/Cryptographer.swift +++ b/Sources/HAP/Security/Cryptographer.swift @@ -44,7 +44,7 @@ class Cryptographer { tag: T) throws -> Data { defer { decryptCount += 1 } - let nonce = try ChaChaPoly.Nonce(data: Data(count: 4) + decryptCount.bigEndian.bytes) + let nonce = try ChaChaPoly.Nonce(data: Data(count: 4) + decryptCount.littleEndianBytes) let box = try ChaChaPoly.SealedBox(nonce: nonce, ciphertext: ciphertext, tag: tag) return try ChaChaPoly.open(box, using: decryptKey, authenticating: lengthBytes) @@ -53,8 +53,8 @@ class Cryptographer { func encrypt(plaintext: ByteBuffer) throws -> Data { defer { encryptCount += 1 } - let nonce = try ChaChaPoly.Nonce(data: Data(count: 4) + encryptCount.bigEndian.bytes) - let authenticationData = UInt16(plaintext.readableBytes).bigEndian.bytes + let nonce = try ChaChaPoly.Nonce(data: Data(count: 4) + encryptCount.littleEndianBytes) + let authenticationData = UInt16(plaintext.readableBytes).littleEndianBytes let box = try ChaChaPoly.seal(plaintext.readableBytesView, using: encryptKey, diff --git a/Sources/HAP/Utils/FixedWidthInteger+Extensions.swift b/Sources/HAP/Utils/FixedWidthInteger+Extensions.swift new file mode 100644 index 00000000..289326a2 --- /dev/null +++ b/Sources/HAP/Utils/FixedWidthInteger+Extensions.swift @@ -0,0 +1,13 @@ +import Foundation + +extension FixedWidthInteger { + /// Returns bytes in Big Endian or Network Byte Ordering. + public var bigEndianBytes: Data { + withUnsafeBytes(of: bigEndian, { Data(bytes: $0.baseAddress!, count: $0.count) }) + } + + /// Returns bytes in Little Endian. + public var littleEndianBytes: Data { + withUnsafeBytes(of: littleEndian, { Data(bytes: $0.baseAddress!, count: $0.count) }) + } +} diff --git a/Sources/HAP/Utils/Integer+Data.swift b/Sources/HAP/Utils/Integer+Data.swift deleted file mode 100644 index 43488835..00000000 --- a/Sources/HAP/Utils/Integer+Data.swift +++ /dev/null @@ -1,29 +0,0 @@ -// swiftlint:disable implicit_return -import Foundation - -extension BinaryInteger { - init(bytes: [UInt8]) { - precondition(bytes.count == MemoryLayout.size, "incorrect number of bytes") - self = bytes.withUnsafeBufferPointer { - $0.baseAddress!.withMemoryRebound(to: Self.self, capacity: 1) { - return $0.pointee - } - } - } - - init(data: Data) { - self.init(bytes: Array(data)) - } -} - -extension UnsignedInteger { - var bytes: Data { - var copy = self - // TODO: optimize this - // TODO: is this a good solution regarding LE/BE? - return withUnsafePointer(to: ©) { - let reversed: ReversedCollection = Data(bytes: $0, count: MemoryLayout.size).reversed() - return Data(reversed) - } - } -} diff --git a/Tests/HAPTests/FixedWithInteger+ExtensionsTests.swift b/Tests/HAPTests/FixedWithInteger+ExtensionsTests.swift new file mode 100644 index 00000000..5ffa193a --- /dev/null +++ b/Tests/HAPTests/FixedWithInteger+ExtensionsTests.swift @@ -0,0 +1,32 @@ +@testable import HAP +import XCTest + +final class FixedWidthIntegerExtensionTests: XCTestCase { + func testBigEndianBytes() throws { + XCTAssertEqual(UInt8(1).bigEndianBytes, Data([1])) + XCTAssertEqual(UInt16(1).bigEndianBytes, Data([0, 1])) + XCTAssertEqual(UInt32(1).bigEndianBytes, Data([0, 0, 0, 1])) + XCTAssertEqual(UInt64(1).bigEndianBytes, Data([0, 0, 0, 0, 0, 0, 0, 1])) + XCTAssertEqual(UInt16(1 << 8).bigEndianBytes, Data([1, 0])) + XCTAssertEqual(UInt32(1 << 24).bigEndianBytes, Data([1, 0, 0, 0])) + XCTAssertEqual(UInt64(1 << 56).bigEndianBytes, Data([1, 0, 0, 0, 0, 0, 0, 0])) + } + + func testLittleEndianBytes() throws { + XCTAssertEqual(UInt8(1).littleEndianBytes, Data([1])) + XCTAssertEqual(UInt16(1).littleEndianBytes, Data([1, 0])) + XCTAssertEqual(UInt32(1).littleEndianBytes, Data([1, 0, 0, 0])) + XCTAssertEqual(UInt64(1).littleEndianBytes, Data([1, 0, 0, 0, 0, 0, 0, 0])) + XCTAssertEqual(UInt16(1 << 8).littleEndianBytes, Data([0, 1])) + XCTAssertEqual(UInt32(1 << 24).littleEndianBytes, Data([0, 0, 0, 1])) + XCTAssertEqual(UInt64(1 << 56).littleEndianBytes, Data([0, 0, 0, 0, 0, 0, 0, 1])) + } + + func testBE() throws { + try XCTSkipUnless(UInt(16) == UInt(16).bigEndian, "Platform is LE") + } + + func testLE() throws { + try XCTSkipIf(UInt(16) == UInt(16).bigEndian, "Platform is BE") + } +}