]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/khash.c
2 This file is part of systemd.
4 Copyright 2016 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include <linux/if_alg.h>
22 #include <sys/socket.h>
24 #include "alloc-util.h"
26 #include "hexdecoct.h"
30 #include "string-util.h"
33 /* On current kernels the maximum digest (according to "grep digestsize /proc/crypto | sort -u") is actually 32, but
34 * let's add some extra room, the few wasted bytes don't really matter... */
35 #define LONGEST_DIGEST 128
40 uint8_t digest
[LONGEST_DIGEST
+1];
45 int khash_new_with_key(khash
**ret
, const char *algorithm
, const void *key
, size_t key_size
) {
48 struct sockaddr_alg alg
;
50 .alg
.salg_family
= AF_ALG
,
51 .alg
.salg_type
= "hash",
54 _cleanup_(khash_unrefp
) khash
*h
= NULL
;
55 _cleanup_close_
int fd
= -1;
59 assert(key
|| key_size
== 0);
61 /* Filter out an empty algorithm early, as we do not support an algorithm by that name. */
62 if (isempty(algorithm
))
65 /* Overly long hash algorithm names we definitely do not support */
66 if (strlen(algorithm
) >= sizeof(sa
.alg
.salg_name
))
69 fd
= socket(AF_ALG
, SOCK_SEQPACKET
|SOCK_CLOEXEC
, 0);
73 strcpy((char*) sa
.alg
.salg_name
, algorithm
);
74 if (bind(fd
, &sa
.sa
, sizeof(sa
)) < 0) {
81 if (setsockopt(fd
, SOL_ALG
, ALG_SET_KEY
, key
, key_size
) < 0)
89 h
->fd
= accept4(fd
, NULL
, 0, SOCK_CLOEXEC
);
93 h
->algorithm
= strdup(algorithm
);
97 /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
98 (void) send(h
->fd
, NULL
, 0, 0);
100 /* Figure out the digest size */
101 n
= recv(h
->fd
, h
->digest
, sizeof(h
->digest
), 0);
104 if (n
>= LONGEST_DIGEST
) /* longer than what we expected? If so, we don't support this */
107 h
->digest_size
= (size_t) n
;
108 h
->digest_valid
= true;
110 /* Temporary fix for rc kernel bug: https://bugzilla.redhat.com/show_bug.cgi?id=1395896 */
111 (void) send(h
->fd
, NULL
, 0, 0);
119 int khash_new(khash
**ret
, const char *algorithm
) {
120 return khash_new_with_key(ret
, algorithm
, NULL
, 0);
123 khash
* khash_unref(khash
*h
) {
134 int khash_dup(khash
*h
, khash
**ret
) {
135 _cleanup_(khash_unrefp
) khash
*copy
= NULL
;
140 copy
= newdup(khash
, h
, 1);
145 copy
->algorithm
= strdup(h
->algorithm
);
146 if (!copy
->algorithm
)
149 copy
->fd
= accept4(h
->fd
, NULL
, 0, SOCK_CLOEXEC
);
159 const char *khash_get_algorithm(khash
*h
) {
165 size_t khash_get_size(khash
*h
) {
168 return h
->digest_size
;
171 int khash_reset(khash
*h
) {
176 n
= send(h
->fd
, NULL
, 0, 0);
180 h
->digest_valid
= false;
185 int khash_put(khash
*h
, const void *buffer
, size_t size
) {
189 assert(buffer
|| size
== 0);
194 n
= send(h
->fd
, buffer
, size
, MSG_MORE
);
198 h
->digest_valid
= false;
203 int khash_put_iovec(khash
*h
, const struct iovec
*iovec
, size_t n
) {
205 mh
.msg_iov
= (struct iovec
*) iovec
,
211 assert(iovec
|| n
== 0);
216 k
= sendmsg(h
->fd
, &mh
, MSG_MORE
);
220 h
->digest_valid
= false;
225 static int retrieve_digest(khash
*h
) {
233 n
= recv(h
->fd
, h
->digest
, h
->digest_size
, 0);
236 if ((size_t) n
!= h
->digest_size
) /* digest size changed? */
239 h
->digest_valid
= true;
244 int khash_digest_data(khash
*h
, const void **ret
) {
250 r
= retrieve_digest(h
);
258 int khash_digest_string(khash
*h
, char **ret
) {
265 r
= retrieve_digest(h
);
269 p
= hexmem(h
->digest
, h
->digest_size
);