Bog Files

Overview

Niagara provides a standard XML format to store a tree of BValues. This XML format is called “BOG” for Baja Object Graph. The bog format is designed for the following criteria:

Bog files are typically given a “.bog” extension. Bog files designed for use as palletes use the “.palette” extension, and though they use the same format as “.bog” files, they may not use reversible encodings for BPassword values (see discussion of encoding and key source below).

Bog files can be flat XML files or stored inside zip files. If zipped, then the zip file contains a single entry called “file.xml” with the XML document. You can use Workbench to copy any BValue to a directory on your file system to easily generate a bog file.

Compatibility

Bog files created by Niagara AX systems use an encoding for passwords that is incompatible with Niagara 4 API and tools. For best results, any AX files should first be converted using the Niagara 4 migration tool.

Password Encoding and Encryption Keys

In Niagara 4 bog files, all BPassword values are encoded using some form of strong encryption. The encoding that’s used for a particular value depends on whether it must be possible to retrieve the original value from the file (a reversible encoding is used), or whether it’s enough just to be able to verify that a given value matches the original (a non-reversible encoding is used). Niagara typically uses reversible encodings for password values only when the system needs to send the value to another system for authentication (an email server, another Niagara station, etc.). Most password values, like those in a station’s user service, use a non-reversible encoding.

Non-reversible encoding is done in the same way everywhere it’s used, so it’s not necessary for bog files to have any special information telling systems how to decode. However, for password values that use reversible encoding, the secret encryption key that’s used is never stored in the file itself, and the file has to contain information telling the decoder how to get the key. A key source attribute describes this, and the choice has important implications for the security and portability of the file. Possible values:

Key SourceDescriptionFile Security and Portability
noneThe file does not and cannot have any reversibly-encoded password values.Best portability; consumers don’t have to know a passphrase or have access to a particular system’s “key ring”.
keyringReversibly-encoded password values are encrypted using a randomly-generated secret key stored in a “key ring” on the system where the file resides.Best security, but values are not readable on other systems.
externalReversibly-encoded password values are encrypted using a secret key derived from a human-provided passphrase, which may be a controller’s “system passphrase”, may be assigned by Workbench user working with files offline, etc. Portable. Correct passphrase needs to be supplied when reading encoded password values.

Developers should note that the ‘keyring’ key source’s limited portability can cause unexpected problems for users when they copy files directly without using Niagara tools. Niagara software:

Software developers should choose key source with this in mind.

API

In general the best way to read and write bog files is via the standard APIs. The ValueDocEncoder class is used to write BValues to an output stream using bog format. You can use the ValueDocEncoder.setZipped() method to compress the bog file to to a zip file with one entry called “file.xml”. In general you should use the encodeDocument() method to generate a complete bog document. However you can also use ValueDocEncoder to stream multiple BValues to an XML document using encode().

The ValueDocDecoder class is used to decode a bog document back into BValue instances. When decoding a bog file, the decoder will automatically detect if the file is zipped or not. General usage is to use decodeDocument() in conjunction with ValueDocEncoder.encodeDocument() for decoding the entire XML document as a BValue. However ValueDocDecoder can also be used to decode BValues mixed with other XML data using ValueDocDecoder.decode() and the standard XParser APIs.

ValueDocEncoder.marshal() and ValueDocDecoder.unmarshal() are convenience methods to encode and decode a BValue to and from a String.

When running in a station, creating a bog file that will be read (only) on the same station, and possibly have password values, you need to pass the ValueDocEncoder a PasswordEncodingContext that instructs the encoder to use the ‘keyring’ key source.

Encoding examples:


BComponent componentToEncode;
OutputStream bogFileOut;
Context cx;
BPassword filePassphrase;
ValueDocEncoder encoder;

// In this example, componentToEncode has no reversible passwords. Because we don't pass a special
// PasswordEncodingContext to the constructor and we don't provide a passphrase, 'none' key source is used.
encoder = new ValueDocEncoder(bogFileOut, cx);
encoder.setZipped(true);
encoder.encode(componentToEncode);

