--- /dev/null
+@node Authcrypt
+@cindex authenticated public-key encryption
+@nodedescription Authenticated public-key encryption
+@subsection Authenticated public-key encryption
+
+Public-key based @ref{KEM, KEMs} provides sender authentication
+@strong{only} if @code{/kem/*/from} field is specified. It should
+contain public key's @code{/load/v/id}, but may be equal to 256-bit
+zeros, to explicitly specify that sender's public key is used, but it is
+anonymous and hidden. It is not specified how recipient should find
+corresponding sender's key that way -- implementation/protocol specific.
+
+Optional @code{/pubs} is a list public keys, which may be used to supply
+sender's public key(s). Public keys may be encrypted, to hide the actual
+deanonymisation contents.
+
+It is @strong{highly} recommended to use multi-recipient safe DEM when
+encrypting to multiple recipients. For example
+@code{@ref{dem-xchapoly-krmr, dem-xchapoly-krmr}} instead of
+@code{@ref{dem-xchapoly-krkc, dem-xchapoly-krkc}}, but unfortunately
+with the price of more expensive double pass authentication scheme.
--- /dev/null
+@node dem-xchapoly-krmr
+@cindex dem-xchapoly-krmr
+@nodedescription XChaCha20-Poly1305 with key ratcheting and multi-recipient DEM
+@subsubsection XChaCha20-Poly1305 with key ratcheting and multi-recipient DEM
+
+@code{cm/encrypted}'s @code{/dem/a} equals to "xchapoly-krmr".
+
+CEK consists of common 64 bytes long part equal in all KEMs (@code{CEK} itself),
+and 64 bytes long per-KEM/per-recipient random MAC key (@code{prMAC}).
+
+Data is split on 128 KiB chunks, each of which is encrypted the following way:
+
+@verbatim
+H = BLAKE2b
+CK0 = CEK
+CKi = HKDF-Extract(H, salt="", ikm=CK{i-1})
+KEY = HKDF-Expand(H, prk=CKi, info="cm/encrypted/xchapoly-krmr/key")
+IV = HKDF-Expand(H, prk=CKi, info="cm/encrypted/xchapoly-krmr/iv", len=24)
+if last chunk { IV[23] |= 0x01 } else { IV[23] &= 0xFE }
+CIPHERTEXT || TAG = XChaCha20-Poly1305(key=KEY, ad="", nonce=IV, data=chunk)
+MACi = BLAKE2b-256-MAC(key=prMACi, H(CIPHERTEXT || TAG))
+CIPHERTEXT || TAG || MAC0 [|| MAC1 ...]
+@end verbatim
+
+Chaining key (CK) advances with every chunk. 256-bit encryption key and
+randomised 192-bit nonce (initialisation vector) are derived from it.
+
+Nonce's lowest bit is set only if this is the last chunk we encrypting.
+
+@code{/payload}'s chunk length equals to 128KiB+16+32*recipients bytes.
+
+HKDF is KDF algorithm,
+@url{https://datatracker.ietf.org/doc/html/rfc5869.html, RFC 5869}.
+@url{https://www.blake2.net/, BLAKE2b} is hashing algorithm,
+@url{https://datatracker.ietf.org/doc/html/rfc7693.html, RFC 7693}.
+@url{https://datatracker.ietf.org/doc/html/draft-irtf-cfrg-xchacha, XChaCha20-Poly1305}
+is an authenticated encryption algorithm, extended nonce version of ChaCha20-Poly1305,
+@url{https://datatracker.ietf.org/doc/html/rfc8439.html, RFC 8439}.
@item Ability to use multiple recipients
@item Either passphrase- or public-key based KEMs
@item Hybrid PQ/T KEMs
-@item Optionally anonymous recipients
+@item Ability to authenticate the sender
+@item Optionally anonymous recipients and sender
@item Streaming friendly
@item Ability to parallelise encryption/decryption procedures
@item Current DEM schemes do explicit key commitment
@item Current DEM schemes use key ratcheting and rotation
+@item Ability to safely encrypt to multiple recipients
@end itemize
-Currently there is @strong{no} sender authentication! But remember to
-include recipient's public key fingerprint in encrypted signed document
-if you use it.
-
Stored in a file, it should begin with "cm/encrypted" @ref{MAGIC, magic}.
@verbatiminclude ../tcl/schemas/encrypted.tcl
It is recommended to encode it as a BLOB, which chunk's length depends
on DEM algorithm.
-CEK is encapsulated in @code{/kem/*} entries (key encapsulation
-mechanism), using @code{/kem/*/a} algorithm. @code{/kem/*/cek} field
-contains an encrypted CEK.
+CEK is encapsulated in @code{/kem/*/cek} entries (key encapsulation
+mechanisms), using @code{/kem/*/a} algorithm.
-If KEM uses public-key based cryptography, then recipient's
-@ref{cm-pub, public key}(s) should be provided, which may lack the
-signatures at all. Optional @code{/kem/*/to}, public key's fingerprint,
-may provide a hint to quickly search for the key on the recipient's side.
+If KEM uses public-key based cryptography, then recipient's @ref{cm-pub,
+public key}(s) must be provided. Optional @code{/kem/*/to}, public key's
+fingerprint, may provide a hint to quickly search for the key on the
+recipient's side.
Optional @code{/id} is used in KEMs for domain separation and envelope
identification. UUIDv4 is recommended. If absent, then null UUID is used
in KDF.
+@include cm/authcrypt.texi
+
@node Key wrapping
@cindex key wrapping
@nodedescription Key wrapping mechanisms
@subsection Data encapsulation mechanisms
@include cm/dem-xchapoly-krkc.texi
+@include cm/dem-xchapoly-krmr.texi
@include cm/dem-kuznechik-ctr-hmac-kr.texi
@node KEM
@verbatim
H = Streebog-512
-PRK = HKDF-Extract(H, salt="", ikm=VKO(..., ukm=UKM))
+DH(sk, pk) = GOSTR3410-VKO(prv=sk, pub=pk, ukm=UKM)
+PRK = HKDF-Extract(H, salt="", ikm=DH(e, s))
+if specified(sender):
+ PRK = HKDF-Extract(H, salt=PRK, ikm=DH(s, s))
KEK = HKDF-Expand(H, prk=PRK, info="cm/encrypted/gost3410-hkdf" || /id)
@end verbatim
algorithm must be used. It should have "kem" key usage set.
Recipient's map @code{/kem/*/encap} field is a concatenation of
-194 bytes of Classic McEliece 6960-119 ciphertext with 32 bytes of
-ephemeral X25519 public key.
+194 bytes of Classic McEliece 6960-119 ciphertext, containing
+ephemeral key, with 32 bytes of ephemeral X25519 public key.
Recipient performs X25519 and Classic McEliece computations to
derive/decapsulate two 32-byte shared keys. Then it combines
@verbatim
H = SHAKE256
PRK = HKDF-Extract(H, salt="", ikm=
- mceliece6960119-shared-key || x25519-shared-key ||
- H(mceliece6960119-sender-ciphertext || x25519-sender-public-key) ||
- H(mceliece6960119-recipient-public-key || x25519-recipient-public-key))
+ mceliece6960119-shared-key || es-x25519-shared-key ||
+ H(mceliece6960119-sender-ciphertext || e-x25519-sender-public-key) ||
+ H(mceliece6960119-recipient-public-key || s-x25519-recipient-public-key))
+if specified(sender):
+ PRK = HKDF-Extract(H, salt=PRK, ikm=
+ ss-x25519-shared-key ||
+ s-x25519-sender-public-key ||
+ s-x25519-recipient-public-key)
KEK = HKDF-Expand(H, prk=PRK,
info="cm/encrypted/mceliece6960119-x25519-hkdf-shake256" || /salt)
@end verbatim
"kem" key usage set.
Recipient's map @code{/kem/*/encap} field is a concatenation of 1047
-bytes of Streamlined NTRU Prime 4591^761's ciphertext with 32 bytes of
-ephemeral X25519 public key.
+bytes of Streamlined NTRU Prime 4591^761's ciphertext, containing
+ephemeral key, with 32 bytes of ephemeral X25519 public key.
Recipient performs X25519 and SNTRUP computations to derive/decapsulate
two 32-byte shared keys. Then it combines them to get the KEK decryption
@verbatim
H = BLAKE2b
PRK = HKDF-Extract(H, salt="", ikm=
- sntrup4591761-shared-key || x25519-shared-key ||
- H(sntrup4591761-sender-ciphertext || x25519-sender-public-key) ||
- H(sntrup4591761-recipient-public-key || x25519-recipient-public-key))
+ sntrup4591761-shared-key || es-x25519-shared-key ||
+ H(sntrup4591761-sender-ciphertext || e-x25519-sender-public-key) ||
+ H(sntrup4591761-recipient-public-key || s-x25519-recipient-public-key))
+if specified(sender):
+ PRK = HKDF-Extract(H, salt=PRK, ikm=
+ ss-x25519-shared-key ||
+ s-x25519-sender-public-key ||
+ s-x25519-recipient-public-key)
KEK = HKDF-Expand(H, prk=PRK, info="cm/encrypted/sntrup4591761-x25519-hkdf-blake2b" || /id)
@end verbatim
{field kem {list} {of kem} >0}
{field id {hexlet} optional}
{field payload {bin} optional}
+ {field pubs {list} {of map} optional >0} {# attached public keys}
}
dem {
{field . {map}}
{field a {str} >0} {# xchapoly-krkc}
+ {# xchapoly-krmr}
{# kuznechik-ctr-hmac-kr}
}
{field cek {bin} >0} {# wrapped CEK}
{field encap {bin} >0}
{field to {with fpr} optional} {# recipient's public key}
+ {field from {with fpr} optional} {# sender's public key}
}