Digital signing and verification

Updated: April 19, 2023

The qcrypto library API includes functions that provide cryptographic signing and verification primitives. Several forms are provided to give you the flexibility of using one that is best suited to your needs.

Cryptographic signatures are useful for protecting assets by allowing an asset's integrity to be verified before it is used. Systems often use these signatures for code signing in secure boot environments.

See the library reference for detailed descriptions of the signing and verification functions.

General signature:
Signature signing:
Signature verification:
Signature size:

DSA and ECDSA signature size

For DSA and ECDSA, the signature size returned can be larger than the result signature because of the random number generation chosen as part of the algorithm (which is also why these signatures differ each time). The qcrypto_signature_sigsize() function returns the largest buffer required to make the signature fit if the client code wants to allocate space. The client should rely on the final size as returned by the qcrypto_signature_sign*() functions.

RSA signatures PSS padding mode

When using RSA PSS padding, the salt size should be equal to or longer than the digest length used for signing. When verifying, the salt size must be provided for verification to succeed.
The qcrypto.h header file provides the following preprocessor definitions to make meeting this requirement simpler: QCRYPTO_RSA_PSS_SALT_DIGEST_SIZE (salt length equals digest algorithm length) and QCRYPTO_RSA_PSS_SALT_MAX_SIZE.

Signature examples

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <qcrypto/qcrypto.h>
#include <qcrypto/qcrypto_error.h>
#include <qcrypto/qcrypto_keys.h>
#include <private/qcrypto/qcrypto_internal.h>

int main(void)
{
    int ret;
    int sig_result = 1;
    int ver_result = 1;
    qcrypto_ctx_t *qctx = NULL;
    qcrypto_ctx_t *qkeyctx = NULL;
    qcrypto_key_t *qprivkey = NULL;
    qcrypto_key_t *qpubkey = NULL;

    const char privkey_hex[] =
	"2d2d2d2d2d424547494e2050524956415445204b45592d2d2d2d2d0a4d49"
	"4945764149424144414e42676b71686b6947397730424151454641415343"
	"424b59776767536941674541416f494241514337322b65305a6173585674"
	"59480a4636414334587945542f3033674434384f436c6672313233597364"
	"4f6f7267686a4b56487655433445306971567a327544312f3753776a3879"
	"702b6a495753360a6d39583862623774756c417533555965662b4d4d704b"
	"2b46327a4e4651714a376c6c35654c506e6d62714c5036652b6378556830"
	"68737967456f6f5035646f550a4d3335362f697769644149764f36376c63"
	"33766174446a4b333748696e2f7a74344a442b66622b6843365861424e33"
	"6c36664f326c3667424276547572702f490a6f3861384958645663422b4a"
	"6751785a6f6278563545527231384a5059672b354832393164537733734f"
	"374330644d73314265707837443143394c792b6f654d0a44714d4d714d71"
	"45736441413974786d68493855484c42614e6e367a4f77542b50556a3071"
	"746770715a595058704e686d5969324557314764584356583246410a775a"
	"45746c417a7241674544416f49424148303952534c7563672b504f566f50"
	"77414872714667315533705666744c51473555666b382b584c346e423042"
	"5a640a7734556f3164414d327877364b5236303671654857314d78763849"
	"57517963536a71684a4b66505269736e6f32576d716c3133444836365349"
	"69347362464a6b0a50756c7a5555524a77642f78536d694468614d456947"
	"713342725644357267695646482b7942623441585453644a6a33702b6369"
	"3049632f792b7870676c6a390a76574f4d396c592f386245594143615244"
	"635a503339726c575475574e6c426468412f4561345774676f5365625a76"
	"35576c77763562694d385079755948772b0a6e485a4950557951446a5956"
	"316f326a4941495a506c4c2f6e58506f47744b5435395a4a435568796832"
	"49586a525475434f37593761344631455873557877480a42644b364a6647"
	"6b62695235723835587a675a7153786f4e6b516c494e413355436e6e7579"
	"6a734367594541395a484e734c7335706c5278754551553643386f0a704e"
	"377a425353446f676e4e2b7442725a4a794d572f55456730613479627130"
	"706e676651725772324a4434764c326b756e47305457634a434854694b43"
	"52570a5264676c50416562505841577851686f664e645933467972555974"
	"3238744155462f45315643764f4c737a3155544e525837714d704b313774"
	"6b4261347438560a594c6d6c2f394b61384d6652474850506c502f454437"
	"3843675945417739615752433377703873364177784c39587a6e75693473"
	"307851725451742f55332b730a484166756568666e574876616e6a543344"
	"6c4e394b53465967454e6a776b4563796c4a556774335030507a4f365451"
	"4a496335386c3344784b5655486d6b66490a536e50695944746173324a63"
	"6c66634c6162796839366c666b58316a4e794468594834472b7047334f70"
	"684e4b4d304163764c4c2f4d7a474a6a2b682b72677a0a374862707a6455"
	"43675945416f37614a49487a52475932684a594b346d736f62474a536941"
	"3232744672457a2f49727951784d49505534444169386c3239484e0a7846"
	"415531795048356258374b48357430614569336b53777345337347734c6b"
	"4c70415930712b38303641504c6757612f65546c3644334869374a505449"
	"71340a442f596a6a584b4a6449696a6933654c6c53634962636a394a4372"
	"6e51656f4f514876442f2b47386f4955324545303144662f59436e384367"
	"594541676f384f0a3242366762397a52563132482b503376305851643467"
	"31794d317a2f6a502f4945712f30555756453561666e46434e5058754a54"
	"634d446c71746558317459540a4d597734567a364b69314d306d33674746"
	"6f6d6f5a50583247343446455955774d614b57367449386435626f592f6f"
	"486d394d577052755643366a737a3274410a3676367655625a364a78417a"
	"63496971393079482f64335a627455577079563338766e784d2b4d436759"
	"4235504f697452706f47364f6a3869635337484175630a416c6b4368782f"
	"6149636d6532516f396e512f342b446c562b7338395679646533656a3078"
	"6444497a464e6c384533732b54754437653034524d6839666f6d790a3672"
	"2b4b58554b756a6f745977636f6434316d2f77433464724d686950516162"
	"3564794578654854775a513134434c3075673631353579484d64594f624b"
	"67470a78664c726c506c4d5648714b4166475237546f4b69513d3d0a2d2d"
	"2d2d2d454e442050524956415445204b45592d2d2d2d2d0a";

    const char pubkey_hex[] =
	"2d2d2d2d2d424547494e205055424c4943204b45592d2d2d2d2d0a4d4949"
	"424944414e42676b71686b6947397730424151454641414f43415130414d"
	"49494243414b43415145417539766e744757724631625742786567417546"
	"380a68452f394e34412b504467705836396474324c4854714b344959796c"
	"5237314175424e49716c6339726739662b3073492f4d71666f79466b7570"
	"76562f47322b0a376270514c743147486e2f6a444b53766864737a52554b"
	"6965355a6558697a35356d36697a2b6e766e4d56496449624d6f424b4b44"
	"2b586146444e2b657634730a496e51434c7a757535584e37327251347974"
	"2b7834702f38376543512f6e322f6f51756c3267546435656e7a7470656f"
	"4151623037713666794b5047764346330a565841666959454d5761473856"
	"655245613966435432495075523976645855734e374475777448544c4e51"
	"587163657739517653387671486a41366a444b6a4b0a684c485141506263"
	"5a6f535046427977576a5a2b737a73452f6a3149394b72594b616d574431"
	"3654595a6d4974684674526e56776c563968514d47524c5a514d0a367749"
	"4241773d3d0a2d2d2d2d2d454e44205055424c4943204b45592d2d2d2d2d"
	"0a";

    const char sig_hex[] =
	"90b605a54006c3eb749c4a03b3cb9ed5cd8ab95fe18f3fd49e0ac0b9544b8"
	"7f50cb1df831cb095fff5ba1e57460a49709287cca42670ee4fe3ba05d873"
	"a62b43e92a699a1cf7143586d181e98831bb7159c3fe2346440fe0f83f52c"
	"096a4fa4ed82274661d1157b6b177475f41bc37318e45ef621b7bd3f31acc"
	"d7f315bdffa837c696a2b4b8479891a7cd87638837c647f89f35e072bb7fb"
	"3fced7a5eb4e59637cb445776608e1a1a977dd68616f8115c616bbc39c48d"
	"05b4f983e7964930b67592ca85f2f12b52defdd4a4daf9b812e3d4696e20e"
	"3fe044aa731a65aa23dae281e25c985d7f43530488055d5758deff9f5114a"
	"a14ed39a939402762ff208ee";

    const char input_hex[] = "3031323334353637383941424344454631323334";

    const size_t privkeysize = (sizeof(privkey_hex)-1)/2;
    uint8_t privkeybuf[2000];
    uint8_t *privkey_bin = privkeybuf;

    const size_t pubkeysize = (sizeof(pubkey_hex)-1)/2;
    uint8_t pubkeybuf[sizeof(privkeybuf)];
    uint8_t *pubkey_bin = pubkeybuf;

    const size_t inputsize = (sizeof(input_hex)-1)/2;
    uint8_t inputbuf[inputsize];
    uint8_t *input_bin = inputbuf;

    const size_t sigsize = (sizeof(sig_hex)-1)/2;
    uint8_t sig_cmpbuf[sigsize];
    uint8_t *sig_cmp = sig_cmpbuf;
    size_t sigsize_cmp = 0;
    char sig_cmp_hexbuf[sigsize*2];
    char *sig_cmp_hex = sig_cmp_hexbuf;

    /* Initialize the Qcrypto Library */
    ret = qcrypto_init(QCRYPTO_INIT_LAZY, NULL);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcryto_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Request rsa keygen */
    ret = qcrypto_keygen_request("rsa", NULL, 0, &qkeyctx);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_keygen_request() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Initialize signature arguments */
    qcrypto_signature_args_t sargs = {
        .mode = QCRYPTO_SIGNATURE_SIGN,
        .rsa.pad_mode = QCRYPTO_RSA_PAD_PKCS1v15,
        .rsa.saltsize = 0,
    };

    /* Request rsa-with-sha256 to sign a signature */
    ret = qcrypto_signature_request("rsa-with-sha256", NULL, 0, &qctx);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_signature_request() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert privkey */
    ret = qcrypto_hex2bin(privkey_bin, privkey_hex, privkeysize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert pubkey */
    ret = qcrypto_hex2bin(pubkey_bin, pubkey_hex, pubkeysize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert input */
    ret = qcrypto_hex2bin(input_bin, input_hex, inputsize);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_hex2bin() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Load privkey */
    ret = qcrypto_privkey_from_mem(qkeyctx, &qprivkey, privkey_bin, privkeysize, QCRYPTO_KEY_FMT_PEM);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_privkey_from_mem() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Initialize signature signing */
    ret = qcrypto_signature_init(qctx, qprivkey, &sargs);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_signature_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Compare sig size */
    sigsize_cmp = qcrypto_signature_sigsize(qctx);
    if (sigsize_cmp != sigsize) {
        fprintf(stderr, "Computed sigsize failed to match with expected sigsize\n");
        goto done;
    }

    /* Sign the Signature */
    qcrypto_memclear(sig_cmp, sigsize_cmp);
    ret = qcrypto_signature_sign_oneshot(qctx, input_bin, inputsize, sig_cmp, &sigsize_cmp);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_signature_sign_oneshot() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Convert the sig */
    qcrypto_bin2hex(sig_cmp_hex, sig_cmp, sigsize);

    /* Compare the sig results */
    sig_result = memcmp(sig_cmp_hex, sig_hex, sigsize);
    if (sig_result == 0) {
         printf("Computed sig matches with expected sig\n");
    } else {
         fprintf(stderr, "Computed sig failed to match with expected sig\n");
         goto done;
    }

    /* Switch to verification mode */
    sargs.mode = QCRYPTO_SIGNATURE_VERIFY;

    /* Load pubkey */
    ret = qcrypto_pubkey_from_mem(qkeyctx, &qpubkey, pubkey_bin, pubkeysize, QCRYPTO_KEY_FMT_PEM);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_pubkey_from_mem() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Initialize signature verification */
    ret = qcrypto_signature_init(qctx, qpubkey, &sargs);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_signature_init() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Verify the Signature */
    ret = qcrypto_signature_verify_oneshot(qctx, input_bin, inputsize, sig_cmp, sigsize, &ver_result);
    if (ret != QCRYPTO_R_EOK) {
        fprintf(stderr, "qcrypto_signature_verify_oneshot() failed (%d:%s)\n", ret, qcrypto_strerror(ret));
        goto done;
    }

    /* Check the verification result */
    if (ver_result == 1) {
         printf("Signature verified\n");
    } else {
         fprintf(stderr, "Signature verification failed\n");
         goto done;
    }
    goto done;

done:
    /* Release all context handles */
    qcrypto_release_ctx(qctx);
    qcrypto_release_ctx(qkeyctx);

    /* Release all key handles */
    qcrypto_release_key(qprivkey);
    qcrypto_release_key(qpubkey);

    /* Uninitialize the Qcrypto Library */
    qcrypto_uninit();

    return ret;
}

#if defined(__QNXNTO__) && defined(__USESRCVERSION)
#include <sys/srcversion.h>
__SRCVERSION("$URL$ $Rev$")
#endif