btok.h(3)

📦
version 2.2.0 · 2 versions
, in fedora 44

btok.h(3) — Library Functions Manual. Yes bestie, we're doing the bee2 crypto headers now, and this one is a lot, so hydrate 💧


🌸 NAME 🌸

btok.h — the cryptographic architecture of СТБ 34.101.79 (btok). That's the whole personality. It's giving standards-compliant, it's giving Eastern European crypto elegance 💅


✨ SYNOPSIS ✨

#include 'bee2/defs.h'
#include 'bee2/core/apdu.h'
#include 'bee2/crypto/bake.h'

🎀 Классы (Classes) 🎀

  • struct btok_pwd_state — the state of the password automaton 🧠
  • struct btok_cvc_t — the information content of a CV certificate 📜

🦋 Перечисления (Enumerations) 🦋

  • enum btok_pin_state — the PIN state of the password automaton 🔐
  • enum btok_auth_state — the authentication status of the password automaton ✅
  • enum btok_pwd_event — the events of the password automaton ⚡

💖 Функции (Functions) 💖

  • bool_t btokPwdTransition (btok_pwd_state *state, btok_pwd_event event) — the password automaton processes an event
  • err_t btokCVCCheck (const btok_cvc_t *cvc) — check the content of a CV certificate
  • err_t btokCVCCheck2 (const btok_cvc_t *cvc, const btok_cvc_t *cvca) — check the content of a CV certificate, this time taking the issuer's data into account
  • err_t btokCVCWrap (octet cert[], size_t *cert_len, btok_cvc_t *cvc, const octet privkey[], size_t privkey_len) — create a CV certificate
  • err_t btokCVCUnwrap (btok_cvc_t *cvc, const octet cert[], size_t cert_len, const octet pubkey[], size_t pubkey_len) — parse a CV certificate
  • err_t btokCVCIss (octet cert[], size_t *cert_len, btok_cvc_t *cvc, const octet certa[], size_t certa_len, const octet privkeya[], size_t privkeya_len) — issue a CV certificate
  • size_t btokCVCLen (const octet der[], size_t count) — the exact length of a CV certificate
  • err_t btokCVCVal (const octet cert[], size_t cert_len, const octet certa[], size_t certa_len, const octet *date) — verify a CV certificate
  • err_t btokCVCVal2 (btok_cvc_t *cvc, const octet cert[], size_t cert_len, const btok_cvc_t *cvca, const octet *date) — verify a CV certificate inside a chain
  • err_t btokCVCMatch (const octet cert[], size_t cert_len, const octet privkey[], size_t privkey_len) — check that a CV certificate and a key actually match
  • size_t btokSM_keep () — the length of the SM state
  • void btokSMStart (void *state, const octet key[32]) — initialise the SM functions
  • void btokSMCtrInc (void *state) — bump the SM counter
  • err_t btokSMCmdWrap (octet apdu[], size_t *count, const apdu_cmd_t *cmd, void *state) — encode a command and slap SM protection on it
  • err_t btokSMCmdUnwrap (apdu_cmd_t *cmd, size_t *size, const octet apdu[], size_t count, void *state) — decode a command and peel the SM protection off it
  • err_t btokSMRespWrap (octet apdu[], size_t *count, const apdu_resp_t *resp, void *state) — encode a response and slap SM protection on it
  • err_t btokSMRespUnwrap (apdu_resp_t *resp, size_t *size, const octet apdu[], size_t count, void *state) — decode a response and peel the SM protection off it
  • size_t btokBAuthT_keep (size_t l) — the length of the BAUTH state on the T side
  • err_t btokBAuthTStart (void *state, const bign_params *params, const bake_settings *settings, const octet privkey[], const bake_cert *cert) — initialise the BAUTH protocol on the T side
  • size_t btokBAuthCT_keep (size_t l) — the length of the BAUTH state on the CT side
  • err_t btokBAuthCTStart (void *state, const bign_params *params, const bake_settings *settings, const octet privkey[], const bake_cert *cert) — initialise the BAUTH protocol on the CT side
  • err_t btokBAuthCTStep2 (octet out[], const bake_cert *certt, void *state) — step 2 of the BAUTH protocol
  • err_t btokBAuthTStep3 (octet out[], const octet in[], void *state) — step 3 of the BAUTH protocol
  • err_t btokBAuthCTStep4 (octet out[], const octet in[], void *state) — step 4 of the BAUTH protocol
  • err_t btokBAuthTStep5 (const octet in[], size_t in_len, bake_certval_i val_ct, void *state) — step 5 of the BAUTH protocol
  • err_t btokBAuthCTStepG (octet key[32], void *state) — pull the BAUTH protocol key out on the CT side
  • err_t btokBAuthTStepG (octet key[32], void *state) — pull the BAUTH protocol key out on the T side

