Anima Cryptographic Identity Protocol
Table of Contents
- 1. Overview
- 1.1. Rationale
- 1.2. Terminology
- 1.3. Persona Authentication
- 1.4. Web of Trust
- 1.5. Encryption for Confidentiality
- 1.6. Compliance
- 2. Keys and Fingerprints
- 2.1. Fingerprints
- 2.2. LUCID URIs
- 2.3. Endorsements
- 3. Message Data
- 3.1. Data Types
- 3.2. Endorsement Message
- 4. Trust System
- 4.1. Trust Levels
- 5. Cipher Suite
- 5.1. Hashing Algorithms
- 5.1.1. Allowed Hashing Algorithms
- 5.1.2. Disallowed Hashing Algorithms
- 5.1.3. TBD
- 5.2. Symmetric Ciphers
- 5.2.1. Allowed Symmetric Ciphers
- 5.2.2. Disallowed Symmetric Ciphers
- 5.3. Asymmetric Ciphers
- 5.3.1. Allowed Asymmetric Ciphers
- 5.3.2. Disallowed Asymmetric Ciphers
- 5.4. Compression Algorithms
- 5.4.1. zlib
- 5.4.2. brotli
- 5.4.3. lzma
- 5.4.4. zstd
1. Overview
1.1. Rationale
TODO1.2. Terminology
Persona: a "Persona" in this document, when capitalized, refers to a consistent, cryptographically verifiable identity. This identity may be strongly linked to a real person or other real entity, or it may be anonymous. A person may have one or many Personas.
Endorsement: an "Endorsement" in this document, when capitalized, refers to a cryptographic signature generated by another third-party Persona based on a public key, which is used to "endorse" the authenticity of the public key, i.e. supporting the claim that this key does in fact correspond to a private key owned by the alleged Persona. Endorsements, especially from people you personally trust, add veracity to authentication via public keys. Endorsements are similar to "keysigning" in OpenPGP.
1.3. Persona Authentication
The Persona authentication process begins with a LUCID URI as described in Part 2.2. These URIs will be attached to anything that one might feasibly want to verify the authorship of. The format of the URIs themselves is defined, but the way in which they are provided is not. They may be included in JSON data, appended in plain text after a message, or any other technique which makes the URI easily accessible.
Next, the full public key, identity proofs, and endorsements for the Persona must be located. Note that LUCID URIs are Uniform Resource Identifiers, not Uniform Resource Locators. The significance of this distinction lies in the fact that this specification does not define a canonical method for resolving LUCID URIs to Personas ("locating" them). It is intentionally left undefined and intended to be open-ended and implementation-specific, though other specifications for LUCID URI resolution may be created in the future.
When the canonical home of the Persona has been located, several resources are collected: the Persona's full public key, a list of ownership proofs (links to - or single proofs as found on - sites such as Keyoxide or Keybase), and a list of Endorsements for that public key. All of this information is stored locally by the client, along with notes about what Persona the key belongs to, for future authentication purposes. All keys found this way should always have at least one Endorsement, from the key owner themselves. This Endorsement obviously doesn't mean anything for the trustworthiness of the key, but it does provide a baseline level of cryptographic integrity.
Once the public key has been stored, any future messages that include an attached fingerprint matching the key can be cryptographically verified using that stored public key, allowing subsequent authentication based on the fingerprint alone.
1.4. Web of Trust
Anima is based on a decentralized trust model known as the "web of trust". The basic principle is that although you can't be expected to know everyone in the world personally, there can be a few people you trust, who have a few people they trust, who have a few people they trust, and so on, forming a giant "web of trust" that can provide some sense of the trustworthiness of a stranger based on who else trusts them, and how many trust-hops away from you they are in the web. Anima has a trust system similar to OpenPGP's but with more fine-grained trust distinctions and more amenable to numeric analysis of complex trust chains. The trust system is outlined in Part 4.
1.5. Encryption for Confidentiality
TODO - key exchange, communication via symmetric cipher
1.6. Compliance
When marked in small caps, the terms must, must not, required, should, should not, may, optional, recommended, and not recommended are to be interpreted as described in RFC 2119. The small caps term not required is equivalent to the term optional as defined in RFC 2119.
2. Keys and Fingerprints
2.1. Fingerprints
Key fingerprints are compact identifiers that can be liberally attached to messages and media with minimal usage of bandwidth or storage. Fingerprints are calculated from a public key using SHA3-512/192, that is, hashed using the SHA-3 hashing algorithm with an output size of 512 bits, which is then truncated to 192 bits. These fingerprints are commonly represented by a string of 32 Base64 characters, e.g. k79dnQ7BwEabPeqqXyZlvyEJ3exz4eVF
. These may be displayed to the user in groups of 4 for readability (such as k79d nQ7B wEab Peqq XyZl vyEJ 3exz 4eVF
) but they must be stored and transmitted without any such padding. (TODO: is 512/192 actually stronger than 224/192 or simply 192?)
Fingerprints serve as a globally unique identifier for a Persona. They are resilient to collision or preimage attacks but must not be considered equivalent to a public key. Messages with only a fingerprint attached should not be trusted for anything important. Important messages should always contain a cryptographic signature alongside the fingerprint, so that the full public key matching the fingerprint can be used to properly verify the contents. Even in the event of a successful collision attack in the future, users who already have the fingerprint's original public key stored would be unaffected.
Malicious public keys generated with colliding fingerprints may try to claim that they are the correct Persona for the fingerprint, which could trick users who haven't received the original, genuine public key. This is not currently computationally feasible, but it could become so in the future. The only way to solve this problem is socially, i.e. by making it publically known that there is an impersonator with your fingerprint out there. A new keypair could be generated and endorsements for it received again, and then revoke the original key/fingerprint, which would alleviate the impersonator problem, but this is potentially a very difficult and time-consuming task and so cannot be considered an acceptable solution. In the event that fingerprints become easily compromised in the future, later versions of the protocol may use more secure fingerprints, and systems will need to be able to handle upgrading to these new fingerprints at that time.
In an abundance of caution, entire public keys could be attached to messages instead of fingerprints. With some ECC-based algorithms, the full public key is fairly short (an Ed25519 public key is 64 characters in Base64). However, this practice is currently not recommended unless viable attacks on the SHA3 hash are discovered.
2.2. LUCID URIs
The perferred identifier for a Persona is a Uniform Resource Identifier (URI) (as per RFC 3986) with a lucid
scheme (not yet registered with IANA). LUCID stands for Lightweight Unique Cryptographic IDentifier.
lucid
URIs must be formatted as follows: lucid:<version>:<fingerprint>?<query>#<fragment>
<version>
is a string starting with "v" followed by an integer representing the LUCID URI version. Currently, only version 1 exists, written as v1
. The "v" is case-insensitive.
<fingerprint>
is a SHA3-512/192 fingerprint as described above, encoded in Base64.
<query>
and <fragment>
are a query component and fragment identifier respectively, as defined in RFC 3986. They currently have no defined use, but may be used in the future for purposes such as supplying parameters to identity queries or identifying sub-resources. Compliant implementations must accept and be able to parse LUCID URIs with query strings or fragments, though currently they are not required to do anything with that data.
The lucid:
scheme, <version>
, and <fingerprint>
are required in a valid LUCID URI. <query>
and <fragment>
are optional. Examples of a valid LUCID URIs are:
lucid:v1:k79dnQ7BwEabPeqqXyZlvyEJ3exz4eVF
lucid:v1:k79dnQ7BwEabPeqqXyZlvyEJ3exz4eVF?param=true
lucid:V1:k79dnQ7BwEabPeqqXyZlvyEJ3exz4eVF#example
LUCID:v1:k79dnQ7BwEabPeqqXyZlvyEJ3exz4eVF?param=3&another=%26%3A#example
2.3. Endorsements
Version 1 (the current and only version) Endorsements consist of five pieces of information: the Endorsement algorithm version number, the fingerprint of the endorser, the trust level associated with the Endorsement, a timestamp indicating when the endorsement was made, and a cryptographic signature. The signature is generated from the concatenation of the following:
- the bytes of the target Persona's public key
- a single byte representing the version number
- a single signed byte representing the trust level assigned to the Endorsement (see Trust Levels)
- the bytes of the endorser's fingerprint
- the Endorsement timestamp, represented as a Unix epoch timestamp in seconds, as a 32-bit unsigned big-endian integer (four bytes).
This stream of bytes is then signed using the endorser's private key, and the resulting signature is used for the Endorsement. Note that the type of public key used is irrelevant. As long as both the endorser and the verifier use the same byte stream, the result will be the same, regardless of the format or size of the public key. Future Endorsement versions are guaranteed to contain a version number, but all other fields may be different.
Security when obtaining the other Persona's original public key is crucial - all other verifications are based on this key. By contrast, security when issuing Endorsements is a non-issue, since they're generated cryptographically with your secret private key, the other Persona's public key (which should be cached locally), and the related Endorsement information, so intercepting them in transit provides no added value to an attacker. Cryptographically invalid Endorsement signatures are rejected, and if the attacker wants to issue their own Endorsement, they can already do that - the weight of that endorsement depends on their own trustworthiness.
3. Message Data
3.1. Data Types
Number
String
Base64
Timestamp
YYYY-MM-DDThh:mm:ssZ
format as defined by ISO 8601. Timestamps must always be in UTC, with the Z
suffix.
Array of T
T
. Arrays may be homogenous or heterogenous, and may or may not be empty.
Object
HashAlgorithm
String
. Must be one of:
"SHA2-512/256"
"SHA2-384"
"SHA3-256"
"SHA3-384"
"SHA3-512"
"BLAKE2s-256"
"BLAKE2b-384"
"BLAKE2b-512"
HashAlgorithm
value is case-insensitive.
CompressionAlgorithm
String
. Must be one of:
"zlib"
"brotli"
"lzma"
"zstd"
CompressionAlgorithm
value is case-insensitive.
SymmetricCipher
String
. Must be one of:
"AES-GCM-128"
"AES-CCM-128"
"ChaCha20-Poly1305"
SymmetricCipher
value is case-insensitive.
AsymmetricCipher
String
. Must be one of:
"RSA2048"
"RSA4096"
"Ed25519"
"Ed448"
"NISTp256"
"NISTp384"
"NISTp521"
AsymmetricCipher
value is case-insensitive.
MessageType
String
. Valid options are:
"SessionKey"
This message type contains an encrypted symmetric session key used for confidential data transmission.
Requires fields:sessionKey
."Signature"
This message type contains a signature corresponding to aSignatureType
.
Requires fields:signature
."Capabilities"
This message type contains information about the ciphers and algorithms supported by the sender.
Requires fields:capabilities
.
MessageType
value is case-insensitive.
SignatureType
String
. Valid options are:
"BinaryDocumentSignature"
This means the signer owns it, created it, or certifies that it has not been modified."TextDocumentSignature"
Identical to BinaryDocumentSignature except that line endings are normalized tobefore the signature is calculated. "InlineSignature"
A signature verifying the BinaryData or TextData block present in the signature file. TextData is a JSON string which cannot include line breaks and escaped line endings are not normalized."IdentityCertificationSignature"
The issuer of this signature offers verification of the claim that the owner of the corresponding key is who they claim to be. Trust level is specified intrustLevel
field."KeyRevocationSignature"
The signature of a key to be revoked. A revoked key is not to be used. The signature is calculated directly on the key being revoked. Only revocation signatures made by the key being revoked should be considered valid revocation signatures."CertificationRevocationSignature"
This signature revokes an earlier IdentityCertificationSignature. It must be issued by the same key that issued the revoked signature. The signature is computed over the same data as the certificate that it revokes, and must have a later creation date than that certificate.
SignatureType
value is case-insensitive.
3.2. Endorsement Message
The canonical form for an endorsement data packet is a JSON-compatible map with the following keys and fields:
{
"version": 1,
"trustLevel": "Known",
"signerFingerprint": "k79dnQ7BwEabPeqqXyZlvyEJ3exz4eVF",
"timestamp": "2022-02-10T12:34:56Z",
"signature": "TODO"
}
These values are valid for a signer public key of TODO
and a target public key of TODO
. You can verify it yourself. Note that these values cannot be used to verify the endorsement as is. The Base64 strings will need to be converted to raw bytes and the trust level and timestamp into a numeric value. See Part 2.3 for details on calculating Endorsement signatures.
4. Trust System
4.1. Trust Levels
Every Persona is able to apply a "trust level" to every other Persona they know of by way of Endorsements. Each Endorsement is associated with a trust level ranging from explicitly distrusted, to neutral, to trusted, to a special level reserved for keys you own the private key for, and therefore don't need to "trust" ownership of at all.
Below is the list of trust levels and their associated descriptions. To the left are the numeric values for each level in parentheses, and in square brackets are possible letters or symbols used to represent them in user interfaces. These are only suggestions; implementations may use whatever abbreviated depiction they want so long as the full-word label is identical to those listed below. This system works best when assigned trust levels are honest and accurate, so give some thought to these before chosing one for someone.
- (-1) [❌][X] Untrustworthy: Keys that have been revoked or that you have explicit reason to distrust.
- (0) [❔][N] Neutral: Keys you have no supporting information for, but do not distrust.
- (1) [➖][M] Moderate: Keys you have some reason to believe are legitimate.
- (2) [⭕][K] Known: Keys of people you've personally known for a while. You trust them and you have good reason to believe that this key is theirs.
- (3) [✔️][T] Trusted: Highly-trusted friends you've known for many years. You're very confident that this key is theirs.
- (4) [⭐][V] Verified: Keys that have been directly verified by you in person.
- (5) [🔑][S] Self: Keys you yourself own.
5. Cipher Suite
5.1. Hashing Algorithms
5.1.1. Allowed Hashing Algorithms
Note that public key fingerprints must always be generated with SHA3-512 truncated to 192 bits as defined in Part 2.1.
SHA2-512/256
SHA version 2 using an internal state size of 512 (8×64) bits, truncated to 256 bits. Thanks to the use of truncation, this method is resistant to length extension attacks.
SHA2-384
SHA version 2 using an internal state size of 512 (8×64) bits, truncated to 384 bits. Less resistant against length extension attacks than SHA2-512/256, but better collision resistance.
SHA3-256
SHA version 3 using an internal state size of 1600 (5×5×64) bits, with an output size of 256 bits. Equivalent to SHA2-512/256 for collision resistance, significantly stronger against length extension attacks but more expensive to compute than SHA2.
SHA3-384
SHA version 3 using an internal state size of 1600 (5×5×64) bits, with an output size of 384 bits. Stronger than SHA3-256 but more expensive to compute.
SHA3-512
SHA version 3 using an internal state size of 1600 (5×5×64) bits, with an output size of 512 bits. Stronger than SHA3-384 but more expensive to compute.
BLAKE2s-256
BLAKE2 with an internal state size of 256 bits and an output size of 256 bits. Significantly better worst-case collision resistance than SHA2 or SHA3, while being faster than both. SHA2/3 are still included as they are more thoroughly tested.
BLAKE2b-384
BLAKE2 with an internal state size of 512 bits and an output size of 384 bits. Stronger variant of BLAKE2s-256.
BLAKE2b-512
BLAKE2 with an internal state size of 512 bits and an output size of 512 bits. Stronger variant of BLAKE2b-384.
5.1.2. Disallowed Hashing Algorithms
MD4 and MD5
Cryptographically broken and collisions can be generated in seconds.
MD2
Less vulnerable than MD4 or MD5 but still not considered secure. MD2 support has been removed from OpenSSL, GnuTLS, and NSS.
SHA0 and SHA1
Cryptographically broken; generating collisions for SHA-1 is computationally feasible, and takes only around an hour for SHA-0 on commodity hardware.
SHA2-224, SHA2-256, and SHA2-512
All are vulnerable against length extension attacks.
SHA3-224
Weaker than SHA3-256 but with nearly identical computation time.
5.1.3. TBD
SHAKE128/SHAKE256
Whirlpool
RIPEMD-160
5.2. Symmetric Ciphers
5.2.1. Allowed Symmetric Ciphers
AES-GCM-128
AES-CCM-128
ChaCha20-Poly1305
5.2.2. Disallowed Symmetric Ciphers
5.3. Asymmetric Ciphers
5.3.1. Allowed Asymmetric Ciphers
RSA2048
RSA4096
Ed25519
Ed448
NISTp256
NISTp384
NISTp521
5.3.2. Disallowed Asymmetric Ciphers
5.4. Compression Algorithms
5.4.1. zlib
(deflate + zlib wrapper)