summaryrefslogtreecommitdiff
path: root/rpmio/digest.c
blob: 13a3b9236889fa6fbb4b1fd929f6456b77accaca (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/** \ingroup signature
 * \file rpmio/digest.c
 */

#include "system.h"
#include "rpmio_internal.h"
#include "beecrypt.h"
#include "md5.h"
#include "endianness.h"
#include "fips180.h"
#include "debug.h"

#ifdef	SHA_DEBUG
#define	DPRINTF(_a)	fprintf _a
#else
#define	DPRINTF(_a)
#endif

/*@access DIGEST_CTX@*/

/**
 * MD5/SHA1 digest private data.
 */
struct DIGEST_CTX_s {
    rpmDigestFlags flags;	/*!< Bit(s) to control digest operation. */
    uint32 digestlen;		/*!< No. bytes of digest. */
    uint32 datalen;		/*!< No. bytes in block of plaintext data. */
    void * param;		/*!< Digest parameters. */
    int (*Reset) (void * param)
	/*@modifies param @*/;	/*!< Digest initialize. */
    int (*Update) (void * param, const byte * data, int len)
	/*@modifies param @*/;	/*!< Digest transform. */
    int (*Digest) (void * param, /*@out@*/ uint32 * digest)
	/*@modifies param, digest @*/;	/*!< Digest finish. */
};

DIGEST_CTX
rpmDigestInit(rpmDigestFlags flags)
{
    DIGEST_CTX ctx = xcalloc(1, sizeof(*ctx));

    ctx->flags = flags;

    if (flags & RPMDIGEST_MD5) {
	ctx->digestlen = 16;
	ctx->datalen = 64;
	ctx->param = xcalloc(1, sizeof(md5Param));
	ctx->Reset = (void *) md5Reset;
	ctx->Update = (void *) md5Update;
	ctx->Digest = (void *) md5Digest;
    }

    if (flags & RPMDIGEST_SHA1) {
	ctx->digestlen = 20;
	ctx->datalen = 64;
	ctx->param = xcalloc(1, sizeof(sha1Param));
	ctx->Reset = (void *) sha1Reset;
	ctx->Update = (void *) sha1Update;
	ctx->Digest = (void *) sha1Digest;
    }

    (void) (*ctx->Reset) (ctx->param);

DPRINTF((stderr, "*** Init(%x) ctx %p param %p\n", flags, ctx, ctx->param));
    return ctx;
}

void
rpmDigestUpdate(DIGEST_CTX ctx, const void * data, size_t len)
{
DPRINTF((stderr, "*** Update(%p,%p,%d) param %p \"%s\"\n", ctx, data, len, ctx->param, ((char *)data)));
    (void) (*ctx->Update) (ctx->param, data, len);
}

static int _ie = 0x44332211;
/*@-redef@*/
static union _dendian {
/*@unused@*/ int i;
    char b[4];
} *_endian = (union _dendian *)&_ie;
/*@=redef@*/
#define        IS_BIG_ENDIAN()         (_endian->b[0] == '\x44')
#define        IS_LITTLE_ENDIAN()      (_endian->b[0] == '\x11')

void
rpmDigestFinal(/*@only@*/ DIGEST_CTX ctx, /*@out@*/ void ** datap,
	/*@out@*/ size_t *lenp, int asAscii)
{
    uint32 * digest = xmalloc(ctx->digestlen);
    char * t;
    int i;

DPRINTF((stderr, "*** Final(%p,%p,%p,%d) param %p digest %p\n", ctx, datap, lenp, asAscii, ctx->param, digest));
    (void) (*ctx->Digest) (ctx->param, digest);

    if (IS_LITTLE_ENDIAN())
    for (i = 0; i < (ctx->digestlen/sizeof(uint32)); i++)
	digest[i] = swapu32(digest[i]);

    /* Return final digest. */
    if (!asAscii) {
	if (lenp) *lenp = ctx->digestlen;
	if (datap) {
	    *datap = digest;
	    digest = NULL;
	}
    } else {
	if (lenp) *lenp = (2*ctx->digestlen) + 1;
	if (datap) {
	    const byte * s = (const byte *) digest;
	    static const char hex[] = "0123456789abcdef";

	    *datap = t = xmalloc((2*ctx->digestlen) + 1);
	    for (i = 0 ; i < ctx->digestlen; i++) {
		*t++ = hex[ (unsigned)((*s >> 4) & 0x0f) ];
		*t++ = hex[ (unsigned)((*s++   ) & 0x0f) ];
	    }
	    *t = '\0';
	}
    }
    if (digest) {
	memset(digest, 0, ctx->digestlen);	/* In case it's sensitive */
	free(digest);
    }
    free(ctx->param);
    memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
    free(ctx);
}