LockerEnvelope locker.envelope@1
Generated at from
openvibe-contracts v0.419.0 and
openvibe-sdk v0.161.0.
- Version
- 1.0.0
- Owner
- network
- Visibility
- public
- Status
- active
- Compatibility
- backward
- Schema
https://openvibe.network/contracts/locker/envelope.v1.json
locker.envelope@1: the header of a Locker envelope. It is the JSON that opens every chunk of the envelope bytes: the suite, the chunk size, the padded size, the counter nonce base and one key slot per way in. The content key is never in the header; it is wrapped inside a slot. Every chunk authenticates the header's core fields (version, suite, chunk_size, padded_size, nonce_base, lock) as associated data, so the framing, the size and the lock kind cannot be changed; the slots sit outside that core on purpose, because adding a member re-wraps the content key without re-encrypting the content, and each slot carries its own AES-GCM tag over the content key with its own parameters bound in.
Fields
| Field | Type | Required | Description | Constraints |
|---|---|---|---|---|
version | const | yes |
| |
suite | const | yes |
| |
chunk_size | const | yes | The chunk size in bytes: 1 MiB. Fixed for this version. |
|
padded_size | integer | yes | The size of the padded plaintext in bytes. The true size lives inside the encrypted content, so the server cannot read it; this is the size it may store and show. The size is padded with Padmé (Nikitin et al., PoPETs 2019): it is the next size on a grid that gets finer as the content grows, at most twelve per cent over the real one, and never below 256 bytes. Every chunk but the last is a whole chunk; the last holds what is left of this size. |
|
nonce_base | string | yes | Eight random bytes, base64: the first half of every chunk nonce. The second half is the chunk counter, so no nonce repeats inside one envelope. |
|
lock | enum | yes | Which way in the envelope has. Exactly one slot kind is present, and it matches this. |
|
slots | object | yes |
| |
slots.people | locker.people-slot |
| ||
slots.password | locker.password-slot | |||
slots.link | locker.link-slot |
Examples
From the contract's own test fixtures: valid ones validate, rejected ones must fail.
Valid: link
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "link",
"slots": {
"link": {}
}
}Valid: password
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "password",
"slots": {
"password": {
"algorithm": "PBKDF2-SHA256/AES-256-GCM",
"kdf": "PBKDF2-SHA-256",
"iterations": 600000,
"salt": "c3Nzc3Nzc3Nzc3Nzc3Nzcw==",
"nonce": "bm5ubm5ubm5ubm5u",
"wrapped_key": "d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3"
}
}
}Valid: people
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "people",
"slots": {
"people": [
{
"subject": {
"type": "user",
"id": "usr_01JAB2C3D4E5F6G7H8J9K0MNPR"
},
"algorithm": "ECDH-P256/HKDF-SHA256/AES-256-GCM",
"recipient_key": "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8",
"ephemeral_public_key": {
"kty": "EC",
"crv": "P-256",
"x": "eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHh4eHg",
"y": "eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXl5eXk"
},
"salt": "c3Nzc3Nzc3Nzc3Nzc3Nzcw==",
"nonce": "bm5ubm5ubm5ubm5u",
"wrapped_key": "d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3"
}
]
}
}Rejected: lock-without-slot
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "password",
"slots": {
"link": {}
}
}Rejected: other-suite
{
"version": "locker.envelope.v1",
"suite": "AES-128-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "link",
"slots": {
"link": {}
}
}Rejected: padded-size
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 100,
"nonce_base": "YmJiYmJiYmI=",
"lock": "link",
"slots": {
"link": {}
}
}Rejected: two-locks
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "link",
"slots": {
"link": {},
"password": {
"algorithm": "PBKDF2-SHA256/AES-256-GCM",
"kdf": "PBKDF2-SHA-256",
"iterations": 600000,
"salt": "c3Nzc3Nzc3Nzc3Nzc3Nzcw==",
"nonce": "bm5ubm5ubm5ubm5u",
"wrapped_key": "d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3d3"
}
}
}Rejected: unknown-field
{
"version": "locker.envelope.v1",
"suite": "AES-256-GCM",
"chunk_size": 1048576,
"padded_size": 256,
"nonce_base": "YmJiYmJiYmI=",
"lock": "link",
"slots": {
"link": {}
},
"secret": "the content key never goes in the header"
}Validate
const contracts = require('openvibe-contracts');
contracts.validate('locker.envelope@1', value); // { valid, errors: [{ path, message }] }