]> git.ipfire.org Git - people/stevee/pakfire.git/blame - src/libpakfire/digest.c
digests: Add a compute and comparison function
[people/stevee/pakfire.git] / src / libpakfire / digest.c
CommitLineData
c52e0148
MT
1/*#############################################################################
2# #
3# Pakfire - The IPFire package management system #
4# Copyright (C) 2022 Pakfire development team #
5# #
6# This program is free software: you can redistribute it and/or modify #
7# it under the terms of the GNU General Public License as published by #
8# the Free Software Foundation, either version 3 of the License, or #
9# (at your option) any later version. #
10# #
11# This program is distributed in the hope that it will be useful, #
12# but WITHOUT ANY WARRANTY; without even the implied warranty of #
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14# GNU General Public License for more details. #
15# #
16# You should have received a copy of the GNU General Public License #
17# along with this program. If not, see <http://www.gnu.org/licenses/>. #
18# #
19#############################################################################*/
293881bc
MT
20
21#include <stdio.h>
22
23#include <openssl/crypto.h>
24#include <openssl/err.h>
25#include <openssl/evp.h>
26
27#include <pakfire/digest.h>
28#include <pakfire/logging.h>
29#include <pakfire/pakfire.h>
30#include <pakfire/private.h>
31
32static EVP_MD_CTX* __pakfire_digest_setup(struct pakfire* pakfire, const EVP_MD* md) {
33 EVP_MD_CTX* ctx = NULL;
34 int r;
35
36 // Setup a new context
37 ctx = EVP_MD_CTX_new();
38 if (!ctx) {
39 ERROR(pakfire, "Could not initialize OpenSSL context: %s\n",
40 ERR_error_string(ERR_get_error(), NULL));
41 r = 1;
42 goto ERROR;
43 }
44
45 // Setup digest
46 r = EVP_DigestInit_ex(ctx, md, NULL);
47 if (r != 1) {
48 ERROR(pakfire, "Could not setup digest: %s\n",
49 ERR_error_string(ERR_get_error(), NULL));
50 r = 1;
51 goto ERROR;
52 }
53
54 return ctx;
55
56ERROR:
57 if (ctx)
58 EVP_MD_CTX_free(ctx);
59
60 return NULL;
61}
62
63int pakfire_digests_compute_from_file(struct pakfire* pakfire,
64 struct pakfire_digests* digests, const int types, FILE* f) {
65 EVP_MD_CTX* sha512_ctx = NULL;
66 EVP_MD_CTX* sha256_ctx = NULL;
67 char buffer[PAKFIRE_BUFFER_SIZE];
68 int r = 1;
69
70 // Initialize context for SHA-512
71 if (types & PAKFIRE_DIGEST_SHA512) {
72 sha512_ctx = __pakfire_digest_setup(pakfire, EVP_sha512());
73 if (!sha512_ctx)
74 goto ERROR;
75 }
76
77 // Initialize context for SHA-256
78 if (types & PAKFIRE_DIGEST_SHA256) {
79 sha512_ctx = __pakfire_digest_setup(pakfire, EVP_sha256());
80 if (!sha512_ctx)
81 goto ERROR;
82 }
83
84 // Read the file into the hash functions
85 while (!feof(f)) {
86 size_t bytes_read = fread(buffer, 1, sizeof(buffer), f);
87
88 // Raise any reading errors
89 if (ferror(f)) {
90 r = 1;
91 goto ERROR;
92 }
93
94 // SHA-512
95 r = EVP_DigestUpdate(sha512_ctx, buffer, bytes_read);
96 if (r != 1) {
97 ERROR(pakfire, "EVP_Digest_Update() failed: %s\n",
98 ERR_error_string(ERR_get_error(), NULL));
99 r = 1;
100 goto ERROR;
101 }
102
103 // SHA-256
104 r = EVP_DigestUpdate(sha256_ctx, buffer, bytes_read);
105 if (r != 1) {
106 ERROR(pakfire, "EVP_Digest_Update() failed: %s\n",
107 ERR_error_string(ERR_get_error(), NULL));
108 r = 1;
109 goto ERROR;
110 }
111 }
112
113 // Finalize SHA-512
114 r = EVP_DigestFinal_ex(sha512_ctx, digests->sha512, NULL);
115 if (r != 1) {
116 ERROR(pakfire, "EVP_DigestFinal_ex() failed: %s\n",
117 ERR_error_string(ERR_get_error(), NULL));
118 r = 1;
119 goto ERROR;
120 }
121
122 // Finalize SHA-256
123 r = EVP_DigestFinal_ex(sha256_ctx, digests->sha256, NULL);
124 if (r != 1) {
125 ERROR(pakfire, "EVP_DigestFinal_ex() failed: %s\n",
126 ERR_error_string(ERR_get_error(), NULL));
127 r = 1;
128 goto ERROR;
129 }
130
131ERROR:
132 if (sha512_ctx)
133 EVP_MD_CTX_free(sha512_ctx);
134 if (sha256_ctx)
135 EVP_MD_CTX_free(sha256_ctx);
136
137 return r;
138}
139
140int pakfire_digests_compare(struct pakfire* pakfire, const struct pakfire_digests* digests1,
141 const struct pakfire_digests* digests2, const int types) {
142 int r;
143
144 // Check if we are at least comparing one type
145 if (!types) {
146 errno = EINVAL;
147 return 1;
148 }
149
150 // Check SHA-512
151 if (types & PAKFIRE_DIGEST_SHA512) {
152 r = CRYPTO_memcmp(digests1->sha512, digests2->sha512, sizeof(digests1->sha512));
153 if (r) {
154 DEBUG(pakfire, "SHA-512 digest does not match\n");
155 return 1;
156 }
157 }
158
159 // Check SHA-256
160 if (types & PAKFIRE_DIGEST_SHA256) {
161 r = CRYPTO_memcmp(digests1->sha256, digests2->sha256, sizeof(digests1->sha256));
162 if (r) {
163 DEBUG(pakfire, "SHA-256 digest does not match\n");
164 return 1;
165 }
166 }
167
168 // All digests match
169 return 0;
170}