Eliminate several copy-paste hex converters, use pgpHexStr() instead
[platform/upstream/rpm.git] / rpmio / digest.c
1 /** \ingroup signature
2  * \file rpmio/digest.c
3  */
4
5 #include "system.h"
6
7 #include "rpmio/digest.h"
8
9 #include "debug.h"
10
11 #ifdef  SHA_DEBUG
12 #define DPRINTF(_a)     fprintf _a
13 #else
14 #define DPRINTF(_a)
15 #endif
16
17
18 /**
19  * MD5/SHA1 digest private data.
20  */
21 struct DIGEST_CTX_s {
22     rpmDigestFlags flags;       /*!< Bit(s) to control digest operation. */
23     HASHContext *hashctx;       /*!< Internal NSS hash context. */
24 };
25
26 DIGEST_CTX
27 rpmDigestDup(DIGEST_CTX octx)
28 {
29     DIGEST_CTX nctx;
30     nctx = memcpy(xcalloc(1, sizeof(*nctx)), octx, sizeof(*nctx));
31     nctx->hashctx = HASH_Clone(octx->hashctx);
32     if (nctx->hashctx == NULL) {
33         fprintf(stderr, "HASH_Clone failed\n");
34         exit(EXIT_FAILURE);  /* FIX: callers do not bother checking error return */
35     }
36     return nctx;
37 }
38
39 static HASH_HashType
40 getHashType(pgpHashAlgo hashalgo)
41 {
42     switch (hashalgo) {
43     case PGPHASHALGO_MD5:
44         return HASH_AlgMD5;
45         break;
46     case PGPHASHALGO_SHA1:
47         return HASH_AlgSHA1;
48         break;
49     case PGPHASHALGO_SHA256:
50         return HASH_AlgSHA256;
51         break;
52     case PGPHASHALGO_SHA384:
53         return HASH_AlgSHA384;
54         break;
55     case PGPHASHALGO_SHA512:
56         return HASH_AlgSHA512;
57         break;
58     case PGPHASHALGO_RIPEMD160:
59     case PGPHASHALGO_MD2:
60     case PGPHASHALGO_TIGER192:
61     case PGPHASHALGO_HAVAL_5_160:
62     default:
63         return HASH_AlgNULL;
64         break;
65     }
66 }
67
68 size_t
69 rpmDigestLength(pgpHashAlgo hashalgo)
70 {
71     return HASH_ResultLen(getHashType(hashalgo));
72 }
73
74 DIGEST_CTX
75 rpmDigestInit(pgpHashAlgo hashalgo, rpmDigestFlags flags)
76 {
77     HASH_HashType type;
78     DIGEST_CTX ctx = xcalloc(1, sizeof(*ctx));
79
80     ctx->flags = flags;
81
82     type = getHashType(hashalgo);
83     if (type == HASH_AlgNULL) {
84         free(ctx);
85         return NULL;
86     }
87
88     ctx->hashctx = HASH_Create(type);
89     if (ctx->hashctx == NULL) {
90         free(ctx);
91         return NULL;
92     }
93
94     HASH_Begin(ctx->hashctx);
95     
96 DPRINTF((stderr, "*** Init(%x) ctx %p hashctx %p\n", flags, ctx, ctx->hashctx));
97     return ctx;
98 }
99
100 int
101 rpmDigestUpdate(DIGEST_CTX ctx, const void * data, size_t len)
102 {
103     size_t partlen;
104     const unsigned char *ptr = data;
105
106     if (ctx == NULL)
107         return -1;
108
109 DPRINTF((stderr, "*** Update(%p,%p,%zd) hashctx %p \"%s\"\n", ctx, data, len, ctx->hashctx, ((char *)data)));
110    partlen = ~(unsigned int)0xFF;
111    while (len > 0) {
112         if (len < partlen) {
113                 partlen = len;
114         }
115         HASH_Update(ctx->hashctx, ptr, partlen);
116         ptr += partlen;
117         len -= partlen;
118    }
119    return 0;
120 }
121
122 int
123 rpmDigestFinal(DIGEST_CTX ctx, void ** datap, size_t *lenp, int asAscii)
124 {
125     unsigned char * digest;
126     size_t digestlen;
127
128     if (ctx == NULL)
129         return -1;
130     digestlen = HASH_ResultLenContext(ctx->hashctx);
131     digest = xmalloc(digestlen);
132
133 DPRINTF((stderr, "*** Final(%p,%p,%p,%zd) hashctx %p digest %p\n", ctx, datap, lenp, asAscii, ctx->hashctx, digest));
134 /* FIX: check rc */
135     HASH_End(ctx->hashctx, digest, (unsigned int *) &digestlen, digestlen);
136
137     /* Return final digest. */
138     if (!asAscii) {
139         if (lenp) *lenp = digestlen;
140         if (datap) {
141             *datap = digest;
142             digest = NULL;
143         }
144     } else {
145         if (lenp) *lenp = (2*digestlen) + 1;
146         if (datap) {
147             const uint8_t * s = (const uint8_t *) digest;
148             *datap = pgpHexStr(s, digestlen);
149         }
150     }
151     if (digest) {
152         memset(digest, 0, digestlen);   /* In case it's sensitive */
153         free(digest);
154     }
155     HASH_Destroy(ctx->hashctx);
156     memset(ctx, 0, sizeof(*ctx));       /* In case it's sensitive */
157     free(ctx);
158     return 0;
159 }
160
161 void fdInitDigest(FD_t fd, pgpHashAlgo hashalgo, int flags)
162 {
163     FDDIGEST_t fddig = fd->digests + fd->ndigests;
164     if (fddig != (fd->digests + FDDIGEST_MAX)) {
165         fd->ndigests++;
166         fddig->hashalgo = hashalgo;
167         fdstat_enter(fd, FDSTAT_DIGEST);
168         fddig->hashctx = rpmDigestInit(hashalgo, flags);
169         fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
170     }
171 }
172
173 void fdUpdateDigests(FD_t fd, const unsigned char * buf, size_t buflen)
174 {
175     int i;
176
177     if (buf != NULL && buflen > 0)
178     for (i = fd->ndigests - 1; i >= 0; i--) {
179         FDDIGEST_t fddig = fd->digests + i;
180         if (fddig->hashctx == NULL)
181             continue;
182         fdstat_enter(fd, FDSTAT_DIGEST);
183         (void) rpmDigestUpdate(fddig->hashctx, buf, buflen);
184         fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) buflen);
185     }
186 }
187
188 void fdFiniDigest(FD_t fd, pgpHashAlgo hashalgo,
189                 void ** datap,
190                 size_t * lenp,
191                 int asAscii)
192 {
193     int imax = -1;
194     int i;
195
196     for (i = fd->ndigests - 1; i >= 0; i--) {
197         FDDIGEST_t fddig = fd->digests + i;
198         if (fddig->hashctx == NULL)
199             continue;
200         if (i > imax) imax = i;
201         if (fddig->hashalgo != hashalgo)
202             continue;
203         fdstat_enter(fd, FDSTAT_DIGEST);
204         (void) rpmDigestFinal(fddig->hashctx, datap, lenp, asAscii);
205         fdstat_exit(fd, FDSTAT_DIGEST, (ssize_t) 0);
206         fddig->hashctx = NULL;
207         break;
208     }
209     if (i < 0) {
210         if (datap) *datap = NULL;
211         if (lenp) *lenp = 0;
212     }
213
214     fd->ndigests = imax;
215     if (i < imax)
216         fd->ndigests++;         /* convert index to count */
217 }
218
219
220 void fdStealDigest(FD_t fd, pgpDig dig)
221 {
222     int i;
223     for (i = fd->ndigests - 1; i >= 0; i--) {
224         FDDIGEST_t fddig = fd->digests + i;
225         if (fddig->hashctx != NULL)
226         switch (fddig->hashalgo) {
227         case PGPHASHALGO_MD5:
228 assert(dig->md5ctx == NULL);
229             dig->md5ctx = fddig->hashctx;
230             fddig->hashctx = NULL;
231             break;
232         case PGPHASHALGO_SHA1:
233         case PGPHASHALGO_SHA256:
234         case PGPHASHALGO_SHA384:
235         case PGPHASHALGO_SHA512:
236 assert(dig->sha1ctx == NULL);
237             dig->sha1ctx = fddig->hashctx;
238             fddig->hashctx = NULL;
239             break;
240         default:
241             break;
242         }
243     }
244 }