210 lines
5.5 KiB
Swift
210 lines
5.5 KiB
Swift
// The Swift Programming Language
|
|
// https://docs.swift.org/swift-book
|
|
|
|
import Crypto
|
|
|
|
import Foundation
|
|
|
|
public func serializeV1(msg: MessageP) -> Data {
|
|
|
|
let MESSAGE_CAPACITY: Int = countBytes(msg: msg)
|
|
|
|
var serializedData: Data = Data(count: MESSAGE_CAPACITY)
|
|
|
|
// Serialize Header
|
|
|
|
// UGLY: extrapolate in functions
|
|
serializedData[0] = msg.version
|
|
serializedData[1] = msg.messageType.rawValue
|
|
serializedData[2] = msg.devType.rawValue
|
|
serializedData[3] = msg.RESERVED
|
|
serializedData[4...7] = msg.signType.rawValue.data
|
|
// First 8 bytes
|
|
|
|
serializedData[8...15] = msg.timestamp.timeIntervalSince1970.data
|
|
// 8 Bytes
|
|
|
|
serializedData[16...31] = msg.devID.data
|
|
// 16 bytes
|
|
|
|
serializedData[32...39] = msg.location.x.data
|
|
// 8 Bytes
|
|
|
|
serializedData[40...47] = msg.location.y.data
|
|
// 8 Bytes
|
|
|
|
serializedData[48...55] = msg.location.z.data
|
|
// 8 Bytes
|
|
|
|
var index = 56
|
|
|
|
for field in msg.fields {
|
|
|
|
serializedData[index..<(index + 4)] = UInt32(field.key.count).data
|
|
serializedData[(index + 4)..<(index + 8)] = UInt32(field.value.count).data
|
|
|
|
index += 8
|
|
|
|
serializedData[index..<(index + field.key.count)] = Data(field.key)
|
|
|
|
index += field.key.count
|
|
|
|
serializedData[index..<(index + field.value.count)] = Data(field.value)
|
|
|
|
index += field.value.count
|
|
}
|
|
|
|
let paddingBytes = (8 - (index % 8)) % 8
|
|
|
|
serializedData[index..<(index + paddingBytes)] = Data(count: paddingBytes)
|
|
index += paddingBytes
|
|
|
|
// Add STOP FIELDS
|
|
serializedData[index..<(index + 8)] = UInt64(0).data
|
|
|
|
return serializedData
|
|
}
|
|
|
|
public func signMessage(msgData: Data, signType: SignType, key: P256.Signing.PrivateKey) throws
|
|
-> [UInt8]
|
|
{
|
|
|
|
// UGLY We are hypothesisying that signType is P521
|
|
switch signType {
|
|
/* case .P521:
|
|
|
|
return try signP521(object: msgData, key: key).map { value in
|
|
return value
|
|
} */
|
|
case .P256:
|
|
return try signP256(object: msgData, key: key).map { value in
|
|
return value
|
|
}
|
|
|
|
default:
|
|
throw CommonError.SIGNATURE_NOT_SUPPORTED
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public func verifyMessageSignature(message: SignedMessage, key: P256.Signing.PublicKey) throws
|
|
-> Bool
|
|
{
|
|
// UGLY Assuming P521 Signature
|
|
|
|
let msgData = serializeV1(msg: message)
|
|
return try verifySignatureP256(signature: Data(message.signature), object: msgData, key: key)
|
|
|
|
}
|
|
|
|
public func deserializeV1(serializedData: Data) throws -> SignedMessage {
|
|
|
|
// Serialize Header
|
|
|
|
// UGLY: extrapolate in functions
|
|
let version: UInt8 = serializedData[0]
|
|
let messageType: MessageType = MessageType(rawValue: serializedData[1])!
|
|
let devType: DeviceType = DeviceType(rawValue: serializedData[2])!
|
|
let RESERVED: UInt8 = serializedData[3]
|
|
let signType: SignType = SignType(rawValue: serializedData[4...7].uint32)!
|
|
// First 8 bytes
|
|
|
|
let timestamp = serializedData[8...15].double
|
|
// 8 Bytes
|
|
|
|
let devID = serializedData[16...31].uint128
|
|
// 16 bytes
|
|
|
|
let locationX = serializedData[32...39].uint64
|
|
// 8 Bytes
|
|
|
|
let locationY = serializedData[40...47].uint64
|
|
// 8 Bytes
|
|
|
|
let locationZ = serializedData[48...55].uint64
|
|
// 8 Bytes
|
|
|
|
var index = 56
|
|
|
|
// Deserializing Fields
|
|
var MORE_FIELDS = true
|
|
var fields: [Field] = []
|
|
|
|
while MORE_FIELDS {
|
|
|
|
let nextChunk = serializedData[index..<(index + 8)]
|
|
|
|
let a = nextChunk.map { value in
|
|
return value
|
|
}
|
|
|
|
if nextChunk.uint64 == 0 {
|
|
MORE_FIELDS = false
|
|
continue
|
|
}
|
|
|
|
let fieldKeyCount = serializedData[index..<(index + 4)].uint32
|
|
let fieldValueCount = serializedData[(index + 4)..<(index + 8)].uint32
|
|
|
|
index += 8
|
|
|
|
let key = serializedData[index..<(index + Int(fieldKeyCount))].map { value in
|
|
return value
|
|
}
|
|
index += Int(fieldKeyCount)
|
|
let value = serializedData[index..<(index + Int(fieldValueCount))].map { value in
|
|
return value
|
|
}
|
|
index += Int(fieldValueCount)
|
|
|
|
fields.append(Field(key: key, value: value))
|
|
|
|
}
|
|
|
|
let paddingBytes = (8 - (index % 8)) % 8
|
|
|
|
// Skip padding bytes
|
|
index += paddingBytes + 8
|
|
|
|
let signature = serializedData[index..<serializedData.count].map { value in
|
|
return value
|
|
}
|
|
|
|
// We can't check for bytes a priori, unluckily
|
|
|
|
return SignedMessage(
|
|
version: version,
|
|
messageType: messageType,
|
|
devType: devType,
|
|
RESERVED: RESERVED,
|
|
signType: signType,
|
|
timestamp: Date(timeIntervalSince1970: timestamp),
|
|
devID: devID,
|
|
location: Location(x: locationX, y: locationY, z: locationZ),
|
|
fields: fields,
|
|
signature: signature
|
|
)
|
|
}
|
|
public func countBytes(msg: MessageP) -> Int {
|
|
|
|
///
|
|
/// Author: Christian Risi
|
|
///
|
|
/// This is computed as all the bits for the fixed fields
|
|
///
|
|
let INITIAL_CAPACITY_BYTES: Int = 56
|
|
let FIELD_HEADER_CAPACITY_BYTES: Int = 8
|
|
|
|
var fieldReveservedCapacity: Int = 0
|
|
|
|
for field in msg.fields {
|
|
fieldReveservedCapacity += FIELD_HEADER_CAPACITY_BYTES + field.key.count + field.value.count
|
|
}
|
|
|
|
fieldReveservedCapacity += (8 - (fieldReveservedCapacity % 8)) % 8 + 8
|
|
|
|
return INITIAL_CAPACITY_BYTES + fieldReveservedCapacity
|
|
|
|
}
|