Merge pull request #1286 from Granddave/feature/update-vault-docs

Update vault documentation
This commit is contained in:
Alexander Bakker 2024-03-01 13:27:07 +01:00 committed by GitHub
commit 243a52ebed
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -14,8 +14,10 @@ format of the vault.
### Primitives
Two cryptographic primitives were selected for use in Aegis. An Authenticated
Encryption with Associated Data (AEAD) cipher and a Key Derivation Function
(KDF).
Encryption with Associated Data
([AEAD](https://en.wikipedia.org/wiki/Authenticated_encryption#Authenticated_encryption_with_associated_data))
cipher and a Key Derivation Function
([KDF](https://en.wikipedia.org/wiki/Key_derivation_function)).
#### AEAD
@ -36,15 +38,16 @@ This is a reasonable assumption to make, because it's highly unlikely that an
Aegis user will ever come close to saving the vault 2<sup>32</sup> times.
_Switching to a nonce misuse-resistant cipher like AES-GCM-SIV or a cipher with
a larger (192 bits) nonce like XChaCha-Poly1305 will be considered in the future._
a larger (192 bits) nonce like XChaCha-Poly1305 will be considered in the
future._
#### KDF
__scrypt__ is used as the KDF to derive a key from a user-provided password,
with the following parameters:
[__scrypt__](https://en.wikipedia.org/wiki/Scrypt) is used as the KDF to derive
a key from a user-provided password, with the following parameters:
| Parameter | Value |
| :-------- | :------------- |
| Parameter | Value |
|:----------|:---------------|
| N | 2<sup>15</sup> |
| r | 8 |
| p | 1 |
@ -104,12 +107,17 @@ shown below:
}
```
It starts with a ``version`` number and a ``header``. If a backwards
incompatible change is introduced to the content format, the version number will
be incremented. The vault contents are stored under ``db``. Its value depends on
whether the vault is encrypted or not. If it is, the value is a string containing
the Base64 encoded (with padding) ciphertext of the vault contents. Otherwise,
the value is a JSON object.
It starts with a ``version`` number. If a forwards incompatible change is
introduced to the vault format, the version number will be incremented. The
current version of the vault format is ``1``.
The [``header``](#header), if not empty, contains the list of slots and the
encryption parameters used for decrypting the vault.
The vault contents are stored under ``db``. Its value depends on whether the
vault is encrypted or not. If it is, the value is a string containing the Base64
encoded (with padding) ciphertext of the vault contents. Otherwise, the value is
a JSON object. See [vault content](#vault-content) for details.
Full examples of a [plain text
vault](/app/src/test/resources/com/beemdevelopment/aegis/importers/aegis_plain.json)
@ -122,9 +130,14 @@ password: [decrypt.py](/docs/decrypt.py).
### Header
The header starts with the list of ``slots``. It also has a ``params`` object
that holds the ``nonce`` and ``tag`` that were produced during encryption,
encoded as a hexadecimal string.
The header starts with the list of [``slots``](#slots-1). Each slot contains the
master key in an encrypted form together with the key wrapping parameters.
It also has a ``params`` object that holds the ``nonce`` and ``tag`` that were
produced during the AES-GCM encryption, encoded as a hexadecimal string. These
encryption parameters together with the master key (which can be retrieved by
decrypting the ``key`` from one of the slots) are used to decrypt the vault
contents found in the ``db`` field.
Setting ``slots`` and ``params`` to null indicates that the vault is not
encrypted and Aegis will try to parse it as such.
@ -141,13 +154,13 @@ encrypted and Aegis will try to parse it as such.
#### Slots
The different slot types are identified with a numerical ID.
The different slot types are identified with a numerical ID.
| Type | ID |
| :---------- | :--- |
| Raw | 0x00 |
| Password | 0x01 |
| Biometric | 0x02 |
| Type | ID |
|:----------|:-----|
| Raw | 0x00 |
| Password | 0x01 |
| Biometric | 0x02 |
##### Raw
@ -182,7 +195,7 @@ Raw slots don't imply use of a particular storage type.
As noted earlier, scrypt is used to derive a 256-bit key from a user-provided
password. A random 256-bit ``salt`` is generated and passed to scrypt to protect
against rainbow table attacks. Its stored along with the ``N``, ``r`` and ``p``
against rainbow table attacks. It's stored along with the ``N``, ``r`` and ``p``
parameters.
```json
@ -201,56 +214,69 @@ parameters.
}
```
### Content
### Vault content
The content is a JSON object encoded in UTF-8.
```json
{
"version": 1,
"entries": []
"version": 3,
"entries": [],
"groups": []
}
```
It has a ``version`` number and a list of ``entries``. If a backwards
incompatible change is introduced to the content format, the version number will
be incremented.
It has a ``version`` number, a list of ``entries`` and a list of ``groups``. If
a forwards incompatible change is introduced to the content format, the version
number will be incremented. The current version of the vault content format is
``3``.
| Field | Type | Description |
|:------------|:------|:-----------------------------------------|
| ``version`` | int | The version of the vault content format. |
| ``entries`` | array | A list of [entries](#entries). |
| ``groups`` | array | A list of [groups](#groups). |
#### Entries
Each entry has a unique randomly generated ``UUID`` (version 4), as well as a
``name`` and ``issuer`` to identify the account name and service that the token
is for. Entries can also have an icon. These are JPEG's encoded in Base64 with
padding. The ``info`` object holds information specific to the OTP type. The
``secret`` is encoded in Base32 without padding.
Each entry has a unique randomly generated ``UUID``, as well as a ``name`` and
``issuer`` to identify the account name and service that the token is for.
Entries hold the following fields:
| Field | Type | Description |
|:--------------|:---------------|:--------------------------------------------------------------------------------|
| ``type`` | string | The type of the OTP algorithm. See table below. |
| ``uuid`` | string | A UUID (version 4). |
| ``name`` | string | The account name. |
| ``issuer`` | string | The service that the token is for. |
| ``note`` | string | A personal note about the entry. |
| ``icon`` | string \| null | JPEG's encoded in Base64 with padding. |
| ``icon_mime`` | string \| null | The MIME type of the icon. Is null if ``icon`` is null. |
| ``icon_hash`` | string \| null | The SHA-256 hash of the icon. Is null if ``icon`` is null. |
| ``favorite`` | bool | Whether the entry is a favorite or not. |
| ``info`` | object | Information specific to the OTP type. |
| ``groups`` | array | A list of UUIDs of groups that the entry is a member of. See [Groups](#groups). |
The ``info`` object contains different fields depending on the type of the OTP.
There are a number of supported types:
| Type | ID | Spec |
| :------------------ | :------- | :-------- |
| HOTP | "hotp" | [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226)
| TOTP | "totp" | [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238)
| Steam | "steam" | N/A
| Yandex | "yandex" | N/A
| Type | ID | Spec |
|:-------|:---------|:----------------------------------------------------------|
| HOTP | "hotp" | [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226) |
| TOTP | "totp" | [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238) |
| Steam | "steam" | N/A |
| MOTP | "motp" | N/A |
| Yandex | "yandex" | N/A |
There is no specification available for Steam's OTP algorithm. It's essentially
the same as TOTP, but it uses a different final encoding step. Aegis'
implementation of it can be found in
[crypto/otp/OTP.java](https://github.com/beemdevelopment/Aegis/blob/master/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/OTP.java).
Common ``info`` fields for all types:
There is also no specification available for Yandex's OTP algorithm. Aegis'
implementation can be found in
[crypto/otp/YAOTP.java](https://github.com/beemdevelopment/Aegis/blob/master/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/YAOTP.java)
The following algorithms are supported for HOTP and TOTP:
| Algorithm | ID |
| :-------- | :------- |
| SHA-1 | "SHA1" |
| SHA-256 | "SHA256" |
| SHA-512 | "SHA512" |
For Steam, only SHA-1 is supported. For Yandex, only SHA-256 is supported.
| Field | Type | Description |
|:-----------|:-------|:-----------------------------------|
| ``secret`` | string | The Base32 encoded secret. |
| ``algo`` | string | The hashing algorithm. |
| ``digits`` | int | The number of digits in the token. |
Example of a TOTP entry:
@ -260,12 +286,105 @@ Example of a TOTP entry:
"uuid": "01234567-89ab-cdef-0123-456789abcdef",
"name": "Bob",
"issuer": "Google",
"note": "Main account",
"favorite": false,
"icon": null,
"icon_mime": null,
"icon_hash": null,
"info": {
"secret": "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567",
"algo": "SHA1",
"digits": 6,
"period": 30
}
},
"groups": [
"01234567-89ab-cdef-0123-456789abcdef"
]
}
```
##### HOTP and TOTP
TOTP uses the ``period`` field, which is the time step in seconds. HOTP uses the
``counter`` field, which is incremented every time a token is generated.
The following algorithms are supported for HOTP and TOTP:
| Algorithm | ID |
|:----------|:---------|
| SHA-1 | "SHA1" |
| SHA-256 | "SHA256" |
| SHA-512 | "SHA512" |
##### Steam
There is no specification available for Steam's OTP algorithm. It's essentially
the same as TOTP, but it uses a different final encoding step. Aegis'
implementation of it can be found in
[crypto/otp/OTP.java](/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/OTP.java).
A couple of fields have fixed values:
| Field | Value |
|:-----------|:-------|
| ``algo`` | "SHA1" |
| ``period`` | 30 |
| ``digits`` | 5 |
##### MOTP
There is no specification available for MOTP. Aegis' implementation of it can be
found in
[crypto/otp/MOTP.java](/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/MOTP.java).
A couple of fields have fixed values:
| Field | Value |
|:-----------|:------|
| ``algo`` | "MD5" |
| ``period`` | 10 |
| ``digits`` | 6 |
MOTP-specific fields:
| Field | Type | Description |
|:--------|:-------|:------------|
| ``pin`` | string | 4-digit PIN |
##### Yandex
There is no specification available for Yandex's OTP algorithm. Aegis'
implementation can be found in
[crypto/otp/YAOTP.java](/app/src/main/java/com/beemdevelopment/aegis/crypto/otp/YAOTP.java)
A couple of fields have fixed values:
| Field | Value |
|:-----------|:---------|
| ``algo`` | "SHA256" |
| ``period`` | 30 |
| ``digits`` | 8 |
Yandex-specific fields:
| Field | Type | Description |
|:--------|:-------|:---------------|
| ``pin`` | string | 4-16 digit PIN |
#### Groups
A group consists of a ``name`` and a randomly generated ``uuid`` (version 4).
| Field | Type | Description |
|:---------|:-------|:-----------------------|
| ``uuid`` | string | A UUID (version 4). |
| ``name`` | string | The name of the group. |
Example:
```json
{
"uuid": "01234567-89ab-cdef-0123-456789abcdef",
"name": "Personal"
}
```