Sesame-Server/Sources/App/Message.swift
2022-04-07 23:53:25 +02:00

108 lines
2.5 KiB
Swift

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..<data.startIndex+4])
self.id = UInt32(data: data[data.startIndex+4..<data.startIndex+8])
}
static var length: Int {
MemoryLayout<UInt32>.size * 2
}
func authenticate(using key: SymmetricKey) -> Message {
let mac = HMAC<SHA256>.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<SHA256>.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..<data.startIndex+count]
self.content = .init(decodeFrom: data.advanced(by: count))
}
func isValid(using key: SymmetricKey) -> Bool {
HMAC<SHA256>.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)
}
}
}