|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <config.h> |
|
|
|
|
|
#include "af_alg.h" |
|
|
|
|
|
#if USE_LINUX_CRYPTO_API |
|
|
|
|
|
#include <unistd.h> |
|
|
#include <string.h> |
|
|
#include <stdio.h> |
|
|
#include <errno.h> |
|
|
#include <linux/if_alg.h> |
|
|
#include <sys/stat.h> |
|
|
#include <sys/sendfile.h> |
|
|
#include <sys/socket.h> |
|
|
|
|
|
#include "sys-limits.h" |
|
|
|
|
|
#define BLOCKSIZE 32768 |
|
|
|
|
|
|
|
|
|
|
|
static int |
|
|
alg_socket (char const *alg) |
|
|
{ |
|
|
struct sockaddr_alg salg = { |
|
|
.salg_family = AF_ALG, |
|
|
.salg_type = "hash", |
|
|
}; |
|
|
|
|
|
for (size_t i = 0; (salg.salg_name[i] = alg[i]) != '\0'; i++) |
|
|
if (i == sizeof salg.salg_name - 1) |
|
|
|
|
|
return -EINVAL; |
|
|
|
|
|
int cfd = socket (AF_ALG, SOCK_SEQPACKET | SOCK_CLOEXEC, 0); |
|
|
if (cfd < 0) |
|
|
return -EAFNOSUPPORT; |
|
|
int ofd = (bind (cfd, (struct sockaddr *) &salg, sizeof salg) == 0 |
|
|
? accept4 (cfd, NULL, 0, SOCK_CLOEXEC) |
|
|
: -1); |
|
|
close (cfd); |
|
|
return ofd < 0 ? -EAFNOSUPPORT : ofd; |
|
|
} |
|
|
|
|
|
int |
|
|
afalg_buffer (const char *buffer, size_t len, const char *alg, |
|
|
void *resblock, ssize_t hashlen) |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (len == 0) |
|
|
return -EAFNOSUPPORT; |
|
|
|
|
|
int ofd = alg_socket (alg); |
|
|
if (ofd < 0) |
|
|
return ofd; |
|
|
|
|
|
int result; |
|
|
|
|
|
for (;;) |
|
|
{ |
|
|
ssize_t size = (len > BLOCKSIZE ? BLOCKSIZE : len); |
|
|
if (send (ofd, buffer, size, MSG_MORE) != size) |
|
|
{ |
|
|
result = -EAFNOSUPPORT; |
|
|
break; |
|
|
} |
|
|
buffer += size; |
|
|
len -= size; |
|
|
if (len == 0) |
|
|
{ |
|
|
result = read (ofd, resblock, hashlen) == hashlen ? 0 : -EAFNOSUPPORT; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
close (ofd); |
|
|
return result; |
|
|
} |
|
|
|
|
|
int |
|
|
afalg_stream (FILE *stream, const char *alg, |
|
|
void *resblock, ssize_t hashlen) |
|
|
{ |
|
|
int ofd = alg_socket (alg); |
|
|
if (ofd < 0) |
|
|
return ofd; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int fd = fileno (stream); |
|
|
int result; |
|
|
struct stat st; |
|
|
off_t off = ftello (stream); |
|
|
if (0 <= off && fstat (fd, &st) == 0 |
|
|
&& (S_ISREG (st.st_mode) || S_TYPEISSHM (&st) || S_TYPEISTMO (&st)) |
|
|
&& off < st.st_size && st.st_size - off < SYS_BUFSIZE_MAX) |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (fflush (stream)) |
|
|
result = -EIO; |
|
|
else |
|
|
{ |
|
|
off_t nbytes = st.st_size - off; |
|
|
if (sendfile (ofd, fd, &off, nbytes) == nbytes) |
|
|
{ |
|
|
if (read (ofd, resblock, hashlen) == hashlen) |
|
|
{ |
|
|
|
|
|
if (lseek (fd, off, SEEK_SET) != (off_t)-1) |
|
|
result = 0; |
|
|
else |
|
|
|
|
|
result = -EAFNOSUPPORT; |
|
|
} |
|
|
else |
|
|
|
|
|
result = -EAFNOSUPPORT; |
|
|
} |
|
|
else |
|
|
|
|
|
result = -EAFNOSUPPORT; |
|
|
} |
|
|
} |
|
|
else |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
off_t nseek = 0; |
|
|
|
|
|
for (;;) |
|
|
{ |
|
|
char buf[BLOCKSIZE]; |
|
|
|
|
|
|
|
|
size_t blocksize = (nseek == 0 && off < 0 ? 1 : BLOCKSIZE); |
|
|
ssize_t size = fread (buf, 1, blocksize, stream); |
|
|
if (size == 0) |
|
|
{ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result = ferror (stream) ? -EIO : nseek == 0 ? -EAFNOSUPPORT : 0; |
|
|
break; |
|
|
} |
|
|
nseek -= size; |
|
|
if (send (ofd, buf, size, MSG_MORE) != size) |
|
|
{ |
|
|
if (nseek == -1) |
|
|
{ |
|
|
|
|
|
|
|
|
ungetc ((unsigned char) buf[0], stream); |
|
|
result = -EAFNOSUPPORT; |
|
|
} |
|
|
else if (fseeko (stream, nseek, SEEK_CUR) == 0) |
|
|
|
|
|
result = -EAFNOSUPPORT; |
|
|
else |
|
|
result = -EIO; |
|
|
break; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if (feof (stream)) |
|
|
{ |
|
|
result = 0; |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
if (result == 0 && read (ofd, resblock, hashlen) != hashlen) |
|
|
{ |
|
|
if (nseek == 0 || fseeko (stream, nseek, SEEK_CUR) == 0) |
|
|
|
|
|
result = -EAFNOSUPPORT; |
|
|
else |
|
|
result = -EIO; |
|
|
} |
|
|
} |
|
|
close (ofd); |
|
|
return result; |
|
|
} |
|
|
|
|
|
#endif |
|
|
|