1 /* af_alg.c - Functions to compute message digest from file streams using
2 Linux kernel crypto API.
3 Copyright (C) 2018 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by the
7 Free Software Foundation; either version 2, or (at your option) any
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
18 /* Written by Matteo Croce <mcroce@redhat.com>, 2018. */
22 #if USE_LINUX_CRYPTO_API
30 #include <linux/if_alg.h>
32 #include <sys/sendfile.h>
33 #include <sys/socket.h>
35 #include "sys-limits.h"
37 #define BLOCKSIZE 32768
40 afalg_buffer (const char *buffer
, size_t len
, const char *alg
,
41 void *resblock
, ssize_t hashlen
)
45 /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
46 See <https://patchwork.kernel.org/patch/9308641/>. */
51 struct sockaddr_alg salg
= {
52 .salg_family
= AF_ALG
,
55 /* Avoid calling both strcpy and strlen. */
56 for (int i
= 0; (salg
.salg_name
[i
] = alg
[i
]); i
++)
57 if (i
== sizeof salg
.salg_name
- 1)
60 int cfd
= socket (AF_ALG
, SOCK_SEQPACKET
, 0);
64 if (bind (cfd
, (struct sockaddr
*) &salg
, sizeof salg
) != 0)
66 result
= -EAFNOSUPPORT
;
70 ofd
= accept (cfd
, NULL
, 0);
73 result
= -EAFNOSUPPORT
;
79 ssize_t size
= (len
> BLOCKSIZE
? BLOCKSIZE
: len
);
80 if (send (ofd
, buffer
, size
, MSG_MORE
) != size
)
90 if (read (ofd
, resblock
, hashlen
) != hashlen
)
103 afalg_stream (FILE *stream
, const char *alg
,
104 void *resblock
, ssize_t hashlen
)
110 struct sockaddr_alg salg
= {
111 .salg_family
= AF_ALG
,
114 /* Avoid calling both strcpy and strlen. */
115 for (int i
= 0; (salg
.salg_name
[i
] = alg
[i
]); i
++)
116 if (i
== sizeof salg
.salg_name
- 1)
119 int cfd
= socket (AF_ALG
, SOCK_SEQPACKET
, 0);
121 return -EAFNOSUPPORT
;
123 if (bind (cfd
, (struct sockaddr
*) &salg
, sizeof salg
) != 0)
125 result
= -EAFNOSUPPORT
;
129 ofd
= accept (cfd
, NULL
, 0);
132 result
= -EAFNOSUPPORT
;
136 /* if file is a regular file, attempt sendfile to pipe the data. */
137 fd
= fileno (stream
);
138 if (fstat (fd
, &st
) == 0
139 && (S_ISREG (st
.st_mode
) || S_TYPEISSHM (&st
) || S_TYPEISTMO (&st
))
140 && 0 < st
.st_size
&& st
.st_size
<= SYS_BUFSIZE_MAX
)
142 /* Make sure the offset of fileno (stream) reflects how many bytes
143 have been read from stream before this function got invoked.
144 Note: fflush on an input stream after ungetc does not work as expected
145 on some platforms. Therefore this situation is not supported here. */
148 #if defined _WIN32 && ! defined __CYGWIN__
156 off_t nbytes
= st
.st_size
- lseek (fd
, 0, SEEK_CUR
);
157 /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
158 See <https://patchwork.kernel.org/patch/9308641/>. */
161 result
= -EAFNOSUPPORT
;
164 if (sendfile (ofd
, fd
, NULL
, nbytes
) != nbytes
)
172 /* sendfile not possible, do a classic read-write loop. */
176 while ((size
= fread (buf
, 1, sizeof buf
, stream
)))
179 if (send (ofd
, buf
, size
, MSG_MORE
) != size
)
190 /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
191 See <https://patchwork.kernel.org/patch/9308641/>. */
194 result
= -EAFNOSUPPORT
;
199 if (read (ofd
, resblock
, hashlen
) != hashlen
)