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
)
43 /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
44 See <https://patchwork.kernel.org/patch/9308641/>. */
48 int cfd
= socket (AF_ALG
, SOCK_SEQPACKET
, 0);
53 struct sockaddr_alg salg
= {
54 .salg_family
= AF_ALG
,
57 /* Avoid calling both strcpy and strlen. */
58 for (int i
= 0; (salg
.salg_name
[i
] = alg
[i
]); i
++)
59 if (i
== sizeof salg
.salg_name
- 1)
65 int ret
= bind (cfd
, (struct sockaddr
*) &salg
, sizeof salg
);
68 result
= -EAFNOSUPPORT
;
72 int ofd
= accept (cfd
, NULL
, 0);
75 result
= -EAFNOSUPPORT
;
81 ssize_t size
= (len
> BLOCKSIZE
? BLOCKSIZE
: len
);
82 if (send (ofd
, buffer
, size
, MSG_MORE
) != size
)
92 if (read (ofd
, resblock
, hashlen
) != hashlen
)
105 afalg_stream (FILE *stream
, const char *alg
,
106 void *resblock
, ssize_t hashlen
)
108 int cfd
= socket (AF_ALG
, SOCK_SEQPACKET
, 0);
110 return -EAFNOSUPPORT
;
116 struct sockaddr_alg salg
= {
117 .salg_family
= AF_ALG
,
120 /* Avoid calling both strcpy and strlen. */
121 for (int i
= 0; (salg
.salg_name
[i
] = alg
[i
]); i
++)
122 if (i
== sizeof salg
.salg_name
- 1)
128 int ret
= bind (cfd
, (struct sockaddr
*) &salg
, sizeof salg
);
131 result
= -EAFNOSUPPORT
;
135 int ofd
= accept (cfd
, NULL
, 0);
138 result
= -EAFNOSUPPORT
;
142 /* if file is a regular file, attempt sendfile to pipe the data. */
143 fd
= fileno (stream
);
144 if (fstat (fd
, &st
) == 0
145 && (S_ISREG (st
.st_mode
) || S_TYPEISSHM (&st
) || S_TYPEISTMO (&st
))
146 && 0 < st
.st_size
&& st
.st_size
<= SYS_BUFSIZE_MAX
)
148 /* Make sure the offset of fileno (stream) reflects how many bytes
149 have been read from stream before this function got invoked.
150 Note: fflush on an input stream after ungetc does not work as expected
151 on some platforms. Therefore this situation is not supported here. */
154 #if defined _WIN32 && ! defined __CYGWIN__
162 off_t nbytes
= st
.st_size
- lseek (fd
, 0, SEEK_CUR
);
163 /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
164 See <https://patchwork.kernel.org/patch/9308641/>. */
167 result
= -EAFNOSUPPORT
;
170 if (sendfile (ofd
, fd
, NULL
, nbytes
) != nbytes
)
178 /* sendfile not possible, do a classic read-write loop. */
182 while ((size
= fread (buf
, 1, sizeof buf
, stream
)))
185 if (send (ofd
, buf
, size
, MSG_MORE
) != size
)
196 /* On Linux < 4.9, the value for an empty stream is wrong (all zeroes).
197 See <https://patchwork.kernel.org/patch/9308641/>. */
200 result
= -EAFNOSUPPORT
;
205 if (read (ofd
, resblock
, hashlen
) != hashlen
)