💅 ПОДРОБНОЕ ОПИСАНИЕ (Detailed Description) 💅

Some individual mechanisms of СТБ 34.101.79 (btok) are implemented here:

  • managing lightweight certificates — that's Card Verifiable, or CV, certificates bestie 🪪

Ожидается (Expects) — [ERR_BAD_INPUT]

  • All input pointers are valid. The exceptions are the cases spelled out separately. Those include a request to figure out how much memory needs to be reserved on a repeat call — that's the [len?]ptr construct 👑

📜 CV-сертификаты (CV certificates) 📜

CV certificate management follows the profile laid out in СТБ 34.101.79. That profile assigns:

  • use of the standard long-term parameters bign-curve256v1, bign-curve384v1 and bign-curve512v1 🔢
  • use of bign-sign algorithms to generate and verify signatures ✍️
  • use of belt-hash, bash384, bash512 algorithms to hash the data being signed 🧬
  • optional use of a 5-octet access-rights word for the eId application program 🪪
  • optional use of a 2-octet access-rights word for the eSign application program ✒️
  • use of specific object identifiers, in particular bign-pubkey 🏷️

In this implementation the СТБ 34.101.79 profile is extended: certificates may use bign96 keys and algorithms (see bign96.h). In particular, public keys can sit on the standard curves bign-curve256v1, bign-curve384v1 and bign-curve512v1, or on the curve bign-curve192v1.

The informational fields of a CV certificate are listed in the btok_cvc_t structure. A certificate is the DER code of those field values.

If there's no access-rights word in a certificate, that means it's zero — i.e. there are no access rights at all. When a certificate is encoded, a zero access-rights word gets dropped. And heads up: finding a zero word inside a certificate you're decoding is not treated as an error 🙅‍♀️

The date in a certificate is given as 6 octets using the YYMMDD scheme (see tm.h) 📅


🔐 Защищенное соединение (Secure Messaging) 🔐

Secure Messaging is the rulebook for protecting APDU commands and APDU responses. The general rules for organising secure messaging are defined in ISO/IEC 7816-4; the concrete rules — the ones that are actually implemented here — live in СТБ 34.101.79.

The SM state holds three objects:

  • a MAC key (belt-mac) 🧾
  • an encryption key (belt-cfb) 🔒
  • a counter 🔢

Protection is organised as encrypt-then-mac: first the body of the command/response is encrypted, and then a MAC is attached to the ciphertext. That MAC covers the counter, the ciphertext, and the plaintext data of the command/response.

The counter is used as the IV when encrypting. Before protection is applied or removed, the counter is incremented. Initially the counter equals zero.

This logic is enforced:

  • applying/removing command protection happens with odd counter values
  • applying/removing response protection happens with even counter values

Ожидается (Expects)

  • The state of the SM functions does not change outside of these functions.

Предусловие (Precondition)

  • The pointers of the SM functions are correct, unless stated otherwise.
  • The input and output buffers of the SM functions do not overlap each other.

