Hi,

linux since 2.6.38 have userspace interface to cryptographic api. What do
you think about using this in busybox as alternative to internal hash
algorithms implementation? There is a sample code from my experimentation
in attachment.

#define _GNU_SOURCE

#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <poll.h>
#include <unistd.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include <linux/if_alg.h>

#define AF_ALG		38

enum hash_alg
{
	HASH_MD5 = 0,
	HASH_SHA1,
	HASH_SHA224,
	HASH_SHA256,
	HASH_SHA384,
	HASH_SHA512
};

const char *alg[] = {
	"md5",
	"sha1",
	"sha224",
	"sha256",
	"sha384",
	"sha512"
};

struct hash_ctx
{
	int psocket;
	int socket;
};

static const char HASH_STR[] = "hash";

int hash_init_ctx(struct hash_ctx *ctx, const char *alg)
{
	struct sockaddr_alg sa;
	int ret;

	ctx->psocket = socket(AF_ALG, SOCK_SEQPACKET, 0);
	if (ctx->psocket < 0) {
		perror("socket");
		return -1;
	}

	memset(&sa, 0, sizeof(sa));
	memcpy(sa.salg_type, HASH_STR, sizeof(HASH_STR));

	strncpy(sa.salg_name, alg, sizeof(sa.salg_name));

	ret = bind(ctx->psocket, (struct sockaddr *)&sa, sizeof(sa));
	if (ret < 0) {
		perror("bind");
		return -1;
	}

	ctx->socket = accept(ctx->psocket, NULL, NULL);
	if (ctx->socket < 0) {
		perror("accept");
		return -1;
	}

	return 0;
}

int hash_update(struct hash_ctx *ctx, uint8_t *buf, size_t bufsize)
{
	ssize_t nsend;

	do {
		nsend = send(ctx->socket, buf, bufsize, MSG_MORE);
		if (nsend < 0) {
			if (errno == EINTR || errno == EAGAIN) {
				continue;
			}
			perror("send");
			return -1;
		}
		bufsize -= nsend;
	} while (bufsize > 0);

	return 0;
}


int hash_finish(struct hash_ctx *ctx, uint8_t *buf, size_t *bufsize)
{
	struct msghdr msg;
	struct iovec iov[1];
	ssize_t nrecv;

	iov[0].iov_base = buf;
	iov[0].iov_len = *bufsize;

	memset(&msg, 0, sizeof(msg));
	msg.msg_iov = iov;
	msg.msg_iovlen = 1;

	nrecv = recvmsg(ctx->socket, &msg, 0);
	if (nrecv < 0) {
		perror("recvmsg");
		return -1;
	}

	if (msg.msg_flags & MSG_TRUNC) {
		fprintf(stderr, "hash truncated\n");
		return -1;
	}
	
	*bufsize = nrecv;
	return 0;
}

int hash_file(struct hash_ctx *ctx, const char *file)
{
	int fd, ret, pair[2];
	loff_t offset;
	ssize_t nbytes;

	fd = open(file, O_RDONLY);
	if (fd < 0) {
		perror("open");
		return -1;
	}

	ret = pipe(pair);
	if (ret < 0) {
		perror("pipe");
		return -1;
	}

	offset = 0;

	do {
		ssize_t nread, nwrite;

		nread = splice(fd, &offset, pair[1], NULL, 4096, 
			SPLICE_F_MORE | SPLICE_F_MOVE);
		if (nread < 0) {
			perror("splice");
			return -1;
		}

		nbytes = nread;

		while (nread > 0) {
			nwrite = splice(pair[0], NULL, ctx->socket, NULL, nread,
				SPLICE_F_MORE | SPLICE_F_MOVE);
			if (nwrite < 0) {
				perror("splice");
				return -1;
			}

			nread -= nwrite;
		}

	} while (nbytes > 0);

	return 0;
}

int main(int argc, char *argv[])
{
	int i, ret;
	uint8_t buf[512];
	size_t bufsize = sizeof(buf);
	struct hash_ctx ctx;

	if (argc != 3)	{
		fprintf(stderr, "Usage: %s hash_alg file", argv[0]);
		exit(EXIT_FAILURE);
	}

	ret = hash_init_ctx(&ctx, argv[1]);
	if (ret != 0) {
		exit(EXIT_FAILURE);
	}

	ret = hash_file(&ctx, argv[2]);
	if (ret != 0) {
		exit(EXIT_FAILURE);
	}

	ret = hash_finish(&ctx, buf, &bufsize);
	if (ret != 0) {
		exit(EXIT_FAILURE);
	}

	for (i = 0; i < bufsize; i++) {
		printf("%.2x", buf[i]);
	}
	puts("");
	
	return EXIT_SUCCESS;
}
_______________________________________________
busybox mailing list
[email protected]
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to