Encrypted SEB Config File Format
Safe Exam Browser’s configuration files with the file name extension .seb containing exam configurations have to be encrypted because:
- examinees should not be able to alter the exam configuration;
- some details of an exam configuration should be kept secret to hinder manipulating configuration of exams.
It has to be possible to implement the encryption on various platforms, as clients running on Windows, Mac OS X and in future iOS, Linux-, Android and a SEB server application should be able to open and save .seb files. We prioritize an encryption which is as secure as possible, following current cryptography standards.
The settings itself are defined as a XML structure with key/value pairs. Key names should be self-explaining (avoid abbreviations, key name string length is irrelevant).
It has to be possible to use the same .seb files platform-independently for configuring all versions of SEB clients. As many key/value pairs as possible should have the same function on all platforms. If this isn’t possible because of the nature of a settings option (for example if that feature isn’t available on some platform or doesn’t make sense there) a compatible way of configuring clients must be found. For example there can be a general meta key for enabling/disabling a specific functionality and individual detail keys per platform for the specific configuration details.
There are two encryption/decryption methods:
- When opening a .seb file, the password used to encrypt this file needs to be entered. This method separates encrypted data (cypher text) and key (secret) very well, as long as the exam administrator chooses a good password and it is kept secret just before the exam starts. Therefore this method is ideal on not centrally managed student computers.
- For encrypting .seb files a cryptographic key (combined with a X.509 certificate) is used, which will be deployed to the exam client computers before the exams and stored securely in the Windows Certificate Store or the OS X Keychain. On centrally managed computers where users/examines don’t have administrator access, the secret (key) is separated quite well from the cipher text.
At the same time this method doesn’t use a general key, which would be stored inside the SEB application code and therefore could be extracted, made public and would affect the whole installed base of SEB worldwide. Instead, each institution using SEB can generate their own certificates/keys and replace them whenever they like.
Encryption with certificate/key can be combined with password encryption, for example for additional security for particular exams.
Basic file structure with 4 char prefix
A .seb file is actually a gzip compressed archive, but with the file extension .seb. This helps some web browsers to recognize that they should download a .seb file instead of displaying it as text in the browser (which would lead to arbitrary characters, as the .seb file is encrypted and in a binary format). Because a web server usually won’t know the .seb file type, it will deliver a .seb file with the standard MIME type html/text. By using a gzip wrapper around the binary encrypted configuration data, most browsers will download the .seb file.
A gzip decompressed .seb file always begins with a 4 char prefix, which specifies the kind of the following data. The four chars correspond 4 bytes. In general, all text information in .seb files, means prefixes and the XML settings data (keys and values) are coded in Unicode UTF8. Encrypted data is in binary format. In the illustration below the .seb file length is n+1 bytes, the lower line shows the byte numbers (ranging from 0 to n).
| prefix | ... data ... |
| 0 - 3 | 4 - n |
Valid prefixes:
pkhs Public key hash, stands for encrypted data using a cryptographic identity, identified by a 20 bytes hash of the encrypting public key.
phsk Public key hash and symmetric key, stands for encryption with public/private asymmetric keys and symmetric key.
pswd Password, stands for encrypted data using a password.
plnd Plain data, stands for unencrypted, gzip compressed data, see below.
pwcc Password, configuring a client. This kind of .seb file is used for changing the local preferences which are used when the SEB application is started up directly (not by opening a .seb file). In the Mac OS X SEB client settings are written into the file ~/Library/Preferences/org.safeexambrowser.Safe-Exam-Browser.plist. The Windows version writes the settings to the file SebClientSettings.seb in the „AppData“ directory.
Since a .seb file can be encrypted with both a cryptographic identity and a password, there can be an outer block and an encapsulated inner block, both identified by their own prefixes. If the .seb file is encrypted by both methods, then the outer block is always a “pkhs” block, the inner is a “pswd” or a “pwcc” block. If a .seb file is only encrypted by an identity, there is a outer “pkhs” block and an inner “plnd” block (means the outer block is encrypted with an identity and the inner block is prefixed by “plnd” and its data is not encrypted). If a .seb file is solely encrypted by a password, there is only one “pswd” or a “pwcc” block (there is no outer/inner block).
The inner, plain (decrypted) data consists of an XML text file. To save space, this UTF8 formatted text file is compressed with the gzip algorithm. That means an encrypted .seb file uses the gzip compression twice: Once on the plain XML text data to reduce its size and a second time on the final, encrypted and prefixed data. To reduce the size of the configuration data effectively, the gzip compression must be applied on the plain text data, as the encrypted binary data has too much entropy and wouldn’t reduce size of the data well (or not at all).
Procedure to encrypt and save a .seb file
(This is done on Windows with the SEB configuration tool, on the Mac inside SEB in the preferences window’s “Exam” pane)
- The SEB configuration tool checks if at least a password or a cryptographic identity for encryption is selected. If none is selected, then it aborts saving the .seb file, requesting the user to enter/choose at least one of these security elements.
- If a password is entered, encrypt the gzip compressed XML settings data with that password and prefix it with “pswd” (store those four bytes in front of the encrypted data).
- If no password is entered, prefix the gzip compressed plain XML settings data with “plnd”.
- If a cryptographic identity is selected, encrypt the whole resulting data from step 2 or 3 (including the prefix!) with the public key. Store the prefix “pkhs”, store the 20 bytes public key hash value (see next chapter) and append the encrypted data to that.
- Compress with gzip and save the resulting (binary) data in the .seb file.
Procedure to load and decrypt a .seb file
(This happens in SEB Starter)
- Load the whole .seb file into memory. Decompress with gzip (ungzip). Check for the first four bytes prefix.
- If the prefix is not “pkhs”: Skip to step 4.
- If the prefix is “pkhs”: The 20 bytes public key hash following this prefix (see next chapter) is read and used to retrieve the identity to which the public key is belonging to from the certificate store or keychain. The private key belonging to this identity is retrieved and used to decrypt the encrypted data.
- Check for the prefix of the data resulting from step 2 or 3. If it is “plnd”, then strip the 4 bytes prefix, the remaining data is the XML settings data.
- If the prefix is “pswd”: Request the user to enter a password. Decrypt the data with this password. If decryption fails with a “wrong password” error, ask again for the password (max. 5 times, then abort).
- If decryption was successful, decompress with gzip (ungzip). The resulting data is the XML settings data.
Encryption with public/private key
In this scenario, RSA public-key cryptography is used to encrypt and decrypt the plain XML settings data or the XML settings data already encrypted by password (see chapter “basic file structure”). In detail, a X.509 certificate with an embedded public key is used to encrypt the exam settings and the associated private key is used to decrypt the settings in the SEB exam clients (the combination of such a certificate containing a public key together with the according private key is called cryptographic identity). This encryption/decryption scenario is a bit an unusual use of the asymmetric RSA cryptography (because the private key has to be deployed to all the exam clients), but it was chosen because it’s easy to deploy the cryptographic identity in form of PKCS #12 data in a password-protected *.p12 file (which can be renamed to .pfx as used by Windows) to all the exam clients. The private key is stored securely in the Certificate Store in Windows or the Keychain in Mac OS X, so this scenario is quite secure if examinees don’t have administrator rights on the (centrally managed) exam computers (means they cannot extract the key from the secure store). Currently SEB is not using the certificate to verify the identity of the originator of the exam settings; so self-signed identity certificates can be used. For better performance especially when decoding larger configuration files with SEB 2.2 we introduced a new version of the identity certificate encryption, which should preferably be used, latest when compatibility with SEB versions < 2.2. isn’t required anymore.
a) Encryption with public/private asymmetric keys and symmetric key
Available in SEB versions starting 2.2, default format when not selecting „Use old asymmetric-only encryption“ in the Config File settings pane.
.seb settings structure when using a cryptographic identity together with a symmetric key:
| “phsk” | public key hash | key length | encrypted key | ... encrypted data ... |
| 0 - 3 | 4 - 23 | 24 - 27 | 28 - (28+kl) | (29+kl) - n |
See above illustration where the parts of the settings structure are placed in the binary data (total length of the .seb file is n+1 bytes).
- 4 bytes prefix containing the string “phsk” (standing for „public key hash + symmetric key“)
- 20 bytes public key hash: In X.509 certificates, the hash of the public key can be used to identity both the certificate (with its embedded public key) and the associated private key. Therefore the SEB on an exam client computer checks if a cryptographic identity with the hash contained in the .seb file is stored in the Certificate Store or Keychain and uses its private key for decoding.
- 4 bytes integer value with the length of the encrypted symmetric key (named „kl“ above).
- kl bytes with the binary representation of the encrypted symmetric key.
- Encrypted settings
The encryption in this „phsk“ mode works generally as usual implementations of public/private key cryptography, where asymmetric keys are combined with a randomly generated symmetric key, as decryption with symmetric keys is much faster:
Encrypt:
- Generate a random symmetric key. In the current implementation, as standard AES 256 key is used (256 bits = 32 bytes).
- Encrypt the SEB config data with the generated symmetric key. For convenience, we are using the same encryption as for password encrypted setting files (based on RNCryptor, see section „ Encryption with password“). The binary key is converted to a base64 encoded string, which is used as the encryption password for the settings data.
- Encrypt the symmetric key with the given public key
- Put the data together (prefix, public key hash, encrypted symmetric key with preceding 32 bit integer value containing the length of the encrypted key, encrypted settings data), gzip compress resulting binary data.
Decrypt:
- 3.1.1.Decompress data, parse prefix and other components
- 3.1.2.Use public key hash to find matching private key from certificate store
- 3.1.3.Decrypt symmetric key using the private key
- 3.1.4.Use base64 encoded string representation of the decrypted symmetric key to decrypt the SEB config data.
b) Encryption with public/private key
Available in SEB versions < 2.2 and for compatibility also in SEB 2.2 and higher.
.seb settings structure when using a cryptographic identity:
| “pkhs” | public key hash | ... encrypted data ... |
| 0 - 3 | 4 - 23 | 24 - n |
Total length of the .seb file is n+1 bytes. After the 4 bytes prefix containing the string “pkhs”, a 20 bytes public key hash follows and after that the encrypted data. In X.509 certificates, the hash of the public key can be used to identity both the certificate (with its embedded public key) and the associated private key. Therefore the SEB on an exam client computer checks if a cryptographic identity with the hash contained in the .seb file is stored in the Certificate Store or Keychain and uses its private key to decode the settings.
In the Mac OS X version of SEB the system provided Common Security Services Manager (CSSM) APIs are used for encryption with public/private key. CSSM belongs to the cross platform, open source Common Data Security Architecture (CDSA), which “is a set of layered security services and cryptographic framework that provide an infrastructure for creating cross-platform, interoperable, security-enabled applications for client-server environments. CDSA covers all the essential components of security capability … with security services that provide facilities for cryptography, certificate management, trust policy management, and key recovery.” For more information see the official documentation at http://www.opengroup.org/security/cdsa.htm and http://pubs.opengroup.org/onlinepubs/9629299/toc.htm. Although other compatible security frameworks and higher-level APIs may also be used on other platforms, below the CDSA/CSSM API methods are listed which are used by SEB on OS X.
Encrypting
-
The exam administrator can choose the identity for encryption from a list of cryptographic identities. These have to meet the following conditions:
- They need to be complete identities; means there must be a certificate with embedded public key and an associated private key.
- In the CSSM_KEY structure of both keys, KeyHeader.AlgorithmId must be CSSM_ALGID_RSA (they have to be RSA keys)
- The public key’s (its KeyHeader.KeyClass is CSSM_KEYCLASS_PUBLIC_KEY) KeyHeader.KeyUsage property must have at least one of these 3 flags set: CSSM_KEYUSE_ENCRYPT, CSSM_KEYUSE_WRAP, CSSM_KEYUSE_ANY.
- The private key’s (its KeyHeader.KeyClass is CSSM_KEYCLASS_PRIVATE_KEY) KeyHeader.KeyUsage property must have at least one of these 3 flags set: CSSM_KEYUSE_DECRYPT, CSSM_KEYUSE_WRAP, CSSM_KEYUSE_ANY.
- They need to be complete identities; means there must be a certificate with embedded public key and an associated private key.
- Fetch certificate and its public key from the identity selected for encryption.
- Get CSSM_ACCESS_CREDENTIALS for operation CSSM_ACL_AUTHORIZATION_ENCRYPT with the selected public key.
- Get CSSM_CSP_HANDLE and CSSM_KEY for the selected public key.
- Call CSSM_CSP_CreateAsymmetricContext with algorithm ID = CSSM_ALGID_RSA and Padding = CSSM_PADDING_PKCS1. This creates the new context handle CSSM_CC_HANDLE.
- Call CSSM_EncryptData, the result is the encrypted data.
- Free the context with CSSM_DeleteContext.
Decrypting
- Using the public key hash find the according certificate -> identity -> private key in the certificate store/keychain on the exam client computers.
- Get CSSM_ACCESS_CREDENTIALS for operation CSSM_ACL_AUTHORIZATION_DECRYPT with the selected private key.
- Get CSSM_CSP_HANDLE and CSSM_KEY for the selected private key.
- Call CSSM_CSP_CreateAsymmetricContext with algorithm ID = CSSM_ALGID_RSA and Padding = CSSM_PADDING_PKCS1. This creates the new context handle CSSM_CC_HANDLE.
- Call CSSM_DecryptData, the result is the decrypted plain XML settings data.
- Free the context with CSSM_DeleteContext.
Encryption with password
In this encryption scenario we use a symmetric AES cipher algorithm, the key is derived from a password. To do this properly, so that we get a secure AES key, is not trivial. The Mac OS X version of SEB uses the open source RNCryptor Objective-C framework, which provides a secure implementation of AES encryption including correct handling of password stretching (PBKDF2), salting, IV and HMAC (see explanations below). The author also provides good documentation about properly encrypting with AES and explains, why this effort is necessary. The description below explains generally how the encryption and decryption is done by RNCryptor, which is roughly the procedure that should be used for any secure use of AES (it is not specific to RNCryptor). For Windows/.NET and other platforms/languages the encryption has to be re-implemented using the platform provided standard low-level crypto algorithms, namely PBKDF2, AES-256-CBC and SHA-256. The OS X version uses the open source C crypto framework CommonCrypto, which could also be used on Linux, although many other open and closed source frameworks also provide these crypto algorithms. .NET also includes AES.
Explanation of terms used
(Taken from Wikipedia, see the links for the full description)
AES Advanced Encryption Standard, specification for the encryption of electronic data using a symmetric-key algorithm. See also list of implementations.
HMAC A hash-based message authentication code is a specific construction for calculating a message authentication code (MAC) involving a cryptographic hash function in combination with a secret cryptographic key. As with any MAC, it may be used to simultaneously verify both the data integrity and the authenticity of a message.
IV Initialization vector, an additional random or pseudorandom input value, which is required to be mixed with the first block when using a block-based encryption algorithm like AES-CBC.
PBKDF2 Password-Based Key Derivation Function 2 is a key derivation function that is part of RSA Laboratories' Public-Key Cryptography Standards (PKCS) series. PBKDF2 applies a pseudorandom function, such as a cryptographic hash, cipher, or HMAC to the input password or passphrase along with a salt value and repeats the process many times to produce a derived key, which then can be used as a cryptographic key in subsequent operations.
PRF Pseudo random function. A hash algorithm like SHA-256 can be used as a PRF.
SHA-256Secure Hash Algorithm belonging to the SHA-2 set of cryptographic hash functions.
Data Format
All data in network order (big-endian).
| version | options | encryption salt | HMAC salt | IV | ... encrypted data ... | HMAC |
| 0 | 1 | 2-9 | 10-17 | 18-33 | 34 - n-33 | n-31 - n |
- version (1 byte): Data format version. For now always 1.
- options (1 byte): Reserved. Always 0.
- encryption salt (8 bytes)
- HMAC salt (8 bytes)
- IV (16 bytes)
- encrypted data/ciphertext (variable) -- Encrypted with CBC mode.
- HMAC (32 bytes)
Details:
- EncryptionKey = PBKDF2 (with parameters encryption salt, 10k iterations, password)
- HMACKey = PBKDF2(HMAC salt, 10k iterations, password)
- Encrypted data (ciphertext) is AES-256-CBC encrypted using the given IV and the EncryptionKey (above).
- HMAC is generated using the encrypted data and the HMACKey (above) and the SHA-256 PRF.
Encrypting
- Generate a random encryption salt
- Generate the encryption key using PBKDF2 (see your language docs for how to call this). Pass the password as a string, the random encryption salt, and 10,000 iterations.
- Generate a random HMAC salt
- Generate the HMAC key using PBKDF2 (see your language docs for how to call this). Pass the password as a string, the random HMAC salt, and 10,000 iterations.
- Generate a random IV
- Encrypt the data using the encryption key (above), the IV (above), AES-256, and the CBC mode. This is the default mode for almost all AES encryption libraries.
- Pass your ciphertext to an HMAC function, along with the HMAC key (above), and the PRF "SHA-256" (see your library's docs for what the names of the PRF functions are; this might also be called "SHA-2, 256-bits").
- Put these elements together in the format given above.
Decrypting
- Pull apart the pieces as described in the data format.
- Generate the encryption key using PBKDF2 (see your language docs for how to call this). Pass the password as a string, the given encryption salt, and 10,000 iterations.
- Generate the HMAC key using PBKDF2 (see your language docs for how to call this). Pass the password as a string, the given HMAC salt, and 10,000 iterations.
- Decrypt the data using the encryption key (above), the given IV, AES-256, and the CBC mode. This is the default mode for almost all AES encryption libraries.
- Pass your ciphertext to an HMAC function, along with the HMAC key (above), and the PRF "SHA-256" (see your library's docs for what the names of the PRF functions are; this might also be called "SHA-2, 256-bits"). Verify that your result matches the result in the message you were sent.
Structure and list of keys in the plain XML configuration file before encryption
The plain settings are saved as serialized objects in a XML format. As base for this the Apple property list (plist) format was chosen, because it‘s a) having a simple structure using only a few basic tags, b) being directly supported on Mac OS X and iOS and easy to parse on other systems.
Property list data types and XML tags:
Abstract type | XML Tag | Storage format |
---|---|---|
array | <array> | Indexed collections of values: Can contain any number of child elements |
dictionary: | <dict> | Collections of values each identified by a key: Alternating <key> tags and plist element tags |
string | <string> | UTF-8 encoded string |
number - integer | <integer> | Decimal string |
number - floating point | <real> | Decimal string |
boolean | <true />, or <false /> | No data (tag only) |
date | <date> | ISO 8601 formatted string |
data | <data> | Base64 encoded data |
Since human readability is not relevant for the .seb configuration file as users will never see it unencrypted, structure of the XML configuration files is reduced to the basic, essential plist-structure. Therefore there are no sections as in the old ini files. All keys in the root-level dictionary are unique (each key can only occur once).