LCOV - code coverage report
Current view: top level - src/core - crypto.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 63.8 % 260 166
Test Date: 2026-05-06 13:17:06 Functions: 92.3 % 26 24

            Line data    Source code
       1              : /* SPDX-License-Identifier: GPL-3.0-or-later */
       2              : /* Copyright 2026 Peter Csaszar */
       3              : 
       4              : /**
       5              :  * @file crypto.c
       6              :  * @brief Production OpenSSL implementation of crypto.h wrappers.
       7              :  *
       8              :  * Uses EVP interfaces for OpenSSL 3.0+ compatibility.
       9              :  * AES block operations use EVP with ECB mode and no padding.
      10              :  */
      11              : 
      12              : #include "crypto.h"
      13              : 
      14              : #include <openssl/evp.h>
      15              : #include <openssl/rand.h>
      16              : #include <openssl/bn.h>
      17              : #include <openssl/pem.h>
      18              : #include <openssl/err.h>
      19              : #include <openssl/decoder.h>
      20              : #include <openssl/core_names.h>
      21              : #include <openssl/param_build.h>
      22              : #include <limits.h>
      23              : #include <stdio.h>
      24              : #include <stdlib.h>
      25              : #include <string.h>
      26              : 
      27         8634 : void crypto_sha256(const unsigned char *data, size_t len, unsigned char *out) {
      28         8634 :     if (EVP_Digest(data, len, out, NULL, EVP_sha256(), NULL) != 1) {
      29            0 :         fprintf(stderr, "crypto: EVP_Digest(sha256) failed\n");
      30            0 :         abort();
      31              :     }
      32         8634 : }
      33              : 
      34         1420 : int crypto_aes_set_encrypt_key(const unsigned char *key, int bits,
      35              :                                CryptoAesKey *schedule) {
      36         1420 :     size_t key_len = (size_t)bits / 8;
      37         1420 :     memcpy(schedule->key, key, key_len);
      38         1420 :     schedule->bits = bits;
      39         1420 :     return 0;
      40              : }
      41              : 
      42         1404 : int crypto_aes_set_decrypt_key(const unsigned char *key, int bits,
      43              :                                CryptoAesKey *schedule) {
      44         1404 :     size_t key_len = (size_t)bits / 8;
      45         1404 :     memcpy(schedule->key, key, key_len);
      46         1404 :     schedule->bits = bits;
      47         1404 :     return 0;
      48              : }
      49              : 
      50      2864170 : static const EVP_CIPHER *aes_ecb_cipher(int bits) {
      51      2864170 :     if (bits == 128)      return EVP_aes_128_ecb();
      52      2864170 :     else if (bits == 192) return EVP_aes_192_ecb();
      53      2864170 :     else                  return EVP_aes_256_ecb();
      54              : }
      55              : 
      56      1432114 : void crypto_aes_encrypt_block(const unsigned char *in, unsigned char *out,
      57              :                               const CryptoAesKey *schedule) {
      58      1432114 :     EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
      59      1432114 :     if (!ctx) { fprintf(stderr, "OOM: EVP_CIPHER_CTX_new\n"); abort(); }
      60      1432114 :     EVP_EncryptInit_ex(ctx, aes_ecb_cipher(schedule->bits),
      61      1432114 :                        NULL, schedule->key, NULL);
      62      1432114 :     EVP_CIPHER_CTX_set_padding(ctx, 0);
      63              : 
      64      1432114 :     int out_len = 0;
      65      1432114 :     if (EVP_EncryptUpdate(ctx, out, &out_len, in, 16) != 1) {
      66            0 :         fprintf(stderr, "crypto: EVP_EncryptUpdate failed\n");
      67            0 :         abort();
      68              :     }
      69      1432114 :     int final_len = 0;
      70      1432114 :     if (EVP_EncryptFinal_ex(ctx, out + out_len, &final_len) != 1) {
      71            0 :         fprintf(stderr, "crypto: EVP_EncryptFinal_ex failed\n");
      72            0 :         abort();
      73              :     }
      74      1432114 :     EVP_CIPHER_CTX_free(ctx);
      75      1432114 : }
      76              : 
      77      1432056 : void crypto_aes_decrypt_block(const unsigned char *in, unsigned char *out,
      78              :                               const CryptoAesKey *schedule) {
      79      1432056 :     EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
      80      1432056 :     if (!ctx) { fprintf(stderr, "OOM: EVP_CIPHER_CTX_new\n"); abort(); }
      81      1432056 :     EVP_DecryptInit_ex(ctx, aes_ecb_cipher(schedule->bits),
      82      1432056 :                        NULL, schedule->key, NULL);
      83      1432056 :     EVP_CIPHER_CTX_set_padding(ctx, 0);
      84              : 
      85      1432056 :     int out_len = 0;
      86      1432056 :     if (EVP_DecryptUpdate(ctx, out, &out_len, in, 16) != 1) {
      87            0 :         fprintf(stderr, "crypto: EVP_DecryptUpdate failed\n");
      88            0 :         abort();
      89              :     }
      90      1432056 :     int final_len = 0;
      91      1432056 :     if (EVP_DecryptFinal_ex(ctx, out + out_len, &final_len) != 1) {
      92            0 :         fprintf(stderr, "crypto: EVP_DecryptFinal_ex failed\n");
      93            0 :         abort();
      94              :     }
      95      1432056 :     EVP_CIPHER_CTX_free(ctx);
      96      1432056 : }
      97              : 
      98         3316 : int crypto_rand_bytes(unsigned char *buf, size_t len) {
      99              :     /* QA-18: guard against size_t → int truncation that would leave the
     100              :      * tail of `buf` uninitialized. The project never asks for > INT_MAX
     101              :      * bytes in practice, so treat it as an impossible condition and abort,
     102              :      * matching the project's abort-on-impossible policy. */
     103         3316 :     if (len > INT_MAX) {
     104            0 :         fprintf(stderr, "crypto_rand_bytes: len too large\n");
     105            0 :         abort();
     106              :     }
     107         3316 :     return RAND_bytes(buf, (int)len) == 1 ? 0 : -1;
     108              : }
     109              : 
     110              : /* ---- SHA-1 ---- */
     111              : 
     112         2034 : void crypto_sha1(const unsigned char *data, size_t len, unsigned char *out) {
     113         2034 :     if (EVP_Digest(data, len, out, NULL, EVP_sha1(), NULL) != 1) {
     114            0 :         fprintf(stderr, "crypto: EVP_Digest(sha1) failed\n");
     115            0 :         abort();
     116              :     }
     117         2034 : }
     118              : 
     119            4 : void crypto_sha512(const unsigned char *data, size_t len, unsigned char *out) {
     120            4 :     if (EVP_Digest(data, len, out, NULL, EVP_sha512(), NULL) != 1) {
     121            0 :         fprintf(stderr, "crypto: EVP_Digest(sha512) failed\n");
     122            0 :         abort();
     123              :     }
     124            4 : }
     125              : 
     126           44 : int crypto_pbkdf2_hmac_sha512(const unsigned char *password, size_t password_len,
     127              :                               const unsigned char *salt, size_t salt_len,
     128              :                               int iters,
     129              :                               unsigned char *out, size_t out_len) {
     130           44 :     if (!password || !salt || !out || out_len == 0 || iters <= 0) return -1;
     131           38 :     if (password_len > INT_MAX || salt_len > INT_MAX || out_len > INT_MAX)
     132            0 :         return -1;
     133           38 :     int rc = PKCS5_PBKDF2_HMAC((const char *)password, (int)password_len,
     134              :                                 salt, (int)salt_len, iters,
     135              :                                 EVP_sha512(), (int)out_len, out);
     136           38 :     return rc == 1 ? 0 : -1;
     137              : }
     138              : 
     139              : /* ---- RSA (OpenSSL 3.0 EVP API) ---- */
     140              : 
     141              : struct CryptoRsaKey {
     142              :     EVP_PKEY *pkey;
     143              : };
     144              : 
     145              : /*
     146              :  * Load an RSA public key from PEM, supporting both formats:
     147              :  *   "-----BEGIN PUBLIC KEY-----"     (PKCS#8 SubjectPublicKeyInfo)
     148              :  *   "-----BEGIN RSA PUBLIC KEY-----" (PKCS#1 RSAPublicKey)
     149              :  * Uses OSSL_DECODER which handles both transparently (OpenSSL 3.0+).
     150              :  * Returns NULL on failure; caller should check ERR queue for diagnostics.
     151              :  */
     152            8 : static EVP_PKEY *rsa_public_pkey_from_pem(const char *pem) {
     153            8 :     EVP_PKEY *pkey = NULL;
     154            8 :     OSSL_DECODER_CTX *dctx = OSSL_DECODER_CTX_new_for_pkey(
     155              :         &pkey, "PEM", NULL, "RSA",
     156              :         OSSL_KEYMGMT_SELECT_PUBLIC_KEY, NULL, NULL);
     157            8 :     if (!dctx) return NULL;
     158              : 
     159            8 :     BIO *bio = BIO_new_mem_buf(pem, (int)strlen(pem));
     160            8 :     if (!bio) { OSSL_DECODER_CTX_free(dctx); return NULL; }
     161              : 
     162            8 :     int ok = OSSL_DECODER_from_bio(dctx, bio);
     163            8 :     OSSL_DECODER_CTX_free(dctx);
     164            8 :     BIO_free(bio);
     165            8 :     return ok ? pkey : NULL;
     166              : }
     167              : 
     168            8 : CryptoRsaKey *crypto_rsa_load_public(const char *pem) {
     169            8 :     if (!pem) return NULL;
     170              : 
     171            8 :     EVP_PKEY *pkey = rsa_public_pkey_from_pem(pem);
     172            8 :     if (!pkey) return NULL;
     173              : 
     174            8 :     CryptoRsaKey *key = (CryptoRsaKey *)calloc(1, sizeof(CryptoRsaKey));
     175            8 :     if (!key) { EVP_PKEY_free(pkey); return NULL; }
     176            8 :     key->pkey = pkey;
     177            8 :     return key;
     178              : }
     179              : 
     180           10 : void crypto_rsa_free(CryptoRsaKey *key) {
     181           10 :     if (key) {
     182           10 :         EVP_PKEY_free(key->pkey);
     183           10 :         free(key);
     184              :     }
     185           10 : }
     186              : 
     187            2 : CryptoRsaKey *crypto_rsa_load_private(const char *pem) {
     188            2 :     if (!pem) return NULL;
     189              : 
     190            2 :     BIO *bio = BIO_new_mem_buf(pem, (int)strlen(pem));
     191            2 :     if (!bio) return NULL;
     192              : 
     193            2 :     EVP_PKEY *pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
     194            2 :     BIO_free(bio);
     195              : 
     196            2 :     if (!pkey) return NULL;
     197              : 
     198            2 :     CryptoRsaKey *key = (CryptoRsaKey *)calloc(1, sizeof(CryptoRsaKey));
     199            2 :     if (!key) { EVP_PKEY_free(pkey); return NULL; }
     200            2 :     key->pkey = pkey;
     201            2 :     return key;
     202              : }
     203              : 
     204            2 : int crypto_rsa_private_decrypt(CryptoRsaKey *key, const unsigned char *data,
     205              :                                size_t data_len, unsigned char *out, size_t *out_len) {
     206            2 :     if (!key || !data || !out || !out_len) return -1;
     207              : 
     208            2 :     EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key->pkey, NULL);
     209            2 :     if (!ctx) return -1;
     210              : 
     211            2 :     if (EVP_PKEY_decrypt_init(ctx) <= 0) {
     212            0 :         EVP_PKEY_CTX_free(ctx);
     213            0 :         return -1;
     214              :     }
     215              : 
     216              :     /* RSA_NO_PADDING — mirrors the RSA_PAD scheme used by the client */
     217            2 :     if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) {
     218            0 :         EVP_PKEY_CTX_free(ctx);
     219            0 :         return -1;
     220              :     }
     221              : 
     222            2 :     if (EVP_PKEY_decrypt(ctx, out, out_len, data, data_len) <= 0) {
     223            0 :         EVP_PKEY_CTX_free(ctx);
     224            0 :         return -1;
     225              :     }
     226              : 
     227            2 :     EVP_PKEY_CTX_free(ctx);
     228            2 :     return 0;
     229              : }
     230              : 
     231            8 : int crypto_rsa_public_encrypt(CryptoRsaKey *key, const unsigned char *data,
     232              :                               size_t data_len, unsigned char *out, size_t *out_len) {
     233            8 :     if (!key || !data || !out || !out_len) return -1;
     234              : 
     235            8 :     EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(key->pkey, NULL);
     236            8 :     if (!ctx) return -1;
     237              : 
     238            8 :     if (EVP_PKEY_encrypt_init(ctx) <= 0) {
     239            0 :         EVP_PKEY_CTX_free(ctx);
     240            0 :         return -1;
     241              :     }
     242              : 
     243              :     /* RSA_NO_PADDING — Telegram uses its own RSA_PAD scheme on top */
     244            8 :     if (EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_NO_PADDING) <= 0) {
     245            0 :         EVP_PKEY_CTX_free(ctx);
     246            0 :         return -1;
     247              :     }
     248              : 
     249            8 :     if (EVP_PKEY_encrypt(ctx, out, out_len, data, data_len) <= 0) {
     250            0 :         EVP_PKEY_CTX_free(ctx);
     251            0 :         return -1;
     252              :     }
     253              : 
     254            8 :     EVP_PKEY_CTX_free(ctx);
     255            8 :     return 0;
     256              : }
     257              : 
     258              : /* ---- RSA fingerprint ---- */
     259              : 
     260              : /*
     261              :  * Telegram fingerprint: lower 64 bits (little-endian) of
     262              :  *   SHA1( TL_bytes(n_BE) || TL_bytes(e_BE) )
     263              :  *
     264              :  * TL bytes encoding: short form (len < 254) = 1-byte-len + data + 4-byte-pad;
     265              :  *                    long  form (len >= 254) = 0xFE + 3-byte-LE-len + data + pad.
     266              :  *
     267              :  * Supports both PKCS#1 ("BEGIN RSA PUBLIC KEY") and
     268              :  * PKCS#8 ("BEGIN PUBLIC KEY") PEM formats.
     269              :  * Uses the OpenSSL 3.0 EVP / OSSL_PARAM API throughout — no deprecated calls.
     270              :  */
     271            0 : int crypto_rsa_fingerprint(const char *pem, uint64_t *out) {
     272            0 :     if (!pem || !out) return -1;
     273              : 
     274            0 :     ERR_clear_error();
     275            0 :     EVP_PKEY *pkey = rsa_public_pkey_from_pem(pem);
     276            0 :     if (!pkey) {
     277            0 :         unsigned long e = ERR_peek_last_error();
     278            0 :         fprintf(stderr,
     279              :                 "crypto_rsa_fingerprint: PEM parse failed%s%s\n"
     280              :                 "  Accepted formats: \"BEGIN PUBLIC KEY\" (PKCS#8) or "
     281              :                 "\"BEGIN RSA PUBLIC KEY\" (PKCS#1)\n",
     282              :                 e ? ": " : "",
     283            0 :                 e ? ERR_reason_error_string(e) : "");
     284            0 :         return -1;
     285              :     }
     286              : 
     287              :     /* Extract n and e as BIGNUMs using the provider-neutral OSSL_PARAM API. */
     288            0 :     BIGNUM *n = NULL, *e = NULL;
     289            0 :     if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &n) != 1 ||
     290            0 :         EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &e) != 1) {
     291            0 :         BN_free(n);
     292            0 :         BN_free(e);
     293            0 :         EVP_PKEY_free(pkey);
     294            0 :         return -1;
     295              :     }
     296            0 :     EVP_PKEY_free(pkey);
     297              : 
     298            0 :     int n_len = BN_num_bytes(n);
     299            0 :     int e_len = BN_num_bytes(e);
     300            0 :     if (n_len <= 0 || e_len <= 0) {
     301            0 :         BN_free(n); BN_free(e);
     302            0 :         return -1;
     303              :     }
     304              : 
     305              :     /*
     306              :      * TL bytes encoding of RSAPublicKey { n:bytes, e:bytes }.
     307              :      * Short form (len < 254): [1-byte len][data][pad to 4-byte boundary].
     308              :      * Long form  (len >= 254): [0xFE][3-byte LE len][data][pad to 4 bytes].
     309              :      */
     310              :     /* n: long form (typically 256 bytes) — (4 + 256) = 260, already 4-aligned */
     311              :     /* e: short form (typically 3 bytes)  — (1 + 3)   =   4, already 4-aligned */
     312            0 :     size_t n_hdr = (n_len < 254) ? 1 : 4;
     313            0 :     size_t e_hdr = (e_len < 254) ? 1 : 4;
     314            0 :     size_t n_block = n_hdr + (size_t)n_len;
     315            0 :     size_t e_block = e_hdr + (size_t)e_len;
     316              :     /* Pad each block to a 4-byte boundary. */
     317            0 :     n_block = (n_block + 3) & ~(size_t)3;
     318            0 :     e_block = (e_block + 3) & ~(size_t)3;
     319              : 
     320            0 :     size_t buf_len = n_block + e_block;
     321            0 :     unsigned char *buf = calloc(1, buf_len);  /* calloc fills padding with 0 */
     322            0 :     if (!buf) { BN_free(n); BN_free(e); return -1; }
     323              : 
     324              :     /* Encode n */
     325            0 :     if (n_len < 254) {
     326            0 :         buf[0] = (unsigned char)n_len;
     327            0 :         BN_bn2bin(n, buf + 1);
     328              :     } else {
     329            0 :         buf[0] = 0xFE;
     330            0 :         buf[1] = (unsigned char)(n_len & 0xFF);
     331            0 :         buf[2] = (unsigned char)((n_len >> 8) & 0xFF);
     332            0 :         buf[3] = (unsigned char)((n_len >> 16) & 0xFF);
     333            0 :         BN_bn2bin(n, buf + 4);
     334              :     }
     335              : 
     336              :     /* Encode e */
     337            0 :     size_t off = n_block;
     338            0 :     if (e_len < 254) {
     339            0 :         buf[off] = (unsigned char)e_len;
     340            0 :         BN_bn2bin(e, buf + off + 1);
     341              :     } else {
     342            0 :         buf[off]     = 0xFE;
     343            0 :         buf[off + 1] = (unsigned char)(e_len & 0xFF);
     344            0 :         buf[off + 2] = (unsigned char)((e_len >> 8) & 0xFF);
     345            0 :         buf[off + 3] = (unsigned char)((e_len >> 16) & 0xFF);
     346            0 :         BN_bn2bin(e, buf + off + 4);
     347              :     }
     348              : 
     349            0 :     BN_free(n);
     350            0 :     BN_free(e);
     351              : 
     352              :     /* SHA1 → take lower 64 bits (last 8 bytes of 20-byte digest). */
     353              :     unsigned char sha1_out[20];
     354            0 :     crypto_sha1(buf, buf_len, sha1_out);
     355            0 :     free(buf);
     356              : 
     357              :     /* Lower 64 bits = bytes [12..19] interpreted as little-endian. */
     358            0 :     uint64_t fp = 0;
     359            0 :     for (int i = 0; i < 8; i++) {
     360            0 :         fp |= ((uint64_t)sha1_out[12 + i]) << (8 * i);
     361              :     }
     362            0 :     *out = fp;
     363            0 :     return 0;
     364              : }
     365              : 
     366              : /* ---- Big Number Arithmetic ---- */
     367              : 
     368              : struct CryptoBnCtx {
     369              :     BN_CTX *ctx;
     370              : };
     371              : 
     372           32 : CryptoBnCtx *crypto_bn_ctx_new(void) {
     373           32 :     CryptoBnCtx *c = (CryptoBnCtx *)calloc(1, sizeof(CryptoBnCtx));
     374           32 :     if (!c) return NULL;
     375           32 :     c->ctx = BN_CTX_new();
     376           32 :     if (!c->ctx) { free(c); return NULL; }
     377           32 :     return c;
     378              : }
     379              : 
     380           32 : void crypto_bn_ctx_free(CryptoBnCtx *ctx) {
     381           32 :     if (ctx) {
     382           32 :         BN_CTX_free(ctx->ctx);
     383           32 :         free(ctx);
     384              :     }
     385           32 : }
     386              : 
     387          102 : int crypto_bn_mod_exp(unsigned char *result, size_t *res_len,
     388              :                       const unsigned char *base, size_t base_len,
     389              :                       const unsigned char *exp, size_t exp_len,
     390              :                       const unsigned char *mod, size_t mod_len,
     391              :                       CryptoBnCtx *ctx) {
     392          102 :     if (!result || !res_len || !base || !exp || !mod || !ctx) return -1;
     393              : 
     394          102 :     BIGNUM *bn_base = BN_bin2bn(base, (int)base_len, NULL);
     395          102 :     BIGNUM *bn_exp  = BN_bin2bn(exp, (int)exp_len, NULL);
     396          102 :     BIGNUM *bn_mod  = BN_bin2bn(mod, (int)mod_len, NULL);
     397          102 :     BIGNUM *bn_res  = BN_new();
     398              : 
     399          102 :     if (!bn_base || !bn_exp || !bn_mod || !bn_res) {
     400            0 :         BN_free(bn_base); BN_free(bn_exp); BN_free(bn_mod); BN_free(bn_res);
     401            0 :         return -1;
     402              :     }
     403              : 
     404          102 :     int rc = BN_mod_exp(bn_res, bn_base, bn_exp, bn_mod, ctx->ctx);
     405          102 :     if (rc != 1) {
     406            0 :         BN_free(bn_base); BN_free(bn_exp); BN_free(bn_mod); BN_free(bn_res);
     407            0 :         return -1;
     408              :     }
     409              : 
     410          102 :     int bytes = BN_num_bytes(bn_res);
     411          102 :     if ((size_t)bytes > *res_len) {
     412            0 :         BN_free(bn_base); BN_free(bn_exp); BN_free(bn_mod); BN_free(bn_res);
     413            0 :         return -1;
     414              :     }
     415              : 
     416              :     /* Left-pad with zeros to fill mod_len */
     417          102 :     size_t actual = (size_t)bytes;
     418          102 :     if (actual < mod_len) {
     419            2 :         memset(result, 0, mod_len - actual);
     420              :     }
     421          102 :     BN_bn2bin(bn_res, result + (mod_len - actual));
     422          102 :     *res_len = mod_len;
     423              : 
     424          102 :     BN_free(bn_base); BN_free(bn_exp); BN_free(bn_mod); BN_free(bn_res);
     425          102 :     return 0;
     426              : }
     427              : 
     428              : /* Shared epilogue for mod_mul/add/sub: BN_bn2bin() into left-padded out. */
     429           58 : static int bn_op_finalize(BIGNUM *bn_res,
     430              :                            unsigned char *out, size_t *out_len,
     431              :                            size_t pad_len) {
     432           58 :     int bytes = BN_num_bytes(bn_res);
     433           58 :     if ((size_t)bytes > *out_len) return -1;
     434           58 :     size_t actual = (size_t)bytes;
     435           58 :     if (actual < pad_len) memset(out, 0, pad_len - actual);
     436           58 :     BN_bn2bin(bn_res, out + (pad_len - actual));
     437           58 :     *out_len = pad_len;
     438           58 :     return 0;
     439              : }
     440              : 
     441              : typedef int (*bn_bin_op)(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
     442              :                           const BIGNUM *m, BN_CTX *ctx);
     443              : 
     444           58 : static int bn_mod_op(bn_bin_op op,
     445              :                       unsigned char *result, size_t *res_len,
     446              :                       const unsigned char *a, size_t a_len,
     447              :                       const unsigned char *b, size_t b_len,
     448              :                       const unsigned char *m, size_t m_len,
     449              :                       CryptoBnCtx *ctx) {
     450           58 :     if (!result || !res_len || !a || !b || !m || !ctx) return -1;
     451           58 :     BIGNUM *ba = BN_bin2bn(a, (int)a_len, NULL);
     452           58 :     BIGNUM *bb = BN_bin2bn(b, (int)b_len, NULL);
     453           58 :     BIGNUM *bm = BN_bin2bn(m, (int)m_len, NULL);
     454           58 :     BIGNUM *br = BN_new();
     455           58 :     int rc = -1;
     456           58 :     if (ba && bb && bm && br && op(br, ba, bb, bm, ctx->ctx) == 1) {
     457           58 :         rc = bn_op_finalize(br, result, res_len, m_len);
     458              :     }
     459           58 :     BN_free(ba); BN_free(bb); BN_free(bm); BN_free(br);
     460           58 :     return rc;
     461              : }
     462              : 
     463           38 : int crypto_bn_mod_mul(unsigned char *result, size_t *res_len,
     464              :                        const unsigned char *a, size_t a_len,
     465              :                        const unsigned char *b, size_t b_len,
     466              :                        const unsigned char *m, size_t m_len,
     467              :                        CryptoBnCtx *ctx) {
     468           38 :     return bn_mod_op(BN_mod_mul, result, res_len,
     469              :                       a, a_len, b, b_len, m, m_len, ctx);
     470              : }
     471              : 
     472            0 : int crypto_bn_mod_add(unsigned char *result, size_t *res_len,
     473              :                        const unsigned char *a, size_t a_len,
     474              :                        const unsigned char *b, size_t b_len,
     475              :                        const unsigned char *m, size_t m_len,
     476              :                        CryptoBnCtx *ctx) {
     477            0 :     return bn_mod_op(BN_mod_add, result, res_len,
     478              :                       a, a_len, b, b_len, m, m_len, ctx);
     479              : }
     480              : 
     481           20 : int crypto_bn_mod_sub(unsigned char *result, size_t *res_len,
     482              :                        const unsigned char *a, size_t a_len,
     483              :                        const unsigned char *b, size_t b_len,
     484              :                        const unsigned char *m, size_t m_len,
     485              :                        CryptoBnCtx *ctx) {
     486           20 :     return bn_mod_op(BN_mod_sub, result, res_len,
     487              :                       a, a_len, b, b_len, m, m_len, ctx);
     488              : }
     489              : 
     490            6 : int crypto_bn_ucmp(const unsigned char *a, size_t a_len,
     491              :                     const unsigned char *b, size_t b_len) {
     492            6 :     BIGNUM *ba = BN_bin2bn(a, (int)a_len, NULL);
     493            6 :     BIGNUM *bb = BN_bin2bn(b, (int)b_len, NULL);
     494            6 :     int r = 0;
     495            6 :     if (ba && bb) r = BN_ucmp(ba, bb);
     496            6 :     BN_free(ba); BN_free(bb);
     497            6 :     return r < 0 ? -1 : (r > 0 ? 1 : 0);
     498              : }
        

Generated by: LCOV version 2.0-1