]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/khash.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2016 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
21 #include <linux/if_alg.h>
23 #include <sys/socket.h>
25 #include "alloc-util.h"
27 #include "hexdecoct.h"
31 #include "string-util.h"
34 /* On current kernels the maximum digest (according to "grep digestsize /proc/crypto | sort -u") is actually 32, but
35 * let's add some extra room, the few wasted bytes don't really matter... */
36 #define LONGEST_DIGEST 128
41 uint8_t digest
[LONGEST_DIGEST
+1];
46 int khash_new_with_key(khash
**ret
, const char *algorithm
, const void *key
, size_t key_size
) {
49 struct sockaddr_alg alg
;
51 .alg
.salg_family
= AF_ALG
,
52 .alg
.salg_type
= "hash",
55 _cleanup_(khash_unrefp
) khash
*h
= NULL
;
56 _cleanup_close_
int fd
= -1;
60 assert(key
|| key_size
== 0);
62 /* Filter out an empty algorithm early, as we do not support an algorithm by that name. */
63 if (isempty(algorithm
))
66 /* Overly long hash algorithm names we definitely do not support */
67 if (strlen(algorithm
) >= sizeof(sa
.alg
.salg_name
))
70 fd
= socket(AF_ALG
, SOCK_SEQPACKET
|SOCK_CLOEXEC
, 0);
74 strcpy((char*) sa
.alg
.salg_name
, algorithm
);
75 if (bind(fd
, &sa
.sa
, sizeof(sa
)) < 0) {
82 if (setsockopt(fd
, SOL_ALG
, ALG_SET_KEY
, key
, key_size
) < 0)
90 h
->fd
= accept4(fd
, NULL
, 0, SOCK_CLOEXEC
);
94 h
->algorithm
= strdup(algorithm
);
98 /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
99 (void) send(h
->fd
, NULL
, 0, 0);
101 /* Figure out the digest size */
102 n
= recv(h
->fd
, h
->digest
, sizeof(h
->digest
), 0);
105 if (n
>= LONGEST_DIGEST
) /* longer than what we expected? If so, we don't support this */
108 h
->digest_size
= (size_t) n
;
109 h
->digest_valid
= true;
111 /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
112 (void) send(h
->fd
, NULL
, 0, 0);
120 int khash_new(khash
**ret
, const char *algorithm
) {
121 return khash_new_with_key(ret
, algorithm
, NULL
, 0);
124 khash
* khash_unref(khash
*h
) {
135 int khash_dup(khash
*h
, khash
**ret
) {
136 _cleanup_(khash_unrefp
) khash
*copy
= NULL
;
141 copy
= newdup(khash
, h
, 1);
146 copy
->algorithm
= strdup(h
->algorithm
);
147 if (!copy
->algorithm
)
150 copy
->fd
= accept4(h
->fd
, NULL
, 0, SOCK_CLOEXEC
);
160 const char *khash_get_algorithm(khash
*h
) {
166 size_t khash_get_size(khash
*h
) {
169 return h
->digest_size
;
172 int khash_reset(khash
*h
) {
177 n
= send(h
->fd
, NULL
, 0, 0);
181 h
->digest_valid
= false;
186 int khash_put(khash
*h
, const void *buffer
, size_t size
) {
190 assert(buffer
|| size
== 0);
195 n
= send(h
->fd
, buffer
, size
, MSG_MORE
);
199 h
->digest_valid
= false;
204 int khash_put_iovec(khash
*h
, const struct iovec
*iovec
, size_t n
) {
206 mh
.msg_iov
= (struct iovec
*) iovec
,
212 assert(iovec
|| n
== 0);
217 k
= sendmsg(h
->fd
, &mh
, MSG_MORE
);
221 h
->digest_valid
= false;
226 static int retrieve_digest(khash
*h
) {
234 n
= recv(h
->fd
, h
->digest
, h
->digest_size
, 0);
237 if ((size_t) n
!= h
->digest_size
) /* digest size changed? */
240 h
->digest_valid
= true;
245 int khash_digest_data(khash
*h
, const void **ret
) {
251 r
= retrieve_digest(h
);
259 int khash_digest_string(khash
*h
, char **ret
) {
266 r
= retrieve_digest(h
);
270 p
= hexmem(h
->digest
, h
->digest_size
);