57 lines
1.6 KiB
Go
57 lines
1.6 KiB
Go
package radio
|
|
|
|
import (
|
|
"crypto/ed25519"
|
|
"crypto/sha512"
|
|
"errors"
|
|
|
|
"github.com/fxamacker/cbor/v2"
|
|
)
|
|
|
|
type packet interface {
|
|
PacketHeartbeatReq | PacketExchangeReq | PacketExchangeRes
|
|
}
|
|
|
|
// Converts a packet into a byte array ready for transmission.
|
|
func Marshal[P packet](p *P, signingKey ed25519.PrivateKey) ([]byte, error) {
|
|
// Get the CBOR representation of the data.
|
|
dataBytes, err := cbor.Marshal(p)
|
|
if err != nil {
|
|
return dataBytes, err
|
|
}
|
|
|
|
// Calculate the checksum of the data for the signature.
|
|
checksum := sha512.Sum384(dataBytes)
|
|
|
|
// Create the signature for verification purposes.
|
|
signatureBytes := ed25519.Sign(signingKey, checksum[:])
|
|
|
|
// Return a byte array of the signature followed by the data.
|
|
return append(signatureBytes, dataBytes...), nil
|
|
}
|
|
|
|
// Converts a byte array into a packet so that it can be processed.
|
|
func Unmarshal[P packet](p *P, verificationKey ed25519.PublicKey, data []byte) error {
|
|
// Make sure the data is correctly formatted (at least 64 bytes)
|
|
if len(data) < 64 {
|
|
return errors.New("provided data was too short")
|
|
}
|
|
|
|
// Split the byte array into the signature and data parts.
|
|
signatureBytes := data[0:64]
|
|
dataBytes := data[64:]
|
|
|
|
// Calculate the checksum of the data for verification.
|
|
checksum := sha512.Sum384(dataBytes)
|
|
|
|
// Verify the signature.
|
|
verified := ed25519.Verify(verificationKey, checksum[:], signatureBytes)
|
|
if !verified {
|
|
return errors.New("data failed signature verification")
|
|
}
|
|
|
|
// If verification was successful, unmarshal the data into the
|
|
// current struct and return whether this was successful.
|
|
return cbor.Unmarshal(dataBytes, p)
|
|
}
|