Прим. (Note)

  • The tell-tale sign that a command is protected is bit 0x04 in the CLA field.
🫶 part 1 done, bestie — the rest is still coming, don't go anywhere

💖 Протокол BAUTH 💖

okay bestie, so this whole protocol is a little back-and-forth between the terminal (T) and the cryptographic token (КТ, aka CT, aka the little crypto bestie that holds your secrets). 🫶

To set the protocol up you use the bake_settings struct (go peep bake.h if you need it). In Bake protocol terms, side A is the terminal and side B is the cryptographic token. That's the whole cast list. ✨

The terminal always confirms the key it formed, which means it authenticates in front of the CT. So in bake_settings the kca flag has to be TRUE. Not optional. Non-negotiable. Periodt. 💅

The CT authenticating in front of the CT is optional — so in bake_settings the kcb flag can be either TRUE or FALSE, your call. 🎀

Expects [ERR_BAD_INPUT]

  • All input pointers are valid, except in the special cases that get called out separately.

Expects

  • When you're running the protocol step by step, the data you handed over at initialization through pointers stays valid and constant for the entire run of the protocol. Do not free it mid-protocol, I am begging 🙈

✨ Функции ✨

size_t btokBAuthCT_keep (size_t l)

This one just tells you the length of the state (in octets) for the BAUTH protocol functions on the CT side. Lowkey the easiest function on this whole page. 💖

Returns

  • The length of the state.

Arguments

  • l — the security level.

err_t btokBAuthCTStart (void * state, const bign_params * params, const bake_settings * settings, const octet privkey[], const bake_cert * cert)

From the parameters params, the settings settings, the private key [l / 4]privkey and the certificate cert of the matching public key, this builds up in state all the data structures you need to actually run BAUTH on the CT side. It's giving setup era. 🌸

Precondition

  • btokBAuthCT_keep() octets are reserved at the address state.

Expects [ERR_BAD_PARAMS]

  • The parameters params are valid.

Expects [ERR_BAD_INPUT]

  • settings->kca == TRUE.

Expects [ERR_BAD_INPUT]

  • The pointer settings->helloa is null, or the buffer [settings->helloa_len]settings->helloa is valid. Same exact energy for the fields settings->hellob and settings->hellob_len.

Expects [ERR_BAD_RNG]

  • The generator settings->rng (with state settings->rng_state) is valid.

Expects

  • The generator settings->rng is cryptographically strong. No mid RNGs allowed in this house. 🔥

Expects [ERR_BAD_CERT]

  • The certificate cert is valid.

Expects

  • The key privkey and the certificate cert agree with each other. If that agreement is broken, the protocol is going to finish with an error. 😭

Returns

  • ERR_OK if the initialization went through successfully, and an error code otherwise.

Arguments

  • state — the state.
  • params — long-term parameters.
  • settings — the settings.
  • privkey — the private key.
  • cert — the certificate.

err_t btokBAuthCTStep2 (octet out[], const bake_cert * certt, void * state)

CT runs step 2 of BAUTH: it processes the terminal's certificate certt and uses the state state. If the step goes well, the message M1 = [5 l / 8 + 16]out gets formed. ✨

Expects

  • btokBAuthCTStart() < btokBAuthCTStep2().

Returns

  • ERR_OK if the step went through successfully, and an error code otherwise.

Прим.

  • The CT's welcome message is not transmitted in M1.

Arguments

  • out — output message M1.
  • certt — the terminal's certificate.
  • state — the state.

err_t btokBAuthCTStep4 (octet out[], const octet in[], void * state)

CT runs step 4 of BAUTH: it processes the message M2 = [8]in if authentication in front of T isn't required, or M2 = [8 + 16]in if it isn't required, using the state state. If authentication in front of the CT is required, then a successful step forms the message M3 = [l / 4 + cert->len + 8]out. 🦋

Expects

  • btokBAuthCTStep2() < btokBAuthCTStep4().

