I can't help with reading HeaderAuth since it depends on the algorithm.
For other fields I wouldn't keep their lenghts and count in the final structure since they are encoded in the actual slice lenght.
I'd make a type to read variable fields from a reader:
type ByteField []byte
func (bf *ByteField) ReadFrom(r io.Reader) error {
var length uint16
err := binary.Read(r, binary.LittleEndian, &length)
if err != nil {
return err
}
*bf = make([]byte, length)
_, err = io.ReadFull(r, *bf)
if err != nil {
return err
}
return nil
}
How to use it. Let's consider encrypted keys:
type EncryptedDataKey struct {
KeyProviderID ByteField
KeyProviderInfo ByteField
EncryptedKey ByteField
}
func (k *EncryptedDataKey) ReadFrom(r io.Reader) error {
if err := k.KeyProviderID.ReadFrom(r); err != nil {
return err
}
if err := k.KeyProviderInfo.ReadFrom(r); err != nil {
return err
}
if err := k.EncryptedKey.ReadFrom(r); err != nil {
return err
}
return nil
}
With ByteField it is easy to decode AAD
type AAD map[string][]byte
func (a *AAD) ReadFrom(r io.Reader) error {
var key ByteField
var value ByteField
var err error
for {
if err = key.ReadFrom(r); err != nil {
if err == io.EOF {
return nil
} else {
return err
}
}
if err = value.ReadFrom(r); err != nil {
return err
}
(*a)[string(key)] = []byte(value)
}
}
Method AAD.ReadFrom reads until the end of buffer, that's why here I check that EOF happened while reading a key. I treat it as no more k-v pairs in the input stream.
Now we are equipped to read the whole header:
type EncryptionSDK_Header_v1 struct {
Version byte
Type byte
AlgorithmID uint16
MessageID [16]byte
AAD AAD
DataKeys []EncryptedDataKey
ContentType byte
Reserved [4]byte
IVLength byte //Maybe a uint8?
FrameLength uint32 //A little-endian uint32
HeaderAuth []byte
}
func (h *EncryptionSDK_Header_v1) ReadFrom(r io.Reader) error {
var err error
if err = binary.Read(r, binary.LittleEndian, &h.Version); err != nil {
return err
}
if err = binary.Read(r, binary.LittleEndian, &h.Type); err != nil {
return err
}
if err = binary.Read(r, binary.LittleEndian, &h.AlgorithmID); err != nil {
return err
}
if _, err = io.ReadFull(r, h.MessageID[:]); err != nil {
return err
}
var aadLen uint16
if err = binary.Read(r, binary.LittleEndian, &aadLen); err != nil {
return err
}
h.AAD = make(AAD)
if aadLen > 0 {
aadBuf := make([]byte, aadLen)
if _, err = io.ReadFull(r, aadBuf); err != nil {
return err
}
aadReader := bytes.NewReader(aadBuf)
if err = h.AAD.ReadFrom(aadReader); err != nil {
return err
}
}
var keyCount uint16
if err = binary.Read(r, binary.LittleEndian, keyCount); err != nil {
return err
}
h.DataKeys = make([]EncryptedDataKey, keyCount)
for i := uint16(0); i < keyCount; i++ {
if err = h.DataKeys[i].ReadFrom(r); err != nil {
return err
}
}
if err = binary.Read(r, binary.LittleEndian, &h.ContentType); err != nil {
return err
}
if _, err = io.ReadFull(r, h.Reserved[:]); err != nil {
return err
}
if err = binary.Read(r, binary.LittleEndian, &h.IVLength); err != nil {
return err
}
if err = binary.Read(r, binary.LittleEndian, &h.FrameLength); err != nil {
return err
}
// Stopped at Header Authentication
return nil
}