Hi:

This is what I am proposing for the Crypto API user-interface.

Note that this is the interface for operations.  There will be
a separate interface (most likely netlink) for configuring crypto
algorithms, e.g., picking a specific AES implementation as the
system default.

First of all let's have a quick look at what the user-space side
looks like for AEAD:

        int op;

        /* This fd corresponds to a tfm object. */
        tfmfd = socket(AF_ALG, SOCK_STREAM, 0);

        alg.type = "aead";
        alg.name = "ccm(aes)";
        bind(tfmfd, &alg, sizeof(alg));

        setsockopt(tfmfd, SOL_ALG, ALG_AEAD_SET_KEY, key, keylen);

The idea here is that each tfm corresponds to a listening socket.

        /* Each listen call generates one or more fds for input/output
         * that behave like pipes.
         */
        listen(tfmfd, 0);
        /* fd for encryption/decryption */
        opfd = accept(tfmfd, NULL, 0);
        /* fd for associated data */
        adfd = accept(tfmfd, NULL, 0);

Each session corresponds to one or more connections obtained from
that socket.  The number depends on the number of inputs/outputs
of that particular type of operation.  For most types, there will
be a s ingle connection/file descriptor that is used for both input
and output.  AEAD is one of the few that require two inputs.

        /* These may also be set through sendmsg(2) cmsgs. */
        op = ALG_AEAD_OP_ENCRYPT;
        setsockopt(opfd, SOL_ALG, ALG_AEAD_OP, op, sizeof(op));
        setsockopt(opfd, SOL_ALG, ALG_AEAD_SET_IV, iv, ivlen);

        /* Like pipes, larges writes will block!
         * For AEAD, ensure the socket buffer is large enough.
         * For ciphers, whenever the write blocks start reading.
         * For hashes, writes should never block.
         */
        write(opfd, plain, datalen);
        write(adfd, ad, adlen);

        /* The first read triggers the operation. */
        read(opfd, crypt, datalen);

        op = ALG_AEAD_OP_DECRYPT;
        setsockopt(opfd, SOL_ALG, ALG_AEAD_OP, op, sizeof(op));

        write(opfd, crypt, datalen);
        write(adfd, ad, adlen);

        /* Returns -1 with errno EBADMSG if auth fails */
        read(defd, plain, datalen);

        /* Zero-copy */
        splice(cryptfd, NULL, opfd, NULL, datalen, SPLICE_F_MOVE|SPLIFE_F_MORE);
        /* We allow writes to be split into multiple system calls. */
        splice(cryptfd2, NULL, opfd, NULL, datalen, SPLICE_F_MOVE);
        splice(adatafd, NULL, adfd, NULL, adlen, SPLICE_F_MOVE);

        /* For now reading is copy-only, if and when vmsplice
         * starts supporting zero-copy to user then we can do it
         * as well.
         */
        read(opfd, plain, datalen);

Ciphers/compression are pretty much the same sans adfd.

For hashes:

        /* This fd corresponds to a tfm object. */
        tfmfd = socket(AF_ALG, SOCK_STREAM, 0);

        alg.type = "hash";
        alg.name = "xcbc(aes)";
        bind(tfmfd, &alg, sizeof(alg));

        setsockopt(tfmfd, SOL_ALG, ALG_HASH_SET_KEY, key, keylen);

        /* Each listen call generates one or more fds for input/output
         * that behave like pipes.
         */
        listen(tfmfd, 0);
        /* fd for hashing */
        opfd = accept(tfmfd, NULL, 0);

        /* MSG_MORE prevents finalisation */
        send(opfd, plain, datalen, MSG_MORE);

        /* Reads partial hash state */
        read(opfd, state, statelen);

        /* Restore from a partial hash state */
        send(opfd, state, statelen, MSG_OOB);

        /* Finalise */
        send(opfd, plain, 0, 0);
        read(opfd, hash, hashlen);

Please comment.

Thanks,
-- 
Email: Herbert Xu <herb...@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
--
To unsubscribe from this list: send the line "unsubscribe linux-crypto" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to