Expects

  • btokBAuthTStep3() << btokBAuthCTStep4().

Returns

  • ERR_OK if the step went through successfully, and an error code otherwise.

Arguments

  • out — output message M3.
  • in — input message M2.
  • state — the state.

err_t btokBAuthCTStepG (octet key[32], void * state)

CT works out the shared secret key key that came out of the BAUTH protocol with the state state. This is the moment. Main character energy. 👑

Expects

  • btokBAuthCTStep4() < btokBAuthCTStepG().

Returns

  • ERR_OK if the key was successfully extracted, and an error code otherwise.

Arguments

  • key — the shared key.
  • state — the state.

size_t btokBAuthT_keep (size_t l)

Same deal as before but for the terminal: this gives you the length of the state (in octets) for the BAUTH protocol functions on the T side. 🎀

Returns

  • The length of the state.

Arguments

  • l — the security level.

err_t btokBAuthTStart (void * state, const bign_params * params, const bake_settings * settings, const octet privkey[], const bake_cert * cert)

From the parameters params, the settings settings, the private key [l / 4]privkey and the certificate cert of the matching public key, this builds up in state all the data structures needed to run BAUTH on the T side. Yes bestie, it's the terminal's turn to get set up. 💜

Precondition

  • btokBAuthT_keep() octets are reserved at the address state.

Expects [ERR_BAD_PARAMS]

  • The parameters params are valid.

Expects [ERR_BAD_INPUT]

  • settings->kca == TRUE.

Expects [ERR_BAD_INPUT]

  • The pointer settings->helloa is null, or the buffer [settings->helloa_len]settings->helloa is valid. Same requirement applies to the fields settings->hellob and settings->hellob_len.

Expects [ERR_BAD_RNG]

  • The generator settings->rng (with state settings->rng_state) is valid.

Expects

  • The generator settings->rng is cryptographically strong.

Expects [ERR_BAD_CERT]

  • The certificate cert is valid.

Expects

  • The key privkey and the certificate cert agree with each other. If that agreement is broken, the protocol will be finished with an error. 💀

Returns

  • ERR_OK if the initialization went through successfully, and an error code otherwise.

Arguments

  • state — the state.
  • params — long-term parameters.
  • settings — the settings.
  • privkey — the private key.
  • cert — the certificate.

err_t btokBAuthTStep3 (octet out[], const octet in[], void * state)

T runs step 3 of BAUTH: it processes the message M1 = [5 l / 8 + 16]in and uses the state state. If the step goes well, the message M2 = [8]out gets formed if authentication in front of T isn't required, or M2 = [8 + 16]out if it is. 🌈

Expects

  • btokBAuthTStart() < btokBAuthTStep3().

Expects

  • btokBAuthCTStep2() << btokBAuthTStep3().

Returns

  • ERR_OK if the step went through successfully, and an error code otherwise.

Arguments

  • out — output message M2.
  • in — input message M1.
  • state — the state.

err_t btokBAuthTStep5 (const octet in[], size_t in_len, bake_certval_i val_ct, void * state)

T runs step 5 of BAUTH: it processes the message M3 = [in_len]in and uses the state state. T checks the CT certificate that got sent in M3 using the function val_ct. Trust but verify, bestie. 🧚

Expects [ERR_BAD_LOGIC]

  • settings->kcb == TRUE, i.e. CT authentication in front of T is required.

Expects

  • btokBAuthTStep3() < btokBAuthTStep5().

Expects

  • btokBAuthCTStep4() << btokBAuthTStep5().

Returns

  • ERR_OK if the step went through successfully, and an error code otherwise.

Arguments

  • in — input message M3.
  • in_len — the length of in.
  • val_ct — the CT certificate verification function.
  • state — the state.

err_t btokBAuthTStepG (octet key[32], void * state)

T works out the shared secret key key that came out of the BAUTH protocol with the state state. 🍓

