Cmsex.Recipient (cmsex v0.1.0)

Copy Markdown View Source

A recipient for Cmsex.encrypt/3 and Cmsex.mac/3: who can decrypt the message, or check its MAC, and how the key reaches them (RFC 5652, 6.2). Build it with one of the functions here; both functions also take a certificate in DER as a recipient of certificate/2 with the defaults.

  • certificate/2 - the holder of the private key of a certificate: RSA-OAEP key transport for an RSA key (RFC 3560), ephemeral-static ECDH for an EC key (RFC 5753), and X25519 or X448 (RFC 8418).
  • kek/3 - whoever holds a symmetric key-encryption key, shared by other means, wrapped with AES key wrap (RFC 3394, RFC 5649).
  • password/2 - whoever knows a password, through PBKDF2 and the key wrap of RFC 3211.

The certificate is read, and its key checked, by Cmsex.encrypt/3; the functions here check the options, and raise ArgumentError for one that is unknown, given twice or of the wrong kind. Inspect leaves the key and the password out.

Summary

Functions

The holder of the certificate certificate, in DER.

Whoever holds the key-encryption key key, of 16, 24 or 32 bytes, known by key_id (KEKRecipientInfo, RFC 5652, 6.2.3). The message carries key_id, and the content-encryption key wrapped with AES key wrap of the size of key.

Whoever knows password (PasswordRecipientInfo, RFC 3211): the key-encryption key comes from PBKDF2 (RFC 8018), and wraps the content-encryption key with id-alg-PWRI-KEK. The password is taken as given, as bytes; normalize it before, if it may come typed in different ways.

Types

key_wrap()

@type key_wrap() ::
  :aes128_wrap
  | :aes192_wrap
  | :aes256_wrap
  | :aes128_wrap_pad
  | :aes192_wrap_pad
  | :aes256_wrap_pad

t()

@type t() :: %Cmsex.Recipient{
  certificate: binary() | nil,
  key_id: binary() | nil,
  options: map(),
  secret: binary() | nil,
  type: :certificate | :kek | :password
}

Functions

certificate(certificate, opts \\ [])

@spec certificate(binary(), keyword()) :: t()

The holder of the certificate certificate, in DER.

The key of the certificate chooses the way:

  • RSA: KeyTransRecipientInfo with RSAES-OAEP (RFC 3560), MGF1 of the same hash and no label. PKCS #1 v1.5 is never written (RFC 3218); Cmsex.decrypt/2 still reads it. An RSASSA-PSS key is for signatures only, and is refused.
  • EC (P-256, P-384, P-521 and the brainpool curves): KeyAgreeRecipientInfo with an ephemeral key on the curve of the certificate and the ANSI X9.63 KDF (RFC 5753).
  • X25519 and X448: KeyAgreeRecipientInfo with an ephemeral key and HKDF (RFC 8418).

A keyUsage extension in the certificate must allow keyEncipherment for RSA, and keyAgreement for the others.

Options:

  • :identifier - :issuer_and_serial (the default) or :subject_key_identifier, which needs that extension in the certificate.
  • :oaep_digest - the hash of RSAES-OAEP and of its MGF1: :sha256 (the default), :sha384, :sha512, :sha224, or :sha1, for a recipient that can only do the defaults of RFC 3560.
  • :key_agreement - the scheme of ECDH: :std_dh_sha256kdf, :std_dh_sha384kdf or :std_dh_sha512kdf (X9.63), or :std_dh_hkdf_sha256, :std_dh_hkdf_sha384 or :std_dh_hkdf_sha512 (HKDF, RFC 8418). The default is X9.63 with SHA-256 for P-256, SHA-384 for P-384 and SHA-512 for P-521, the hash of the size of the curve for brainpool, HKDF with SHA-256 for X25519 (as RFC 8551 asks) and HKDF with SHA-512 for X448.
  • :key_wrap - the key wrap of key agreement: :aes128_wrap, :aes192_wrap or :aes256_wrap (RFC 3394), or the same with _pad (RFC 5649). The default is AES key wrap of the size of the content-encryption key, as RFC 8551 asks, and AES-256 for a key longer than that.
  • :ukm - user keying material for key agreement, mixed into the key-encryption key (RFC 5753, 3.1.1), or nil (the default).

kek(key, key_id, opts \\ [])

@spec kek(binary(), binary(), keyword()) :: t()

Whoever holds the key-encryption key key, of 16, 24 or 32 bytes, known by key_id (KEKRecipientInfo, RFC 5652, 6.2.3). The message carries key_id, and the content-encryption key wrapped with AES key wrap of the size of key.

Options:

  • :key_wrap - :aes128_wrap, :aes192_wrap or :aes256_wrap (RFC 3394, the default), or the same with _pad (RFC 5649); its size must be that of key.
  • :date - a DateTime that tells keys of the same key_id apart.
  • :other - {oid, value}, an OtherKeyAttribute: an OID, a name of Cmsex.OID, and its value encoded in DER, or nil.

password(password, opts \\ [])

@spec password(binary(), keyword()) :: t()

Whoever knows password (PasswordRecipientInfo, RFC 3211): the key-encryption key comes from PBKDF2 (RFC 8018), and wraps the content-encryption key with id-alg-PWRI-KEK. The password is taken as given, as bytes; normalize it before, if it may come typed in different ways.

Options:

  • :iterations - of PBKDF2 (600,000). Cmsex.decrypt/2 refuses more than its :max_iterations (2,000,000).
  • :salt - 16 random bytes unless given; at least 8.
  • :prf - the pseudorandom function of PBKDF2: :hmac_sha256 (the default), :hmac_sha224, :hmac_sha384 or :hmac_sha512.
  • :kek_cipher - the cipher of the key wrap: :aes256_cbc (the default), :aes192_cbc or :aes128_cbc.