Native cryptography integration
Use M7 C Crypto when a C application needs explicit key, signature or RSA-OAEP operations. This guide describes the 0.3.0 source candidate; consult installation and release status first. No provider registration or network account is required for local operations.
Entry points and algorithms
Include m7crypto.h and use these exported getters:
| Getter | Operations |
|---|---|
get_lib_m7crypto() |
key.load_private_pem, key.load_public_pem, key.load_secret, key.free; family sign/verify; buffer.free |
get_lib_m7crypto_keygen() |
generate, export_private_pem, export_public_pem |
get_lib_m7crypto_encryption() |
rsa_oaep.encrypt, rsa_oaep.decrypt |
The signing tables recognize 18 profiles:
| Table | Exact algorithm identifiers |
|---|---|
rsa |
RS256, RS384, RS512 |
pss |
PS256, PS384, PS512 |
ecdsa |
ES256, ES384, ES512, ES256K |
eddsa |
Ed25519, Ed448 |
hmac |
HS256, HS384, HS512 |
ml_dsa |
ML-DSA-44, ML-DSA-65, ML-DSA-87 |
Select an exact algorithm through trusted application policy. Unknown names,
the ambiguous EdDSA alias, wrong key types and unavailable providers fail;
there is no algorithm fallback. This list is a library contract, not an identity
provider's discovery document or permission to enable an algorithm for a client.
Sign and verify raw message bytes, not a precomputed digest. ECDSA output
is fixed-width R || S, not DER. EdDSA and ML-DSA use pure mode with an empty
context. Inputs and outputs have explicit lengths and may contain NUL bytes.
Minimal sign and verify example
Save as example.c. The key is generated for this example and never printed.
#include <m7crypto.h>
int main(void)
{
const M7CryptoLib *crypto = get_lib_m7crypto();
const M7CryptoKeyGenLib *keygen = get_lib_m7crypto_keygen();
M7CryptoKey *key = NULL;
M7CryptoBuffer signature = {0};
M7CryptoError error = {0};
const char message[] = "example payload";
int result = 1;
if (keygen->generate("RS256", 2048, &key, &error) != M7CRYPTO_OK)
goto cleanup;
if (crypto->rsa.sign(key, "RS256", message, sizeof(message) - 1,
&signature, &error) != M7CRYPTO_OK)
goto cleanup;
if (crypto->rsa.verify(key, "RS256", message, sizeof(message) - 1,
signature.data, signature.length, &error) != M7CRYPTO_OK)
goto cleanup;
result = 0;
cleanup:
crypto->buffer.free(&signature);
crypto->key.free(&key);
return result;
}
With the absolute m7_crypto_prefix established during installation:
cc -std=c11 -Wall -Wextra -I"$m7_crypto_prefix/include" example.c \
-L"$m7_crypto_prefix/lib" -lm7crypto \
-Wl,-rpath,"$m7_crypto_prefix/lib" -o example
./example
Exit status zero means the example verified successfully. In a real verifier, import the expected public key separately and reject every nonzero status.
Import, generate and export keys
Private import accepts unencrypted PKCS#8, RSA PKCS#1 and EC SEC1 PEM.
Public import accepts SPKI (BEGIN PUBLIC KEY), not a certificate or JWK.
Protect or decrypt stored keys before import using your application's key
management policy; the library does not prompt for passwords.
key.load_secret copies raw HMAC secret bytes. Import requires at least 32
bytes; HS384 and HS512 additionally require at least 48 and 64 bytes at use.
Generate these secrets with a cryptographically secure random source. A secret
handle and an asymmetric key are not interchangeable.
generate(algorithm, rsa_bits, &key, &error) supports the 15 asymmetric signing
profiles above and RSA-OAEP-256. RSA accepts 2048, 3072, 4096 or 8192 bits;
zero selects 4096. Other profiles require zero and select their fixed key type
or curve. PS profiles generate ordinary RSA. HMAC generation is not exposed.
PEM export returns exact bytes with no trailing NUL: unencrypted PKCS#8 for
private output and SPKI for public output, capped at 65536 bytes. Public export
accepts a private or public-only asymmetric handle. Public-only keys cannot
export private material, and secret handles cannot export PEM. Protect private
output before storage and release it with buffer.free after use.
RSA-OAEP-256 encryption
Call the encryption getter's rsa_oaep.encrypt or rsa_oaep.decrypt with
(key, "RSA-OAEP-256", input, input_length, &output, &error). Both return a
status and use the same owned-buffer cleanup as signatures.
The profile fixes OAEP SHA-256, MGF1 SHA-256 and an empty label. It accepts
ordinary RSA keys of 2048–8192 bits, rejecting RSA-PSS-restricted, non-RSA and
secret keys. Encryption uses the public part; decryption needs the private key.
The plaintext limit is ceil(key_bits / 8) - 66 bytes (190 for a 2048-bit key);
ciphertext is ceil(key_bits / 8) bytes. Encryption uses fresh OAEP randomness.
Use this for a small secret such as a 32-byte content-encryption key. AES-GCM, JWE serialization, JWT validation and key-selection policy belong to the integrating application. Invalid ciphertext or a wrong decryption key produces the fixed decryption failure, without returning partial plaintext.
Ownership and failures
Initialize key outputs to NULL and buffers to {0}. Occupied outputs are
rejected unchanged. Input pointers are borrowed for the call; imported keys and
secrets become owned native handles. Release keys through key.free(&key) and
successful output through buffer.free(&buffer), including on error cleanup
paths. These functions clear the handle or pointer/length; buffer release also
cleanses its bytes. Do not change a buffer's pointer or length before release,
or give the library a caller-owned buffer to free. Native cleanup does not erase
the caller's original PEM, messages, secrets or copies.
Only M7CRYPTO_OK (0) is success. Other statuses are invalid signature (1),
invalid argument (2), unsupported algorithm (3), invalid key (4), OpenSSL error
(5), out of memory (6), and decryption failed (7). Reject on every nonzero
verification result; malformed signatures can produce an operational error as
well as invalid-signature status. Diagnostics must not include key, secret or
message material. Operations consume the calling thread's OpenSSL error queue.
Immutable function tables may be shared. Keep key handles independently owned by each worker; concurrent use of one handle is outside the supported contract. The library does not validate token issuer, audience, expiration or sender binding, and a successful signature check alone does not authorize a request.
Return to M7 C Crypto.