Expects

  • If the CT authenticates in front of the terminal, then btokBAuthTStep5() < btokBAuthTStepG(), otherwise btokBAuthTStep3() < btokBAuthTStepG().

Returns

ERR_OK if the key was successfully extracted, and an error code otherwise.

Args

  • key — shared key
  • state — state

✨ err_t btokCVCCheck (const btok_cvc_t * cvc) ✨

okay bestie, this one is a whole vibe check for the contents of the cvc CV certificate. It passes if:

  • the strings cvc->authority and cvc->holder are made of printable characters only — no shady bytes, periodt;
  • the lengths of cvc->authority and cvc->holder are between 8 and 12, inclusive;
  • the dates cvc->from and cvc->until are correct, no cap;
  • cvc->from <= cvc->until, as it should be;
  • the public key [cvc->pubkey_len]cvc->pubkey is correct — it has to lie on one of the bign-curveXXXv1 curves.

Returns

ERR_OK if the check passed, and an error code otherwise.

Note

The signature cvc->sig is not checked. So don't come for it.

Args

  • cvc — certificate content

💅 err_t btokCVCCheck2 (const btok_cvc_t * cvc, const btok_cvc_t * cvca) 💅

This one checks the cvc CV certificate content, but it also brings cvca — the (potential) issuer's certificate content — into the mix. It's giving chain validation energy. The check passes if:

  • btokCVCCheck(cvc) == ERR_OK;
  • cvc->authority == cvca->holder;
  • the dates cvca->from and cvca->until are correct;
  • cvca->from <= cvc->from && cvc->from <= cvca->until.

Returns

ERR_OK if the check passed, and an error code otherwise.

Note

Again, cvc->sig is not checked. We're just not looking at it.

Args

  • cvc — certificate content
  • cvca — issuer certificate content

👑 err_t btokCVCIss (octet cert[], size_t * cert_len, btok_cvc_t * cvc, const octet certa[], size_t certa_len, const octet privkeya[], size_t privkeya_len) 👑

Issues a CV certificate [cert_len?]cert with content cvc. It uses the issuer's private key [privkeya_len]privkeya and certificate [certa_len]certa. The signature gets saved into [cvc->sig_len]cvc->sig. Before it even starts, it checks:

  • certa has correct format;
  • btokCVCCheck2(cvc, cvca) == ERR_OK, where cvca is the content of certa;
  • the public key in certa matches the private key privkeya.

Returns

ERR_OK if the certificate was successfully issued, and an error code otherwise.

Note

It uses deterministic signature generation mode. If the standard RNG is initialized, it also uses data from it. So yeah, extra randomness if available.

Args

  • cert — certificate
  • cert_len — length of cert in octets
  • cvc — certificate content
  • certa — issuer certificate
  • certa_len — length of certa in octets
  • privkeya — issuer private key
  • privkeya_len — length of privkeya in octets

🦋 size_t btokCVCLen (const octet der[], size_t count) 🦋

Figures out the exact length of a CV certificate sitting in the prefix of the DER code [count]der. It's like measuring the fit, bestie.

Returns

The length of the certificate, or SIZE_MAX if something went wrong.

Note

It does not check if the CV certificate is correct. So don't trust it blindly.

Args

  • der — DER code
  • count — length of der in octets

🌸 err_t btokCVCMatch (const octet cert[], size_t cert_len, const octet privkey[], size_t privkey_len) 🌸

Checks if the CV certificate [cert_len]cert and the private key [privkey_len]privkey are a match made in heaven. It succeeds if:

  • cert has correct format;
  • the public key of cert corresponds to privkey.

Returns

ERR_OK if the match is confirmed, and an error code otherwise.

Args

  • cert — certificate
  • cert_len — length of cert in octets
  • privkey — private key
  • privkey_len — length of privkey in octets

🎀 err_t btokCVCUnwrap (btok_cvc_t * cvc, const octet cert[], size_t cert_len, const octet pubkey[], size_t pubkey_len) 🎀

