import Foundation import CryptoKit import NIOCore import Vapor struct Message: Equatable, Hashable { static var length: Int { SHA256Digest.byteCount + Content.length } struct Content: Equatable, Hashable { let time: UInt32 let id: UInt32 init(time: UInt32, id: UInt32) { self.time = time self.id = id } init(decodeFrom data: Data) { self.time = UInt32(data: data[data.startIndex...size * 2 } func authenticate(using key: SymmetricKey) -> Message { let mac = HMAC.authenticationCode(for: encoded, using: key) return .init(mac: Data(mac.map { $0 }), content: self) } func authenticateAndSerialize(using key: SymmetricKey) -> Data { let encoded = self.encoded let mac = HMAC.authenticationCode(for: encoded, using: key) return Data(mac.map { $0 }) + encoded } var encoded: Data { time.encoded + id.encoded } var bytes: [UInt8] { time.bytes + id.bytes } } let mac: Data let content: Content init(mac: Data, content: Content) { self.mac = mac self.content = content } init?(decodeFrom buffer: ByteBuffer) { guard let data = buffer.getData(at: 0, length: Message.length) else { return nil } self.init(decodeFrom: data) } private init(decodeFrom data: Data) { let count = SHA256Digest.byteCount self.mac = data[data.startIndex.. Bool { HMAC.isValidAuthenticationCode(mac, authenticating: content.encoded, using: key) } var encoded: Data { mac + content.encoded } var bytes: [UInt8] { Array(mac) + content.bytes } } extension UInt32 { init(data: Data) { self = data .reversed() .enumerated() .map { UInt32($0.element) << ($0.offset * 8) } .reduce(0, +) } var encoded: Data { .init(bytes) } var bytes: [UInt8] { (0..<4).reversed().map { UInt8((self >> ($0*8)) & 0xFF) } } }