bacc

package module
v0.0.0-...-2d1e0fa Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 3, 2018 License: Apache-2.0 Imports: 32 Imported by: 1

README

= BACC - Binary Archive Compression Cabinet Format
Christoph Engelbert <https://github.com/noctarius[@noctarius2k]>
Relations.One Digital GmbH
// Settings:
:compat-mode!:
:idseperator: -
// Aliases:
:project-name: BACC - Binary Archive Compression Cabinet Format
:project-handle: binary-archive-compression-cabinet
:toc:

BACC or the Binary Archive Compression Cabinet is the main compression format used in the Zodiac embedded platform. It is influenced by the ZIP file format but adds important elements such as digital signature verification and different compression levels per item inside the data stream.

The file format is also designed for fast opening by having a full directory structure at the beginning of the file, following the initial header, and storing actual archive content after the lookup dictionary.

Internally, BACC uses either 32 bit or 64 bit addressing and location pointers based on a tag in the file's header. If either is selected all (except the signature pointer) internal addressing is using the same scheme.

Furthermore items inside the BACC file can be encrypted. The selected for encryption can done by file and keys are referenced using a fingerprint of the key. Possible encryption algorithms are AES-256 or Twofish-256 for symmetric, as well as RSA-2048 for asymmetric encryption.

Same as encryption, the digital signature feature can be set by item. In addition the overall BACC file itself is always digitally signed to prevent changes after its creation. The hash function in use is SHA2-512 with an RSA-2048 signature for verification. The signature verification certificate is again selected based on the fingerprint of the certificate.

All certificate and symmetric key fingerprints are calculated using and stored as SHA2-256.

Numbers are always encoded in BigEndian byte order.

== BACC File Header Definition

|===
| Value | Size | Offset | Description

| Magic header
| 2 bytes
| 0x00
| The BACC file magic header, always *0xBACC*.

| File format version
| 1 byte
| 0x02
| The version of the BACC file, normally always *0x01*.

| Bitflags
| 1 byte
| 0x03
| General purpose bitflag field, see the <<BACC General Bitfield>> section.

| Quick checksum
| 32 bytes
| 0x04
| SHA2-256 checksum, only for verification of successful download. Contains all bytes, except the attached file signature (at the end of the file).

| Header size
| 4 bytes
| 0x24
| An unsigned 32 bit size value, defining the overall size of the file's header.

| Signature offset
| 8 bytes
| 0x28
| An unsigned 64 bit pointer to the begin of the file's signature. The signature is always SHA2-512 with RSA-2048. Furthermore the signature is always attached at the very end of the file, to sign files after all content is written.

| Signature method
| 1 byte
| 0x30
| The signature / verification method being used to sign this archive.

  *0x00*: unsigned +
  *0x01*: SHA2-512 + RSA-2048 (signed with private) +
  *0x02*: SHA2-512 + RSA-2048 (signed with public)

| Certificate fingerprint
| 32 bytes
| 0x31
| Unique ID (e.g. SHA2-256 fingerprint) of the private-public keypair. In difference from certificate fingerprints for files, this fingerprint is always available, as production archives are expected to be signed.

| Metadata section
| variable
| 0x51
| Contains additional metadata records to specify application specific data. See the <<Metadata Record Format>> section.
|===

Following the file header the BACC file contains the central directory which contains all folders and files stored inside the archive. See more information in the <<Central Directory>> section.

== BACC General Bitfield

This bitfield encodes some of the general configuration properties. The bitfield is encoded left to right, therefore bit 0, is to the left.


|===
| Value | Size | Offset | Description

| Addressing scheme
| 1 bit
| 0
| The internally used addressing scheme.

  *0x0*: 32bit addressing +
  *0x1*: 64bit addressing
|===

Later versions of the BACC format might define additional bit field values.

== Metadata Record Format

The metadata size is represented as a 3 byte unsigned integer to prevent exceeding the maximum size of a archive header which is represented as 32 bit no matter of the internal addressing scheme.

|===
| Value | Size | Offset | Description

| Metatable size
| 3 bytes
| 0x00
| Unsigned 3 bytes integer containing the bytesize of the following CBOR metatable. If the value is 0, no metadata is available.

| Metatable
| variable
| 0x03
| The CBOR encoded metatable. See information below
|===

The metadata is stored as a CBOR encoded table. However keys always need to be of type string to be considered a valid metadata entry. Implementations of the readers are considered to test this restriction before using the actual data.

== Central Directory

The central directory contains all folder and file headers of the archive. Each element either represents a folder, pointing to a folder  entry, or a file, pointing to the file's content.

The central directory is always positioned directly following the BACC file's header.

The central directory therefore consists of 2 types of entries, folder entry or file entry. The top most entry is always a folder entry, also called root entry.

The pointer size of entries depends on the configured address size from the <<BACC General Bitfield>> section and is depending on that either 4 or 8 bytes. Therefore the following tables use _Pointer_ as the size value to be of either value.

=== Folder Entry

An Folder Entry header is limited to a maximum size of 4 bytes (unsigned 32 bits).


|===
| Value | Size | Offset | Description