Determines and checks the content of the cvc CV certificate [cert_len]cert. It uses the public key [pubkey_len]pubkey for the check. It succeeds if:

  • btokCVCCheck(cvc) == ERR_OK;
  • the signature of cert is recognized as correct on the public key pubkey. You can pass zero length pubkey_len, and then:
    • the signature is not checked if pubkey == 0;
    • the signature is checked on the certificate's public key if pubkey == cvc->pubkey;
    • an error is induced if pubkey != 0 && pubkey != cvc->pubkey.

Returns

ERR_OK if the certificate was successfully parsed, and an error code otherwise.

Note

Even if the signature isn't checked, its length is still controlled. A wrong length is a format error, no cap.

The length of cert must exactly equal cert_len. Otherwise, it's a format error. So precise.

Args

  • cvc — certificate content
  • cert — certificate
  • cert_len — length of cert in octets
  • pubkey — public key
  • pubkey_len — length of pubkey in octets

💖 err_t btokCVCVal (const octet cert[], size_t cert_len, const octet certa[], size_t certa_len, const octet * date) 💖

Checks if the CV certificate [cert_len]cert is correct on the date date, using the issuer certificate [certa_len]certa. It's a whole validation moment. It succeeds if:

  • certa has correct format;
  • cert parses without errors on the public key from certa;
  • btokCVCCheck2(cvc, cvca) == ERR_OK, where cvc and cvca are the contents of cert and certa respectively;
  • date falls within the validity period of cert. The date pointer can be null, and then this last check is skipped.

Returns

ERR_OK if the certificate is recognized as correct, and an error code otherwise.

Note

You can get the current date with tmDate2(). Handy.

Args

  • cert — certificate
  • cert_len — length of cert in octets
  • certa — issuer certificate
  • certa_len — length of certa in octets
  • date — verification date

🌈 err_t btokCVCVal2 (btok_cvc_t * cvc, const octet cert[], size_t cert_len, const btok_cvc_t * cvca, const octet * date) 🌈

Checks if the CV certificate [cert_len]cert is correct on the date date, using the issuer certificate content cvca. On success, it also gives you the content cvc of the certificate being checked. It's giving full service. It succeeds if:

  • cert has correct format;
  • the issuer name in cert matches the owner name in cvca;
  • the signature of cert is recognized as correct on the public key from cvca;
  • the validity period specified in cvca is correct;
  • the start of validity of cert does not go beyond the validity period of cvca;
  • date falls within the validity period of cert. The date pointer can be null, and then this last check is skipped. The cvc pointer can be null, and then the content of the checked certificate is not returned.

Returns

ERR_OK if the certificate is recognized as correct, and an error code otherwise.

Note

You can get the current date with tmDate2().

This interface is built for checking a certificate chain. A chain like certa, certb, certc,... is checked like this:

  • btokCVCUnwrap(cvca, certa, certa_len, 0, 0);
  • btokCVCVal2(cvcb, certb, certb_len, cvca, 0);
  • btokCVCVal2(cvcc, certc, certc_len, cvcb, date);
  • ...

Note

If certa is self-signed and you need to check its signature, then the first line in the previous code should look like this:

  • btokCVCUnwrap(cvca, certa, certa_len, cvca->pubkey, 0);

Args

  • cvc — certificate content
  • cert — certificate
  • cert_len — length of cert in octets
  • cvca — issuer certificate content
  • date — verification date

🦋 err_t btokCVCWrap (octet cert[], size_t * cert_len, btok_cvc_t * cvc, const octet privkey[], size_t privkey_len)

