btok.h(3)
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 eventerr_t btokCVCCheck (const btok_cvc_t *cvc)— check the content of a CV certificateerr_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 accounterr_t btokCVCWrap (octet cert[], size_t *cert_len, btok_cvc_t *cvc, const octet privkey[], size_t privkey_len)— create a CV certificateerr_t btokCVCUnwrap (btok_cvc_t *cvc, const octet cert[], size_t cert_len, const octet pubkey[], size_t pubkey_len)— parse a CV certificateerr_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 certificatesize_t btokCVCLen (const octet der[], size_t count)— the exact length of a CV certificateerr_t btokCVCVal (const octet cert[], size_t cert_len, const octet certa[], size_t certa_len, const octet *date)— verify a CV certificateerr_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 chainerr_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 matchsize_t btokSM_keep ()— the length of the SM statevoid btokSMStart (void *state, const octet key[32])— initialise the SM functionsvoid btokSMCtrInc (void *state)— bump the SM countererr_t btokSMCmdWrap (octet apdu[], size_t *count, const apdu_cmd_t *cmd, void *state)— encode a command and slap SM protection on iterr_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 iterr_t btokSMRespWrap (octet apdu[], size_t *count, const apdu_resp_t *resp, void *state)— encode a response and slap SM protection on iterr_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 itsize_t btokBAuthT_keep (size_t l)— the length of the BAUTH state on the T sideerr_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 sidesize_t btokBAuthCT_keep (size_t l)— the length of the BAUTH state on the CT sideerr_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 sideerr_t btokBAuthCTStep2 (octet out[], const bake_cert *certt, void *state)— step 2 of the BAUTH protocolerr_t btokBAuthTStep3 (octet out[], const octet in[], void *state)— step 3 of the BAUTH protocolerr_t btokBAuthCTStep4 (octet out[], const octet in[], void *state)— step 4 of the BAUTH protocolerr_t btokBAuthTStep5 (const octet in[], size_t in_len, bake_certval_i val_ct, void *state)— step 5 of the BAUTH protocolerr_t btokBAuthCTStepG (octet key[32], void *state)— pull the BAUTH protocol key out on the CT sideerr_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?]ptrconstruct 👑
📜 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-curve384v1andbign-curve512v1🔢 - use of
bign-signalgorithms to generate and verify signatures ✍️ - use of
belt-hash,bash384,bash512algorithms to hash the data being signed 🧬 - optional use of a 5-octet access-rights word for the
eIdapplication program 🪪 - optional use of a 2-octet access-rights word for the
eSignapplication 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
0x04in theCLAfield.
🫶 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 addressstate.
Expects [ERR_BAD_PARAMS]
- The parameters
paramsare valid.
Expects [ERR_BAD_INPUT]
settings->kca == TRUE.
Expects [ERR_BAD_INPUT]
- The pointer
settings->helloais null, or the buffer[settings->helloa_len]settings->helloais valid. Same exact energy for the fieldssettings->hellobandsettings->hellob_len.
Expects [ERR_BAD_RNG]
- The generator
settings->rng(with statesettings->rng_state) is valid.
Expects
- The generator
settings->rngis cryptographically strong. No mid RNGs allowed in this house. 🔥
Expects [ERR_BAD_CERT]
- The certificate
certis valid.
Expects
- The key
privkeyand the certificatecertagree with each other. If that agreement is broken, the protocol is going to finish with an error. 😭
Returns
ERR_OKif 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_OKif 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_OKif 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_OKif 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 addressstate.
Expects [ERR_BAD_PARAMS]
- The parameters
paramsare valid.
Expects [ERR_BAD_INPUT]
settings->kca == TRUE.
Expects [ERR_BAD_INPUT]
- The pointer
settings->helloais null, or the buffer[settings->helloa_len]settings->helloais valid. Same requirement applies to the fieldssettings->hellobandsettings->hellob_len.
Expects [ERR_BAD_RNG]
- The generator
settings->rng(with statesettings->rng_state) is valid.
Expects
- The generator
settings->rngis cryptographically strong.
Expects [ERR_BAD_CERT]
- The certificate
certis valid.
Expects
- The key
privkeyand the certificatecertagree with each other. If that agreement is broken, the protocol will be finished with an error. 💀
Returns
ERR_OKif 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_OKif 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_OKif the step went through successfully, and an error code otherwise.
Arguments
in— input message M3.in_len— the length ofin.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(), otherwisebtokBAuthTStep3() < btokBAuthTStepG().
Returns
ERR_OK if the key was successfully extracted, and an error code otherwise.
Args
key— shared keystate— 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->authorityandcvc->holderare made of printable characters only — no shady bytes, periodt; - the lengths of
cvc->authorityandcvc->holderare between 8 and 12, inclusive; - the dates
cvc->fromandcvc->untilare correct, no cap; cvc->from <= cvc->until, as it should be;- the public key
[cvc->pubkey_len]cvc->pubkeyis correct — it has to lie on one of thebign-curveXXXv1curves.
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->fromandcvca->untilare 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 contentcvca— 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:
certahas correct format;btokCVCCheck2(cvc, cvca) == ERR_OK, wherecvcais the content ofcerta;- the public key in
certamatches the private keyprivkeya.
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— certificatecert_len— length ofcertin octetscvc— certificate contentcerta— issuer certificatecerta_len— length ofcertain octetsprivkeya— issuer private keyprivkeya_len— length ofprivkeyain 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 codecount— length ofderin 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:
certhas correct format;- the public key of
certcorresponds toprivkey.
Returns
ERR_OK if the match is confirmed, and an error code otherwise.
Args
cert— certificatecert_len— length ofcertin octetsprivkey— private keyprivkey_len— length ofprivkeyin 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
certis recognized as correct on the public keypubkey. You can pass zero lengthpubkey_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.
- the signature is not checked if
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 contentcert— certificatecert_len— length ofcertin octetspubkey— public keypubkey_len— length ofpubkeyin 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:
certahas correct format;certparses without errors on the public key fromcerta;btokCVCCheck2(cvc, cvca) == ERR_OK, wherecvcandcvcaare the contents ofcertandcertarespectively;datefalls within the validity period ofcert. Thedatepointer 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— certificatecert_len— length ofcertin octetscerta— issuer certificatecerta_len— length ofcertain octetsdate— 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:
certhas correct format;- the issuer name in
certmatches the owner name incvca; - the signature of
certis recognized as correct on the public key fromcvca; - the validity period specified in
cvcais correct; - the start of validity of
certdoes not go beyond the validity period ofcvca; datefalls within the validity period ofcert. Thedatepointer can be null, and then this last check is skipped. Thecvcpointer 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 contentcert— certificatecert_len— length ofcertin octetscvca— issuer certificate contentdate— 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— состояние SMkey— ключ
👑 Автор
Автоматически создано Doxygen для Библиотека Bee2 из исходного текста. Машина сделала всю работу, а мы просто навели красоту 💖.
И вот мы на финише, бести 🫶 эта страничка — btok.h(3), она из Библиотека Bee2, и дата у неё Вс 25 Янв 2026 00:00:00. Всё, читай, пользуйся, и пусть твои счётчики SM всегда будут нужной чётности 💅✨
📦 where this page comes from
- fedora 44: bee2-devel 2.2.0-1.fc44 · GPL-3.0-only and GPL-3.0-or-later
- fedora 44: bee2-devel 2.2.0-1.fc44 · GPL-3.0-only and GPL-3.0-or-later
- 💖 girlified by deepseek-ai/DeepSeek-V4.1-Flash on : a language model's rewrite of the original, under its terms