| Name
| variable
| 0x00
| An UTF-8 encoded, null terminated, variable-length string, defining the name of the folder entry. Even though UTF-8 naming is possible, it is highly encouraged to use ASCII characters only.

| Timestamp
| 8 bytes
| 0x00 + len(Name)
| An unsigned 64 bit timestamp using nanos, starting from 1970-01-01 00:00:00.000. The timestamp will be set for access and modification time on extraction.

| Entry type
| 1 byte
| 0x08 + len(Name)
| Type of the entry, for folders this is always *0x00*.

| Entry header size
| 4 bytes
| 0x09 + len(Name)
| An unsigned 32 bit size value, defining the overall size of this folder entry header.

| Entry count
| 4 bytes
| 0x0D + len(Name)
| An unsigned 32 bit value defining the number of entries inside the folder. All entries directly follow up this folder's header. After all entries are defined, the next element will be the same level as this entry again.

Every defined child entry may be of type folder entry or file entry.

| Metadata section
| variable
| 0x11 + len(Name)
| Contains additional metadata records to specify application specific data. See the <<Metadata Record Format>> section.
|===


=== File Entry

The following table doesn't contain offset definitions as offsets depend on the addressing scheme chosen, as well as on encryption and signature of every single entry. Therefore the offsets change based on the given entry's configuration.

|===
| Value | Size | Description

| Name
| variable
| An UTF-8 encoded, null terminated, variable-length string, defining the name of the folder entry. Even though UTF-8 naming is possible, it is highly encouraged to use ASCII characters only.

| Timestamp
| 8 bytes
| An unsigned 64 bit timestamp using nanos, starting from 1970-01-01 00:00:00.000. The timestamp will be set for access and modification time on extraction.

| Entry type
| 1 byte
| Type of the entry, for files this is always *0x01*.

| Entry header size
| 4 bytes
| An unsigned 32 bit size value, defining the overall size of this file entry header.

| Quick checksum
| 32 bytes
| SHA2-256 checksum of the file's unencrypted and uncompressed (original) content

| Compressed size
| _Pointer_
| The compressed size of the file's content.

| Uncompressed size
| _Pointer_
| The uncompressed size of the file's content.

| Content offset
| _Pointer_
| The pointer to the actual (maybe encrypted and/or compressed) file content in absolute bytes from the beginning of the file.

| Compression method
| 1 byte
| The compression method being used to compress this entry's content.

  *0x00*: uncompressed +
  *0x01*: gzip compression0x02: bzip2 compression

| Encryption method
| 1 byte
| The encryption method being used to encrypt this entry's content.

  If an encryption with initialization vector (IV) is used (AES, Twofish), the first bytes of the actual files content is the IV. The IV length is equal to the blocksize of the encryption.

  *0x00*: unencrypted +
  *0x01*: AES-256 +
  *0x02*: Twofish-256 +
  *0x03*: RSA-2048 (encrypted with private) +
  *0x04*: RSA-2048 (encrypted with public)

| Key fingerprint
| 32 bytes
| SHA2-256 fingerprint of the symmetric key or the private-public keypair used to encrypt this file. Only available if Encryption Method is not *0x00* (unencrypted).

| Signature method
| 1 byte
| The signature / verification method being used to sign this entry's content.

  *0x00*: unsigned +
  *0x01*: SHA2-512 + RSA-2048 (signed with private) +
  *0x02*: SHA2-512 + RSA-2048 (signed with public)

| Certificate fingerprint
| 32 bytes
| SHA2-256 fingerprint of the private-public keypair used to sign this file. Only available if Signature Method is not *0x00* (unsigned).

| Signature
| 256 bytes
| Signature of the file's content and the file's header, except the 256 signature bytes which are all zeroed out. Only available if Signature Method is not *0x00* (unsigned).

| Metadata section
| variable
| Contains additional metadata records to specify application specific data. See the <<Metadata Record Format>> section.

|===

If an entry is compressed and encrypted, the content is compressed before it is encrypted.

Documentation

Index

Constants

View Source
const (
	BaseBytesizeArchiveHeader = uint32(2 + 1 + 1 + 32 + 4 + 8 + 1 + 32 + 3)
	BaseBytesizeFolderHeader  = uint32(8 + 1 + 4 + 4 + 3)
	BaseBytesizeFile32Header  = uint32(8 + 1 + 4 + 32 + 4 + 4 + 4 + 1 + 1 + 1 + 3)
	BaseBytesizeFile64Header  = uint32(8 + 1 + 4 + 32 + 8 + 8 + 8 + 1 + 1 + 1 + 3)
)
View Source
const MagicHeader uint16 = 0xBACC

Variables

This section is empty.

Functions

func NewBaccFilesystem

func NewBaccFilesystem(archivePath string, keyManger KeyManager) (afero.Fs, error)

Types

type AddressingMode

type AddressingMode uint8
const (
	ADDRESSING_32BIT AddressingMode = 0x0
	ADDRESSING_64BIT AddressingMode = 0x1
)

func (AddressingMode) String

func (am AddressingMode) String() string

type Archive