Окей бести, слушай 💖 эта функция буквально создаёт CV-сертификат [cert_len?]cert, а начинка берётся из cvc. Сертификат подписывается на личном ключе [privkey_len]privkey, и подпись уезжает в [cvc->sig_len]cvc->sig. Если cvc->pubkey_len == 0, то открытый ключ [cvc->pubkey_len]cvc->pubkey строится по privkey, и тогда выходной сертификат выступает в роли доказательства владения личным ключом 👑. И ещё: непосредственно перед созданием сертификата содержание cvc проверяется. Проверка завершается успешно, если:

  • btokCVCCheck(cvc) == ERR_OK.

💅 Возвращает

ERR_OK, если сертификат успешно создан, и код ошибки в противном случае.

✨ Прим.

Используется детерминированный режим выработки подписи. Если инициализирован штатный ГСЧ, то дополнительно используются данные от него.

Устанавливая cvc->pubkey_len == 0 && cvc->authority == cvc->holder, можно создать самоподписанный сертификат.

Устанавливая cvc->pubkey_len == 0 && cvc->authority != cvc->holder, можно создать предварительный сертификат, подпись которого будет изменена в дальнейшем стороной cvc->authority. Предварительный сертификат доказывает владение стороной cvc->holder личным ключом, которому соответствует открытый ключ cvc->pubkey. Предварительный сертификат выступает в роли запроса на выпуск сертификата.

🎀 Аргументы

  • cert — сертификат
  • cert_len — длина cert в октетах
  • cvc — содержание сертификата
  • privkey — личный ключ
  • privkey_len — длина privkey в октетах

🍓 bool_t btokPwdTransition (btok_pwd_state * state, btok_pwd_event event)

Парольный автомат с состоянием state обрабатывает событие event. И да, состояние может измениться прямо во время обработки, так что не удивляйся 🙈.

Предусловие

Указатель state корректен.

💖 Возвращает

TRUE, если событие event является допустимым и поэтому обработано, и FALSE в противном случае.

🎀 Аргументы

  • state — состояние
  • event — событие

🌸 size_t btokSM_keep ()

Возвращается длина состояния (в октетах) функций SM. Вот прям столько места тебе надо зарезервировать, ни октетом меньше 💅.

Возвращает

Длина состояния.


🧚 err_t btokSMCmdUnwrap (apdu_cmd_t * cmd, size_t * size, const octet apdu[], size_t count, void * state)

Код команды [count]apdu декодируется, и одновременно с него снимается защита с помощью объектов SM, размещённых в state. Результат возвращается в буфере [size?]cmd. Указатель state может быть нулевым, и тогда выполняется только декодирование, без снятия защиты. Указатель cmd может быть нулевым, и тогда выполняется только проверка формата кода, без контроля целостности. Выбирай свой вайб ✨.

Предусловие

По адресу state зарезервировано btokSM_keep() октетов.

Ожидается

btokSMStart() < btokSMCmdUnwrap()*.

Ожидается [ERR_BAD_APDU]

Если state != 0, то в cmd->cla установлен бит 0x04 (признак защиты). Если state == 0, то бит снят.

Ожидается [ERR_BAD_LOGIC]

Непосредственно в момент снятия защиты (cmd != 0 && state != 0) счётчик SM принимает нечётное значение.

💖 Возвращает

ERR_OK в случае успеха и код ошибки в противном случае.

🎀 Аргументы

  • cmd — команда
  • size — размер буфера для команды
  • apdu — код команды
  • count — длина кода команды
  • state — состояние SM

🦋 err_t btokSMCmdWrap (octet apdu[], size_t * count, const apdu_cmd_t * cmd, void * state)

Команда cmd кодируется и защищается с помощью объектов SM, размещённых в state. Результат возвращается в буфере [count?]apdu. Указатель state может быть нулевым, и тогда выполняется только кодирование, без защиты. Скромненько, но по делу 😌.

Предусловие

По адресу state зарезервировано btokSM_keep() октетов.

Ожидается

btokSMStart() < btokSMCmdWrap()*.

Ожидается [ERR_BAD_APDU]

В cmd->cla снят бит 0x04 (признак защиты).

Ожидается [ERR_BAD_LOGIC]

