NEWS


zucrypt 0.1.0

First release, and the first on CRAN. A focused set of cryptographic primitives over raw vectors, backed by a vendored, pinned crypto library, published to R and to C. The seven R functions are stable, and the static archive is frozen as ABI 1, after its first consumer -- zuxlsx's decryption of password-protected workbooks -- was built and tested against it. The registered table is experimental (see "C interface" below).

R interface

Seven functions, and deliberately no more:

Failures are R conditions classed c(<specific>, "zucrypt_error", "error", "condition"), mapped from the C status by enumerator name rather than by number. Every condition carries algorithm and native_status fields; for AES, algorithm names the cipher ("aes-256-cbc"), or "aes-cbc" when the key is what is wrong. No message ever contains a key, an IV or plaintext.

Fixed before the tag, from the package review in #51:

Renamed before release (#56): the CBC pair was crypt_aes_cbc_encrypt() and crypt_aes_cbc_decrypt() during development. The _nopad suffix names the difference from openssl::aes_cbc_encrypt(), which pads, so that code moved from openssl by changing a prefix can never silently get the padding back as plaintext. The unsuffixed names are reserved for an openssl-compatible padded pair. The C interface (zuc_aes_*()) is unchanged.

C interface

Both shapes the zu* family consumes siblings by, at ZUCRYPT_ABI_VERSION 1, with different stability (?zucrypt_c_api):

Settled before the freeze, from the first consumer's report (#43):

inst/include/zucrypt.h compiles standalone as C99 against <stddef.h> and <stdint.h>, and names no backend type: a consumer never has to reproduce this package's build configuration.

Both shapes are exercised on Linux, macOS and Windows by consumer fixture packages, as a real consumer would use them:

The archive fixture's checks cover:

Settled before any consumer linked the ABI (design revision 3):

Backend

Vendored TF-PSA-Crypto 1.1.1, an LTS release, trimmed to 113 files — the dependency closure of the sources that carry a symbol under this package's configuration. Installation needs a C99 compiler and nothing else: no system cryptographic library, no CMake, no Python or Perl, and no network access.

AES runs on the CPU's AES instructions — AES-NI on x86, the Cryptography Extension on 64-bit Arm — chosen at run time, and on a software fallback where the CPU has neither. The backend's own security policy warns that the software fallback leaks key material through cache timing; crypt_info()$build_flags$aes_implementation reports which path a machine uses, and ?crypt_aes_cbc_nopad explains when that matters. Every path produces the same bytes. (Until the review in #51 hardware AES was off everywhere.)

Upstream symbols are hidden. The installed shared object exports exactly one symbol, R_init_zucrypt, so an independently vendored copy of the same library in another package cannot bind to this one, and no OpenSSL-ABI name is exported beside the libcrypto other packages link.

Supported platforms

Checked on every push: Linux, macOS (ARM64) and Windows; R release, oldrel-1 and 4.1; CRAN's clang-23 and GCC-16 containers; the no-Suggests flavour; LTO; rchk and gctorture; ASan, UBSan, valgrind and GCC's -fanalyzer. Weekly: i386, musl and aarch64 builds that run the test suite and fail on a WARNING, and a sweep that fails each allocation the crypt_*() calls make, one run per allocation — about 250 of them, of which some 77 land in zucrypt's own code — checking that each surfaces as an error rather than a crash or a wrong answer.

Correctness is checked against published vectors — FIPS 180-2, RFC 2202, RFC 4231, RFC 6234 and NIST SP 800-38A, including the one-million-byte messages and HMAC keys longer than the block — every one of which is also recomputed with OpenSSL, an implementation sharing no code with the vendored backend. Inputs up to 4 MiB are compared with OpenSSL directly, and the iterated hash Office agile encryption uses is checked against msoffcrypto-tool.

Not in this release

Deliberate omissions, each waiting on a concrete consumer rather than on effort: authenticated encryption, password-based key derivation (PBKDF2, HKDF, Argon2), random byte generation, signatures, key serialization, file hashing and connection wrappers. There is no encrypt_file(password = ), and there will not be one without a specified authenticated format, a nonce policy and a key derivation step.

Office/Excel decryption is not here either. It belongs to zuxlsx, which consumes this package.