// In this example, we encrypt passwords using a key from the station's keyring. updateForKeyring isn't appropriate
// for code running anywhere except in a station VM, and isn't appropriate for writing files that need to be read
// by code not running on the same station.
encoder = new ValueDocEncoder(bogFileOut, PasswordEncodingContext.updateForKeyring(cx));
encoder.setZipped(true);
encoder.encode(componentToEncode);

// In this example, we encrypt passwords using a key generated from a given file passphrase.
encoder = new ValueDocEncoder(bogFileOut, cx);
encoder.setPassPhrase(Optional.of(filePassphrase));
encoder.setZipped(true);
encoder.encode(componentToEncode);

Decoding examples:


BComponent decodedComponent;
InputStream bogFileIn;
Context cx;
BPassword filePassphrase;
ValueDocDecoder decoder;

// This example will work with a bog file that has 'none' encoding, or with a bog file written using 'keyring' by the
// this VM's station.
decoder = new ValueDocDecoder(bogFileIn, cx);
decodedComponent = decoder.decodeDocument();

// This example will work with a bog file that has 'external' encoding
decoder = new ValueDocDecoder(bogFileIn, cx);
decoder.setPassPhrase(Optional.of(filePassphrase));
decodedComponent = decoder.decodeDocument();

Syntax

The bog format conforms to a very simple syntax. The root element of a bog document must always be “bajaObjectGraph”. Root element attributes:

AttributeDescription
versionBog schema version. Value is 1.0 for Niagara AX, 4.0 for Niagara 4
reversibleEncodingKeySourceNew to Niagara 4. Specifies where the encryption key used for password values should come from. Possible values are ‘none’(default), ‘keyring’ and ‘external’.
reversibleEncodingValidatorRequired for Niagara 4 files that use ‘external’ key source.
reversibleEncodingSaltRequired for Niagara 4 files that use ‘external’ key source.
reversibleEncodingIterationCountRequired for Niagara 4 files that use ‘external’ key source.

Under the root there are only three element types, which map to the three slot types:

ElementDescription
pContains information about a property slot
aContains information about a frozen action slot
tContains information about a frozen topic slot

All other information is encoded into XML attributes:

AttributeDescription
nThis required attribute stores the slot name.
mDefines a module symbol using the format “symbol=name”. Once defined, the symbol is used in subsequent t attributes.
tSpecifies the type of a property using the format “symbol:typename”, where symbol must map to a module declaration earlier in the document. If unspecified, then the type of the property’s default value is used.
fSpecifies slot flags using the format defined by Flags.encodeToString()
hThis attribute specifies the handle of BComponents
xSpecifies the slot facets using format defined by BFacets.encodeToString()
vStores the string encoding of BSimples.

In practice the XML will be a series of nested p elements which map to the structure of the BComplex tree. The leaves of tree will be the BSimples stored in the v attribute.

Example

A short example of a kitControl:SineWave linked to a kitControl:Add component. The Add component has a dynamic slot called description where value is “hello”, operator flag is set, and facets are defined with multiLine=true.

<?xml version="1.0" encoding="UTF-8"?>
<bajaObjectGraph version="4.0" reversibleEncodingKeySource="none">
  <p m="b=baja" t="b:UnrestrictedFolder">
    <p n="SineWave" h="1" m="kitControl=kitControl" t="kitControl:SineWave">
      <p n="amplitude" v="35"/>
    </p>
  <p n="Add" h="3" t="kitControl:Add">
  </p>
  <p n="Link" t="b:Link">
    <p n="sourceOrd" v="h:1"/>
    <p n="sourceSlotName" v="out"/>
    <p n="targetSlotName" v="inA"/>
  </p>
  <p n="description" f="o" x="multiLine=b:true" t="b:String" v="hello"/>
  </p>
</bajaObjectGraph>