Непосредственно в момент установки защиты (apdu != 0 && state != 0) счётчик SM принимает нечётное значение.

💖 Возвращает

ERR_OK в случае успеха и код ошибки в противном случае.

🎀 Аргументы

  • apdu — код команды
  • count — длина кода команды
  • cmd — команда
  • state — состояние SM

💜 void btokSMCtrInc (void * state)

Счётчик, размещённый в состоянии state, увеличивается на 1. Просто +1, и всё 🔥.

Предусловие

По адресу state зарезервировано btokSM_keep() октетов.

Ожидается

btokSMStart() < btokSMCtrInc()*.

✨ Прим.

Отправитель команд и ответов должен увеличивать счётчик всякий раз перед установкой их защиты. Соответственно получатель должен увеличивать счётчик всякий раз перед снятием защиты.

Установка и снятие защиты команд должны выполняться с нечётными значениями счётчика. Установка и снятие защиты ответов — с чётными. Чёт-нечет, как в считалочке, но это буквально безопасность, так что не путай 🙏.

🎀 Аргументы

  • state — состояние SM

🌈 err_t btokSMRespUnwrap (apdu_resp_t * resp, size_t * size, const octet apdu[], size_t count, void * state)

Код ответа [count]apdu декодируется, и одновременно с него снимается защита с помощью объектов SM, размещённых в state. Результат возвращается в буфере [size?]resp. Указатель state может быть нулевым, и тогда выполняется только декодирование, без снятия защиты. Указатель resp может быть нулевым, и тогда выполняется только проверка формата кода, без контроля целостности 👑.

Предусловие

По адресу state зарезервировано btokSM_keep() октетов.

Ожидается

btokSMStart() < btokSMRespUnwrap()*.

Ожидается [ERR_BAD_LOGIC]

Непосредственно в момент снятия защиты (resp != 0 && state != 0) счётчик SM принимает чётное значение.

💖 Возвращает

ERR_OK в случае успеха и код ошибки в противном случае.

🎀 Аргументы

  • resp — ответ
  • size — размер буфера для ответа
  • apdu — код ответа
  • count — длина кода ответа
  • state — состояние SM

⭐ err_t btokSMRespWrap (octet apdu[], size_t * count, const apdu_resp_t * resp, void * state)

Ответ resp кодируется и защищается с помощью объектов SM, размещённых в state. Результат возвращается в буфере [count?]apdu. Указатель state может быть нулевым, и тогда выполняется только кодирование, без защиты. Голенький режим, но легальный 💅.

Предусловие

По адресу state зарезервировано btokSM_keep() октетов.

Ожидается

btokSMStart() < btokSMRespWrap()*.

Ожидается [ERR_BAD_LOGIC]

Непосредственно в момент установки защиты (apdu != 0 && state != 0) счётчик SM принимает чётное значение.

💖 Возвращает

ERR_OK в случае успеха и код ошибки в противном случае.

🎀 Аргументы

  • apdu — код ответа
  • count — длина кода ответа
  • resp — ответ
  • state — состояние SM

🧚 void btokSMStart (void * state, const octet key[32])

По ключу key в state формируются объекты, необходимые для управления защищённым соединением. Это типа инициализация, с которой всё начинается ✨.

Предусловие

По адресу state зарезервировано btokSM_keep() октетов.

✨ Прим.

В перечень объектов входит счётчик, первоначально равный нулю.

🎀 Аргументы

  • state — состояние SM
  • key — ключ

👑 Автор

Автоматически создано Doxygen для Библиотека Bee2 из исходного текста. Машина сделала всю работу, а мы просто навели красоту 💖.


И вот мы на финише, бести 🫶 эта страничка — btok.h(3), она из Библиотека Bee2, и дата у неё Вс 25 Янв 2026 00:00:00. Всё, читай, пользуйся, и пусть твои счётчики SM всегда будут нужной чётности 💅✨

📦 where this page comes from