From: Herbert Xu Subject: RFC: Crypto API User-interface Date: Tue, 7 Sep 2010 16:42:13 +0800 Message-ID: <20100907084213.GA4610@gondor.apana.org.au> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii To: Linux Crypto Mailing List , netdev@vger.kernel.org Return-path: Content-Disposition: inline Sender: netdev-owner@vger.kernel.org List-Id: linux-crypto.vger.kernel.org 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 Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt