Christian Risi ad4fd555f1 V0.6.0 Arroyo Toad
Added the capability to sign and verify P521 Signature
2024-12-06 11:31:07 +00:00

214 lines
5.6 KiB
Swift

// The Swift Programming Language
// https://docs.swift.org/swift-book
import Foundation
import Crypto
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.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: P521.Signing.PrivateKey) throws -> [UInt8] {
let signatureBytes = try signatureBytes(signature: signType)
// UGLY We are hypothesisying that signType is P521
let signature = try signP521(object: msgData, key: key).map { value in
return value
}
return signature
}
public func verifyMessageSignature(message: SignedMessage, key: P521.Signing.PublicKey) throws -> Bool {
// UGLY Assuming P521 Signature
let msgData = serializeV1(msg: message)
return try verifySignatureP521(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 signBytes = try signatureBytes(signature: signType)
let timestamp = serializedData[8...15].timestamp
// 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
}
// Sanity check signature with signatureType
if signature.count != signBytes {
throw DeserializationError.UNMATCHING_SIGNATURE_TYPE
}
return SignedMessage(
version: version,
messageType: messageType,
devType: devType,
RESERVED: RESERVED,
signType: signType,
timestamp: 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
}
public func signatureBytes(signature: SignType) throws -> Int {
switch signature {
case .P521:
return 132
default:
throw CommonError.SIGNATURE_NOT_SUPPORTED
}
}