type Archive interface {
	io.Closer
	Header() ArchiveHeader
	RootEntry() ArchiveFolder
	ListLookupDirectory()
	Verify(allowUnsigned bool) (bool, error)
}

type ArchiveEntry

type ArchiveEntry interface {
	Name() string
	Timestamp() uint64
	HeaderSize() uint32
	Metadata() map[string]interface{}
	EntryType() EntryType
}

type ArchiveFile

type ArchiveFile interface {
	Name() string
	Timestamp() uint64
	HeaderSize() uint32
	Metadata() map[string]interface{}
	EntryType() EntryType
	CompressedSize() uint64
	UncompressedSize() uint64
	ContentOffset() uint64
	CompressionMethod() CompressionMethod
	EncryptionMethod() EncryptionMethod
	SignatureMethod() SignatureMethod
	Verify() (bool, error)
	Extract(writer io.Writer, progress ProgressCallback, callback CompletionCallback) error
	NewReader() EntryReader
}

type ArchiveFolder

type ArchiveFolder interface {
	Name() string
	Timestamp() uint64
	HeaderSize() uint32
	Metadata() map[string]interface{}
	EntryType() EntryType
	EntryCount() uint32
	Entries() []ArchiveEntry
}

type ArchiveHeader

type ArchiveHeader interface {
	MagicHeader() uint16
	Version() uint8
	Bitflag() uint8
	Checksum() [32]byte
	HeaderSize() uint32
	SignatureOffset() uint64
	SignatureMethod() SignatureMethod
	CertificateFingerprint() string
	Metadata() map[string]interface{}
	AddressingMode() AddressingMode
	Verify(allowUnsigned bool) (bool, error)
}

type CompletionCallback

type CompletionCallback func(read uint64, processed uint64, result bool, err error)

type CompressionMethod

type CompressionMethod uint8
const (
	COMPMET_UNCOMPRESSED CompressionMethod = 0x00
	COMPMET_GZIP         CompressionMethod = 0x01
	COMPMET_BZIP2        CompressionMethod = 0x02
)

func (CompressionMethod) String

func (cm CompressionMethod) String() string

type EncryptionMethod

type EncryptionMethod uint8
const (
	ENCMET_UNENCRYPTED EncryptionMethod = 0x00
	ENCMET_AES256      EncryptionMethod = 0x01
	ENCMET_TWOFISH256  EncryptionMethod = 0x02
	ENCMET_RSA_PRIVATE EncryptionMethod = 0x03
	ENCMET_RSA_PUBLIC  EncryptionMethod = 0x04
)

func (EncryptionMethod) String

func (em EncryptionMethod) String() string

type EntryReader

type EntryReader interface {
	io.Seeker
	io.Reader
	io.ReaderAt
}

type EntryType

type EntryType uint8
const (
	ENTRY_TYPE_FOLDER EntryType = 0x00
	ENTRY_TYPE_FILE   EntryType = 0x01
)

func (EntryType) String

func (et EntryType) String() string

type JsonArchive

type JsonArchive struct {
	// contains filtered or unexported fields
}

type JsonEntry

type JsonEntry struct {
	// contains filtered or unexported fields
}

func (*JsonEntry) String

func (e *JsonEntry) String() string

type JsonParser

type JsonParser struct {
	// contains filtered or unexported fields
}

func NewJsonParser

func NewJsonParser(verbose bool) *JsonParser

func (*JsonParser) ReadJsonDescriptor

func (jp *JsonParser) ReadJsonDescriptor(jsonDescriptor string) (*JsonArchive, error)

type KeyManager

type KeyManager interface {
	GetKey(fingerprint string) ([]byte, error)
}

type Packager

type Packager struct {
	// contains filtered or unexported fields
}

func NewPackager

func NewPackager(keyManager KeyManager, verbose bool) *Packager

func (*Packager) WriteArchive

func (p *Packager) WriteArchive(archivePath string, archiveDefinition *JsonArchive, force64bit bool) error

type ProgressCallback

type ProgressCallback func(total uint64, processed uint64, progress float32)

type Reader

type Reader struct {
	// contains filtered or unexported fields
}

func NewReader

func NewReader(keyManager KeyManager) *Reader

func (*Reader) ReadArchive

func (r *Reader) ReadArchive(archivePath string) (Archive, error)

type SignatureMethod

type SignatureMethod uint8
const (
	SIGMET_UNSINGED    SignatureMethod = 0x00
	SIGMET_RSA_PRIVATE SignatureMethod = 0x01
)

func (SignatureMethod) String

func (sm SignatureMethod) String() string

type Signer

type Signer interface {
	Sign(reader io.Reader, size int64, progress ProgressCallback) ([]byte, error)
}

func LoadKeyForSigning

func LoadKeyForSigning(keyPath string) (Signer, error)

func ParsePrivateKey

func ParsePrivateKey(data []byte) (Signer, error)

type Verifier

type Verifier interface {
	Verify(reader io.Reader, size int64, signature []byte, progress ProgressCallback) error
}

func LoadKeyForVerifying

func LoadKeyForVerifying(keyPath string) (Verifier, error)

func ParsePublicKey

func ParsePublicKey(data []byte) (Verifier, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL