<commit_before>/** \ingroup rpmpgp
 * \file rpmio/rpmgc.c
 */

#include "system.h"

#include <rpmiotypes.h>
#define	_RPMGC_INTERNAL
#if defined(WITH_GCRYPT)
#define	_RPMPGP_INTERNAL
#include <rpmgc.h>
#endif

#include "debug.h"

#if defined(WITH_GCRYPT)

/*@access pgpDig @*/
/*@access pgpDigParams @*/

/*@-redecl@*/
/*@unchecked@*/
extern int _pgp_debug;

/*@unchecked@*/
extern int _pgp_print;
/*@=redecl@*/

static
void rpmgcDump(const char * msg, gcry_sexp_t sexp)
	/*@*/
{
    char buf[BUFSIZ];
    size_t nb;

/*@-modunconnomods @*/
    nb = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, sizeof(buf));
/*@=modunconnomods @*/
/*@-modfilesys@*/
if (_pgp_debug)
fprintf(stderr, "========== %s:\n%s", msg, buf);
/*@=modfilesys@*/
    return;
}

static
gcry_error_t rpmgcErr(rpmgc gc, const char * msg, gcry_error_t err)
	/*@*/
{
    if (err) {
	fprintf (stderr, "rpmgc: %s: %s/%s\n",
		msg, gcry_strsource (err), gcry_strerror (err));
    }
    return err;
}

static
int rpmgcSetRSA(/*@only@*/ DIGEST_CTX ctx, pgpDig dig, pgpDigParams sigp)
	/*@modifies dig @*/
{
    rpmgc gc = dig->impl;
    const char * hash_algo_name = NULL;
    int rc;
    int xx;

    switch (sigp->hash_algo) {
    case PGPHASHALGO_MD5:
	hash_algo_name = "md5";
	break;
    case PGPHASHALGO_SHA1:
	hash_algo_name = "sha1";
	break;
    case PGPHASHALGO_RIPEMD160:
	hash_algo_name = "ripemd160";
	break;
    case PGPHASHALGO_MD2:
	hash_algo_name = "md2";
	break;
    case PGPHASHALGO_TIGER192:
	hash_algo_name = "tiger";
	break;
    case PGPHASHALGO_HAVAL_5_160:
#ifdef	NOTYET
	hash_algo_name = "haval";
#endif
	break;
    case PGPHASHALGO_SHA256:
	hash_algo_name = "sha256";
	break;
    case PGPHASHALGO_SHA384:
	hash_algo_name = "sha384";
	break;
    case PGPHASHALGO_SHA512:
	hash_algo_name = "sha512";
	break;
    case PGPHASHALGO_SHA224:
#ifdef	NOTYET
	hash_algo_name = "sha224";
#endif
	break;
    default:
	break;
    }
    if (hash_algo_name == NULL)
	return 1;

    xx = rpmDigestFinal(ctx, (void **)&dig->md5, &dig->md5len, 0);

    /* Set RSA hash. */
/*@-moduncon -noeffectuncon @*/
    {	gcry_mpi_t c = NULL;
	gcry_error_t yy;
	xx = gcry_mpi_scan(&c, GCRYMPI_FMT_USG, dig->md5, dig->md5len, NULL);
	yy = rpmgcErr(gc, "RSA c",
		gcry_sexp_build(&gc->hash, NULL,
			"(data (flags pkcs1) (hash %s %m))", hash_algo_name, c) );
	gcry_mpi_release(c);
if (_pgp_debug < 0) rpmgcDump("gc->hash", gc->hash);
    }
/*@=moduncon =noeffectuncon @*/

    /* Compare leading 16 bits of digest for quick check. */
    {	const rpmuint8_t *s = dig->md5;
	const rpmuint8_t *t = sigp->signhash16;
	rc = memcmp(s, t, sizeof(sigp->signhash16));
#ifdef	DYING
	if (rc != 0)
	    fprintf(stderr, "*** hash fails: digest(%02x%02x) != signhash(%02x%02x)\n",
		s[0], s[1], t[0], t[1]);
#endif
    }

    return rc;
}

static
int rpmgcVerifyRSA(pgpDig dig)
	/*@*/
{
    rpmgc gc = dig->impl;
    gcry_error_t err;

/*@-moduncon@*/
    err = rpmgcErr(gc, "RSA gc->sig",
		gcry_sexp_build(&gc->sig, NULL,
			"(sig-val (RSA (s %m)))", gc->c) );
/*@=moduncon@*/
if (_pgp_debug < 0)
rpmgcDump("gc->sig", gc->sig);
/*@-moduncon@*/
    err = rpmgcErr(gc, "RSA gc->pkey",
		gcry_sexp_build(&gc->pkey, NULL,
			"(public-key (RSA (n %m) (e %m)))", gc->n, gc->e) );
/*@=moduncon@*/
if (_pgp_debug < 0)
rpmgcDump("gc->pkey", gc->pkey);

    /* Verify RSA signature. */
/*@-moduncon@*/
    err = rpmgcErr(gc, "RSA verify",
		gcry_pk_verify (gc->sig, gc->hash, gc->pkey) );
/*@=moduncon@*/

    gcry_sexp_release(gc->pkey);	gc->pkey = NULL;
    gcry_sexp_release(gc->hash);	gc->hash = NULL;
    gcry_sexp_release(gc->sig);		gc->sig = NULL;

    return (err ? 0 : 1);
}

static
int rpmgcSetDSA(/*@only@*/ DIGEST_CTX ctx, pgpDig dig, pgpDigParams sigp)
	/*@modifies dig @*/
{
    rpmgc gc = dig->impl;
    gcry_error_t err;
    int xx;

assert(sigp->hash_algo == rpmDigestAlgo(ctx));
    xx = rpmDigestFinal(ctx, (void **)&dig->sha1, &dig->sha1len, 0);

   /* Set DSA hash. */
/*@-moduncon -noeffectuncon @*/
    err = rpmgcErr(gc, "DSA gc->hash",
		gcry_sexp_build(&gc->hash, NULL,
			"(data (flags raw) (value %b))", dig->sha1len, dig->sha1) );
/*@=moduncon =noeffectuncon @*/
if (_pgp_debug < 0)
rpmgcDump("gc->hash", gc->hash);

    /* Compare leading 16 bits of digest for quick check. */
    return memcmp(dig->sha1, sigp->signhash16, sizeof(sigp->signhash16));
}

static
int rpmgcVerifyDSA(pgpDig dig)
	/*@*/
{
    rpmgc gc = dig->impl;
    gcry_error_t err;

/*@-moduncon -noeffectuncon @*/
    err = rpmgcErr(gc, "DSA gc->sig",
		gcry_sexp_build(&gc->sig, NULL,
			"(sig-val (DSA (r %m) (s %m)))", gc->r, gc->s) );
if (_pgp_debug < 0)
rpmgcDump("gc->sig", gc->sig);
    err = rpmgcErr(gc, "DSA gc->pkey",
		gcry_sexp_build(&gc->pkey, NULL,
			"(public-key (DSA (p %m) (q %m) (g %m) (y %m)))",
			gc->p, gc->q, gc->g, gc->y) );
if (_pgp_debug < 0)
rpmgcDump("gc->pkey", gc->pkey);

    /* Verify DSA signature. */
    err = rpmgcErr(gc, "DSA verify",
		gcry_pk_verify (gc->sig, gc->hash, gc->pkey) );

    gcry_sexp_release(gc->pkey);	gc->pkey = NULL;
    gcry_sexp_release(gc->hash);	gc->hash = NULL;
    gcry_sexp_release(gc->sig);		gc->sig = NULL;
/*@=moduncon -noeffectuncon @*/
    return (err ? 0 : 1);
}


static
int rpmgcSetECDSA(/*@only@*/ DIGEST_CTX ctx, pgpDig dig, pgpDigParams sigp)
	/*@modifies dig @*/
{
    int rc = 1;		/* XXX always fail. */
    int xx;

assert(sigp->hash_algo == rpmDigestAlgo(ctx));
    xx = rpmDigestFinal(ctx, (void **)NULL, NULL, 0);

    /* Compare leading 16 bits of digest for quick check. */

    return rc;
}

static
int rpmgcVerifyECDSA(pgpDig dig)
	/*@*/
{
    int rc = 0;		/* XXX always fail. */

    return rc;
}

/*@-globuse -mustmod @*/
static
int rpmgcMpiItem(/*@unused@*/ const char * pre, pgpDig dig, int itemno,
		const rpmuint8_t * p,
		/*@unused@*/ /*@null@*/ const rpmuint8_t * pend)
	/*@globals fileSystem @*/
	/*@modifies dig, fileSystem @*/
{
    rpmgc gc = dig->impl;
    size_t nb = ((pgpMpiBits(p) + 7) >> 3) + 2;
    size_t nscan = 0;
    gcry_error_t err;
    int rc = 0;

/*@-moduncon -noeffectuncon @*/
    switch (itemno) {
    default:
assert(0);
	break;
    case 10:		/* RSA m**d */
	err = rpmgcErr(gc, "RSA m**d",
		gcry_mpi_scan(&gc->c, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 20:		/* DSA r */
	err = rpmgcErr(gc, "DSA r",
		gcry_mpi_scan(&gc->r, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 21:		/* DSA s */
	err = rpmgcErr(gc, "DSA s",
		gcry_mpi_scan(&gc->s, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 30:		/* RSA n */
	err = rpmgcErr(gc, "RSA n",
		gcry_mpi_scan(&gc->n, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 31:		/* RSA e */
	err = rpmgcErr(gc, "RSA e",
		gcry_mpi_scan(&gc->e, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 40:		/* DSA p */
	err = rpmgcErr(gc, "DSA p",
		gcry_mpi_scan(&gc->p, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 41:		/* DSA q */
	err = rpmgcErr(gc, "DSA q",
		gcry_mpi_scan(&gc->q, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 42:		/* DSA g */
	err = rpmgcErr(gc, "DSA g",
		gcry_mpi_scan(&gc->g, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    case 43:		/* DSA y */
	err = rpmgcErr(gc, "DSA y",
		gcry_mpi_scan(&gc->y, GCRYMPI_FMT_PGP, p, nb, &nscan) );
	break;
    }
/*@=moduncon =noeffectuncon @*/
    return rc;
}
/*@=globuse =mustmod @*/

/*@-mustmod@*/
static
void rpmgcClean(void * impl)
	/*@modifies impl @*/
{
    rpmgc gc = impl;
/*@-moduncon -noeffectuncon @*/
    if (gc != NULL) {
	if (gc->sig) {
	    gcry_sexp_release(gc->sig);
	    gc->sig = NULL;
	}
	if (gc->hash) {
	    gcry_sexp_release(gc->hash);
	    gc->hash = NULL;
	}
	if (gc->pkey) {
	    gcry_sexp_release(gc->pkey);
	    gc->pkey = NULL;
	}
	if (gc->r) {
	    gcry_mpi_release(gc->r);
	    gc->r = NULL;
	}
	if (gc->s) {
	    gcry_mpi_release(gc->s);
	    gc->s = NULL;
	}
	if (gc->n) {
	    gcry_mpi_release(gc->n);
	    gc->n = NULL;
	}
	if (gc->e) {
	    gcry_mpi_release(gc->e);
	    gc->e = NULL;
	}
	if (gc->c) {
	    gcry_mpi_release(gc->c);
	    gc->c = NULL;
	}
	if (gc->p) {
	    gcry_mpi_release(gc->p);
	    gc->p = NULL;
	}
	if (gc->q) {
	    gcry_mpi_release(gc->q);
	    gc->q = NULL;
	}
	if (gc->g) {
	    gcry_mpi_release(gc->g);
	    gc->g = NULL;
	}
	if (gc->y) {
	    gcry_mpi_release(gc->y);
	    gc->y = NULL;
	}
    }
/*@=moduncon =noeffectuncon @*/
}
/*@=mustmod@*/

static /*@null@*/
void * rpmgcFree(/*@only@*/ void * impl)
	/*@modifies impl @*/
{
    rpmgc gc = impl;
    rpmgcClean(impl);
    gc = _free(gc);
    return NULL;
}

static
void * rpmgcInit(void)
	/*@*/
{
    rpmgc gc = xcalloc(1, sizeof(*gc));
    return (void *) gc;
}

struct pgpImplVecs_s rpmgcImplVecs = {
	rpmgcSetRSA, rpmgcVerifyRSA,
	rpmgcSetDSA, rpmgcVerifyDSA,
	rpmgcSetECDSA, rpmgcVerifyECDSA,
	rpmgcMpiItem, rpmgcClean,
	rpmgcFree, rpmgcInit
};

#endif
<commit_msg>- jbj: rpmgc: yet more debugging code.<commit_after>/** \ingroup rpmpgp
 * \file rpmio/rpmgc.c
 */

#include "system.h"

#include <rpmiotypes.h>
#define	_RPMGC_INTERNAL
#if defined(WITH_GCRYPT)
#define	_RPMPGP_INTERNAL
#include <rpmgc.h>
#endif

#include "debug.h"

#if defined(WITH_GCRYPT)

/*@access pgpDig @*/
/*@access pgpDigParams @*/

/*@-redecl@*/
/*@unchecked@*/
extern int _pgp_debug;

/*@unchecked@*/
extern int _pgp_print;
/*@=redecl@*/

static
void rpmgcDump(const char * msg, gcry_sexp_t sexp)
	/*@*/
{
    size_t nb = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, NULL, 0);
    char * buf = alloca(nb+1);

/*@-modunconnomods @*/
    nb = gcry_sexp_sprint(sexp, GCRYSEXP_FMT_ADVANCED, buf, nb);
/*@=modunconnomods @*/
    buf[nb] = '\0';
/*@-modfilesys@*/
if (_pgp_debug)
fprintf(stderr, "========== %s:\n%s", msg, buf);
/*@=modfilesys@*/
    return;
}

static
gcry_error_t rpmgcErr(rpmgc gc, const char * msg, gcry_error_t err)
	/*@*/
{
    if (err) {
	fprintf (stderr, "rpmgc: %s: %s/%s\n",
		msg, gcry_strsource (err), gcry_strerror (err));
    }
    return err;
}

static
int rpmgcSetRSA(/*@only@*/ DIGEST_CTX ctx, pgpDig dig, pgpDigParams sigp)
	/*@modifies dig @*/
{
    rpmgc gc = dig->impl;
    const char * hash_algo_name = NULL;
    int rc;
    int xx;

    switch (sigp->hash_algo) {
    case PGPHASHALGO_MD5:
	hash_algo_name = "md5";
	break;
    case PGPHASHALGO_SHA1:
	hash_algo_name = "sha1";
	break;
    case PGPHASHALGO_RIPEMD160:
	hash_algo_name = "ripemd160";
	break;
    case PGPHASHALGO_MD2:
	hash_algo_name = "md2";
	break;
    case PGPHASHALGO_TIGER192:
	hash_algo_name = "tiger";
	break;
    case PGPHASHALGO_HAVAL_5_160:
#ifdef	NOTYET
	hash_algo_name = "haval";
#endif
	break;
    case PGPHASHALGO_SHA256:
	hash_algo_name = "sha256";
	break;
    case PGPHASHALGO_SHA384:
	hash_algo_name = "sha384";
	break;
    case PGPHASHALGO_SHA512:
	hash_algo_name = "sha512";
	break;
    case PGPHASHALGO_SHA224:
#ifdef	NOTYET
	hash_algo_name = "sha224";
#endif
	break;
    default:
	break;
    }
    if (hash_algo_name == NULL)
	return 1;

    xx = rpmDigestFinal(ctx, (void **)&dig->md5, &dig->md5len, 0);

    /* Set RSA hash. */
/*@-moduncon -noeffectuncon @*/
    {	gcry_mpi_t c = NULL;
	gcry_error_t yy;
	xx = gcry_mpi_scan(&c, GCRYMPI_FMT_USG, dig->md5, dig->md5len, NULL);
	yy = rpmgcErr(gc, "RSA c",
		gcry_sexp_build(&gc->hash, NULL,
			"(data (flags pkcs1) (hash %s %m))", hash_algo_name, c) );
	gcry_mpi_release(c);
if (_pgp_debug < 0) rpmgcDump("gc->hash", gc->hash);
    }
/*@=moduncon =noeffectuncon @*/

    /* Compare leading 16 bits of digest for quick check. */
    {	const rpmuint8_t *s = dig->md5;
	const rpmuint8_t *t = sigp->signhash16;
	rc = memcmp(s, t, sizeof(sigp->signhash16));
#ifdef	DYING
	if (rc != 0)
	    fprintf(stderr, "*** hash fails: digest(%02x%02x) != signhash(%02x%02x)\n",
		s[0], s[1], t[0], t[1]);
#endif
    }

    return rc;
}

static
int rpmgcVerifyRSA(pgpDig dig)
	/*@*/
{
    rpmgc gc = dig->impl;
    gcry_error_t err;

/*@-moduncon@*/
    err = rpmgcErr(gc, "RSA gc->sig",
		gcry_sexp_build(&gc->sig, NULL,
			"(sig-val (RSA (s %m)))", gc->c) );
/*@=moduncon@*/
if (_pgp_debug < 0)
rpmgcDump("gc->sig", gc->sig);
/*@-moduncon@*/
    err = rpmgcErr(gc, "RSA gc->pkey",
		gcry_sexp_build(&gc->pkey, NULL,
			"(public-key (RSA (n %m) (e %m)))", gc->n, gc->e) );
/*@=moduncon@*/
if (_pgp_debug < 0)
rpmgcDump("gc->pkey", gc->pkey);

    /* Verify RSA signature. */
/*@-moduncon@*/
    err = rpmgcErr(gc, "RSA verify",
		gcry_pk_verify (gc->sig, gc->hash, gc->pkey) );
/*@=moduncon@*/

    gcry_sexp_release(gc->pkey);	gc->pkey = NULL;
    gcry_sexp_release(gc->hash);	gc->hash = NULL;
    gcry_sexp_release(gc->sig);		gc->sig = NULL;

    return (err ? 0 : 1);
}

static
int rpmgcSetDSA(/*@only@*/ DIGEST_CTX ctx, pgpDig dig, pgpDigParams sigp)
	/*@modifies dig @*/
{
    rpmgc gc = dig->impl;
    gcry_error_t err;
    int xx;

assert(sigp->hash_algo == rpmDigestAlgo(ctx));
    xx = rpmDigestFinal(ctx, (void **)&dig->sha1, &dig->sha1len, 0);

    /* Set DSA hash. */
    err = rpmgcErr(gc, "DSA gc->hash",
		gcry_sexp_build(&gc->hash, NULL,
			"(data (flags raw) (value %b))", dig->sha1len, dig->sha1) );
if (_pgp_debug < 0)
rpmgcDump("gc->hash", gc->hash);

    /* Compare leading 16 bits of digest for quick check. */
    return memcmp(dig->sha1, sigp->signhash16, sizeof(sigp->signhash16));
}

static
int rpmgcVerifyDSA(pgpDig dig)
	/*@*/
{
    rpmgc gc = dig->impl;
    gcry_error_t err;

/*@-moduncon -noeffectuncon @*/

    err = rpmgcErr(gc, "DSA gc->sig",
		gcry_sexp_build(&gc->sig, NULL,
			"(sig-val (DSA (r %m) (s %m)))", gc->r, gc->s) );
if (_pgp_debug < 0)
rpmgcDump("gc->sig", gc->sig);
    err = rpmgcErr(gc, "DSA gc->pkey",
		gcry_sexp_build(&gc->pkey, NULL,
			"(public-key (DSA (p %m) (q %m) (g %m) (y %m)))",
			gc->p, gc->q, gc->g, gc->y) );
if (_pgp_debug < 0)
rpmgcDump("gc->pkey", gc->pkey);

    /* Verify DSA signature. */
    err = rpmgcErr(gc, "DSA verify",
		gcry_pk_verify (gc->sig, gc->hash, gc->pkey) );

    gcry_sexp_release(gc->pkey);	gc->pkey = NULL;
    gcry_sexp_release(gc->hash);	gc->hash = NULL;
    gcry_sexp_release(gc->sig);		gc->sig = NULL;

/*@=moduncon -noeffectuncon @*/

    return (err ? 0 : 1);
}


static
int rpmgcSetECDSA(/*@only@*/ DIGEST_CTX ctx, pgpDig dig, pgpDigParams sigp)
	/*@modifies dig @*/
{
    int rc = 1;		/* XXX always fail. */
    int xx;

assert(sigp->hash_algo == rpmDigestAlgo(ctx));
    xx = rpmDigestFinal(ctx, (void **)NULL, NULL, 0);

    /* Compare leading 16 bits of digest for quick check. */

    return rc;
}

static
int rpmgcVerifyECDSA(pgpDig dig)
	/*@*/
{
    int rc = 0;		/* XXX always fail. */

    return rc;
}

/*@-globuse -mustmod @*/
static
int rpmgcMpiItem(/*@unused@*/ const char * pre, pgpDig dig, int itemno,
		const rpmuint8_t * p,
		/*@unused@*/ /*@null@*/ const rpmuint8_t * pend)
	/*@globals fileSystem @*/
	/*@modifies dig, fileSystem @*/
{
    rpmgc gc = dig->impl;
    size_t nb = pgpMpiLen(p);
    const char * mpiname = "";
    gcry_mpi_t * mpip = NULL;
    size_t nscan = 0;
    gcry_error_t err;
    int rc = 0;

    switch (itemno) {
    default:
assert(0);
	break;
    case 10:		/* RSA m**d */
	mpiname ="RSA m**d";	mpip = &gc->c;
	break;
    case 20:		/* DSA r */
	mpiname = "DSA r";	mpip = &gc->r;
	break;
    case 21:		/* DSA s */
	mpiname = "DSA s";	mpip = &gc->s;
	break;
    case 30:		/* RSA n */
	mpiname = "RSA n";	mpip = &gc->n;
	break;
    case 31:		/* RSA e */
	mpiname = "RSA e";	mpip = &gc->e;
	break;
    case 40:		/* DSA p */
	mpiname = "DSA p";	mpip = &gc->p;
	break;
    case 41:		/* DSA q */
	mpiname = "DSA q";	mpip = &gc->q;
	break;
    case 42:		/* DSA g */
	mpiname = "DSA g";	mpip = &gc->g;
	break;
    case 43:		/* DSA y */
	mpiname = "DSA y";	mpip = &gc->y;
	break;
    }

/*@-moduncon -noeffectuncon @*/
    err = rpmgcErr(gc, mpiname,
		gcry_mpi_scan(mpip, GCRYMPI_FMT_PGP, p, nb, &nscan) );
/*@=moduncon =noeffectuncon @*/

    if (_pgp_debug < 0)
    {	size_t nbits = gcry_mpi_get_nbits(*mpip);
	unsigned char * hex = NULL;
	size_t nhex = 0;
	err = rpmgcErr(gc, "MPI print",
		gcry_mpi_aprint(GCRYMPI_FMT_HEX, &hex, &nhex, *mpip) );
	fprintf(stderr, "*** %s\t%5d:%s\n", mpiname, nbits, hex);
	hex = _free(hex);
    }

    return rc;
}
/*@=globuse =mustmod @*/

/*@-mustmod@*/
static
void rpmgcClean(void * impl)
	/*@modifies impl @*/
{
    rpmgc gc = impl;
/*@-moduncon -noeffectuncon @*/
    if (gc != NULL) {
	if (gc->sig) {
	    gcry_sexp_release(gc->sig);
	    gc->sig = NULL;
	}
	if (gc->hash) {
	    gcry_sexp_release(gc->hash);
	    gc->hash = NULL;
	}
	if (gc->pkey) {
	    gcry_sexp_release(gc->pkey);
	    gc->pkey = NULL;
	}
	if (gc->r) {
	    gcry_mpi_release(gc->r);
	    gc->r = NULL;
	}
	if (gc->s) {
	    gcry_mpi_release(gc->s);
	    gc->s = NULL;
	}
	if (gc->n) {
	    gcry_mpi_release(gc->n);
	    gc->n = NULL;
	}
	if (gc->e) {
	    gcry_mpi_release(gc->e);
	    gc->e = NULL;
	}
	if (gc->c) {
	    gcry_mpi_release(gc->c);
	    gc->c = NULL;
	}
	if (gc->p) {
	    gcry_mpi_release(gc->p);
	    gc->p = NULL;
	}
	if (gc->q) {
	    gcry_mpi_release(gc->q);
	    gc->q = NULL;
	}
	if (gc->g) {
	    gcry_mpi_release(gc->g);
	    gc->g = NULL;
	}
	if (gc->y) {
	    gcry_mpi_release(gc->y);
	    gc->y = NULL;
	}
    }
/*@=moduncon =noeffectuncon @*/
}
/*@=mustmod@*/

/*@unchecked@*/
static int rpmgc_initialized;

static /*@null@*/
void * rpmgcFree(/*@only@*/ void * impl)
	/*@modifies impl @*/
{
    rpmgc gc = impl;

    rpmgcClean(impl);

    if (--rpmgc_initialized == 0 && _pgp_debug < 0) {
	gcry_error_t err;
	err = rpmgcErr(gc, "CLEAR_DEBUG_FLAGS",
		gcry_control(GCRYCTL_CLEAR_DEBUG_FLAGS, 3));
	err = rpmgcErr(gc, "SET_VERBOSITY",
		gcry_control(GCRYCTL_SET_VERBOSITY, 0) );
    }

    gc = _free(gc);

    return NULL;
}

static
void * rpmgcInit(void)
	/*@*/
{
    rpmgc gc = xcalloc(1, sizeof(*gc));

    if (rpmgc_initialized++ == 0 && _pgp_debug < 0) {
	gcry_error_t err;
	err = rpmgcErr(gc, "SET_VERBOSITY",
		gcry_control(GCRYCTL_SET_VERBOSITY, 3) );
	err = rpmgcErr(gc, "SET_DEBUG_FLAGS",
		gcry_control(GCRYCTL_SET_DEBUG_FLAGS, 3) );
    }

    return (void *) gc;
}

struct pgpImplVecs_s rpmgcImplVecs = {
	rpmgcSetRSA, rpmgcVerifyRSA,
	rpmgcSetDSA, rpmgcVerifyDSA,
	rpmgcSetECDSA, rpmgcVerifyECDSA,
	rpmgcMpiItem, rpmgcClean,
	rpmgcFree, rpmgcInit
};

#endif

{'fraction_non_alphanumeric': 0.19009681881051177, 'fraction_numerical': 0.014550484094052558, 'mean_word_length': 3.1765249537892792, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 243, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4687640', 'n_tokens_mistral': 8935, 'n_tokens_neox': 8300, 'n_words': 1696}