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 <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Tue, 2010-09-07 at 16:42 +0800, Herbert Xu wrote:
> 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);
This has much much higher overhead in terms of number of needed syscalls
than the previously proposed ioctl interface. Of course in case of large
data operation the overhead converges to just one or two (for AEAD) more
syscalls (1. ioctl vs. 2. write+read). But there will be many real
use-cases where all the setup of the fds will be done again and again.
And of course it adds an overhead in terms of number of file descriptors
needed for each crypto operation. Where the old interface had just
constant one fd overhead per lifetime of the process, this interface has
3 fds per crypto context in use.
> 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.
This is also serious performance penalty for now.
> 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);
Note, that one of frequent hash operations is duplicating the internal
hash state. How this would be done with this API?
--
Tomas Mraz
No matter how far down the wrong road you've gone, turn back.
Turkish proverb
Hello,
----- "Herbert Xu" <[email protected]> wrote:
> First of all let's have a quick look at what the user-space side
> looks like for AEAD:
>
> /* 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);
If nothing else, two consecutive accept() calls with different semantics go rather strongly against the spirit of the socket API IMHO.
> /* 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);
So that is 8 syscalls to initialize a single AEAD operation.
> /* 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.
> */
How does one know the buffer is large enough?
"Whenever the write blocks start reading" turns a trivial loop submitting one buffer-size at a time into something that would be much easier to get wrong.
> /* Zero-copy */
> splice(cryptfd, NULL, opfd, NULL, datalen,
> SPLICE_F_MOVE|SPLIFE_F_MORE);
So that is "zero copy on input if your data come from a file descriptor"? I'm not sure many applications will be able to take advantage of that, and there's still the output copy.
Also, is SPLICE_F_MOVE actually implemented?
Why use splice() at all? Simple write() gives the driver the __user pointers that can be used to access the underlying pages directly. Yanking user-space pages out from the process address space to make them "owned" by the crypto driver, causing more page faults when the process wants to reuse the buffer, does not seem like a performance improvement.
> Please comment.
I can't really see any advantage in trying to use existing syscalls for crypto when the syscalls were clearly not intended for the purpose. setsockopt() is fine for sockets because options are set up once per connection, and the connection very rarely lasts less than several milliseconds; crypto operation options have to be configured much more often.
7 syscalls to compute a single hash is very difficult to accept.
Mirek
On Tue, Sep 07, 2010 at 04:42:13PM +0800, Herbert Xu wrote:
> Hi:
>
> This is what I am proposing for the Crypto API user-interface.
Can you explain why we would ever want a userspace interface to it?
doing crypto in kernel for userspace consumers sis simply insane.
It's computational intensive code which has no business in kernel space
unless absolutely required (e.g. for kernel consumers). In addition
to that adding the context switch overhead and address space transitions
is god awfull too.
This all very much sounds like someone had far too much crack.
On Tue, Sep 07, 2010 at 07:27:47AM -0400, Miloslav Trmac wrote:
> Hello,
> ----- "Herbert Xu" <[email protected]> wrote:
> > First of all let's have a quick look at what the user-space side
> > looks like for AEAD:
> >
> > /* 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);
> If nothing else, two consecutive accept() calls with different semantics go rather strongly against the spirit of the socket API IMHO.
If you have a better suggestion of obtaining multiple fds for
multiple input streams please let us know.
> > /* 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);
> So that is 8 syscalls to initialize a single AEAD operation.
If this interface is fast enough for TCP, it ought to be fast
enough for crypto.
> > /* 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.
> > */
> How does one know the buffer is large enough?
For anything other than AEAD you don't have to know. As I said
it behaves just like a pipe. If you know how to use a pipe you'll
know how to deal with this.
For AEAD we need this as otherwise you can chew up an unlimited
amount of kernel memory.
> "Whenever the write blocks start reading" turns a trivial loop submitting one buffer-size at a time into something that would be much easier to get wrong.
We don't have a choice. We cannot allow user-space to use up
an unlimted amount of kernel memory. At some point you've got
to say stop.
Now the usual socket limits should be good enough for most users.
That is, if you're encrypting anything less than 128K you shouldn't
care.
If you need more just do a setsockopt (subject to limits set by
the admin of course).
> > /* Zero-copy */
> > splice(cryptfd, NULL, opfd, NULL, datalen,
> > SPLICE_F_MOVE|SPLIFE_F_MORE);
> So that is "zero copy on input if your data come from a file descriptor"? I'm not sure many applications will be able to take advantage of that, and there's still the output copy.
>
> Also, is SPLICE_F_MOVE actually implemented?
Actually it doesn't matter, it'll do zero-copy by default.
> Why use splice() at all? Simple write() gives the driver the __user pointers that can be used to access the underlying pages directly. Yanking user-space pages out from the process address space to make them "owned" by the crypto driver, causing more page faults when the process wants to reuse the buffer, does not seem like a performance improvement.
For someone working on security I thought you would've considered
the pitfalls of inventing yet another interface for moving data
between the kernel/user-space.
Also you're wrong about the page faults, splicing does not cause
additional page faults at all. This is the whole point of the
vmsplice(2) interface, we don't play with page tables.
Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Tue, Sep 07, 2010 at 10:06:46AM -0400, Christoph Hellwig wrote:
> On Tue, Sep 07, 2010 at 04:42:13PM +0800, Herbert Xu wrote:
> > Hi:
> >
> > This is what I am proposing for the Crypto API user-interface.
>
> Can you explain why we would ever want a userspace interface to it?
>
> doing crypto in kernel for userspace consumers sis simply insane.
> It's computational intensive code which has no business in kernel space
> unless absolutely required (e.g. for kernel consumers). In addition
> to that adding the context switch overhead and address space transitions
> is god awfull too.
>
> This all very much sounds like someone had far too much crack.
FWIW I don't care about user-space using kernel software crypto at
all. It's the security people that do.
The purpose of the user-space API is to export the hardware crypto
devices to user-space. This means PCI devices mostly, as things
like aesni-intel can already be used without kernel help.
Now as a side-effect if this means that we can shut the security
people up about adding another interface then all the better. But
I will certainly not go out of the way to add more crap to the
kernel for that purpose.
Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Tue, Sep 07, 2010 at 10:11:12PM +0800, Herbert Xu wrote:
> FWIW I don't care about user-space using kernel software crypto at
> all. It's the security people that do.
And since when did we care about their crack pipe dreams?
> The purpose of the user-space API is to export the hardware crypto
> devices to user-space. This means PCI devices mostly, as things
> like aesni-intel can already be used without kernel help.
I don't think they matter in practice. We have less than a handfull
of drivers for them, and with CPUs gaining proper instructions they
are even less useful. In addition any sane PCI card should just
allow userspace mapping of their descriptors.
> Now as a side-effect if this means that we can shut the security
> people up about adding another interface then all the better. But
> I will certainly not go out of the way to add more crap to the
> kernel for that purpose.
So what is the real use case for this? In addition to kernel bloat
the real fear I have is that the security wankers will just configure
the userspace crypto libraries to always use the kernel interface
just in case, and once that happens we will have to deal with the whole
mess. Especially for RHEL and Fedora where the inmantes now run the
asylum in that respect.
----- "Herbert Xu" <[email protected]> wrote:
> On Tue, Sep 07, 2010 at 07:27:47AM -0400, Miloslav Trmac wrote:
> > Hello,
> > ----- "Herbert Xu" <[email protected]> wrote:
> > > First of all let's have a quick look at what the user-space side
> > > looks like for AEAD:
> > >
> > > /* 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);
> > If nothing else, two consecutive accept() calls with different
> semantics go rather strongly against the spirit of the socket API
> IMHO.
>
> If you have a better suggestion of obtaining multiple fds for
> multiple input streams please let us know.
- Don't use a FD for associated data that is limited to 16? bytes
- Don't use file descriptors for input data at all, if it makes the interface so complex.
> > > /* 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);
> > So that is 8 syscalls to initialize a single AEAD operation.
>
> If this interface is fast enough for TCP, it ought to be fast
> enough for crypto.
Crypto has much smaller granularity than TCP. A single TLS handshake involves something on the order of 20 separate crypto operations in addition to setting up the four transforms used throughout the life of the session.
A single SHA-256 password verification is more than 5000 hash operations by default.
> > Why use splice() at all? Simple write() gives the driver the __user
> pointers that can be used to access the underlying pages directly.
> Yanking user-space pages out from the process address space to make
> them "owned" by the crypto driver, causing more page faults when the
> process wants to reuse the buffer, does not seem like a performance
> improvement.
>
> For someone working on security I thought you would've considered
> the pitfalls of inventing yet another interface for moving data
> between the kernel/user-space.
The data will in the usual case be in user-space memory, not in file descriptors. Existing low-level crypto libraries have no access to the file descriptors that are used to work with the data. And even in the case of TLS where the data does come through a file descriptor, a MAC is then computed on it - so at most half of the (steady-state) crypto is coming through a file descriptor.
Finally, when the application uses file descriptors, it uses them to transfer the _encrypted_ form of the data; it keeps plaintext in memory in order to use it. So avoiding the trip to userspace protects primarily the kind of data that does not need protecting.
Mirek
On Tue, Sep 07, 2010 at 10:24:27AM -0400, Christoph Hellwig wrote:
>
> I don't think they matter in practice. We have less than a handfull
> of drivers for them, and with CPUs gaining proper instructions they
> are even less useful. In addition any sane PCI card should just
> allow userspace mapping of their descriptors.
I totally agree that mainstream CPUs won't need this at all.
However we still have embedded users where the CPUs may not be
powerful enough per se or where they want to use their CPUs for
other work.
There are also cases such as the Niagra SPU which may not be
easy to manage from user-space (correct me if I'm wrong Dave).
> > Now as a side-effect if this means that we can shut the security
> > people up about adding another interface then all the better. But
> > I will certainly not go out of the way to add more crap to the
> > kernel for that purpose.
>
> So what is the real use case for this? In addition to kernel bloat
> the real fear I have is that the security wankers will just configure
> the userspace crypto libraries to always use the kernel interface
> just in case, and once that happens we will have to deal with the whole
> mess. Especially for RHEL and Fedora where the inmantes now run the
> asylum in that respect.
I will let the security people answer this :)
Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Tue, Sep 07, 2010 at 10:34:25AM -0400, Miloslav Trmac wrote:
>
> > > > /* 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);
> > > So that is 8 syscalls to initialize a single AEAD operation.
> >
> > If this interface is fast enough for TCP, it ought to be fast
> > enough for crypto.
> Crypto has much smaller granularity than TCP. A single TLS handshake involves something on the order of 20 separate crypto operations in addition to setting up the four transforms used throughout the life of the session.
>
> A single SHA-256 password verification is more than 5000 hash operations by default.
You're clearly one of those crazy security people.
If you're processing a small amount of data the last thing you want
is to go through the kernel if you care about performance.
Now on the other hand if you had to go through the kernel for
certification reasons then why are you talking about performance?
> The data will in the usual case be in user-space memory, not in file descriptors. Existing low-level crypto libraries have no access to the file descriptors that are used to work with the data. And even in the case of TLS where the data does come through a file descriptor, a MAC is then computed on it - so at most half of the (steady-state) crypto is coming through a file descriptor.
man vmsplice
Also learn to wrap your lines please.
Thanks,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Tue, Sep 7, 2010 at 4:11 PM, Herbert Xu <[email protected]> wrote:
>> > This is what I am proposing for the Crypto API user-interface.
>>
>> Can you explain why we would ever want a userspace interface to it?
>>
>> doing crypto in kernel for userspace consumers sis simply insane.
>> It's computational intensive code which has no business in kernel space
>> unless absolutely required (e.g. for kernel consumers). In addition
>> to that adding the context switch overhead and address space transitions
>> is god awfull too.
>>
>> This all very much sounds like someone had far too much crack.
>
> FWIW I don't care about user-space using kernel software crypto at
> all. It's the security people that do.
Then I'd suggest to not enforce your design over to people who have
thought and have interests on that. The NCR api which you rejected
(for not supporting kernel keyring - which your design also doesn't!),
has specific security goals and protects against specific threats.
This design here has been proposed by you quite many times in the past
and neither you, nor anyone else bothered implementing it. Now we have
two working implementations that offer user-space access to crypto
operations, (the openbsd cryptodev port), and NCR, but you discard
them and insist on a different design. Maybe yours is better (you have
to argue about that)... Probably I'd use it if it was there, but it
isn't.
regards,
Nikos
On Tue, Sep 07, 2010 at 10:34:25AM -0400, Miloslav Trmac wrote:
> - Don't use a FD for associated data that is limited to 16? bytes
>
> - Don't use file descriptors for input data at all, if it makes the interface so complex.
Calling into the kernel for 16 bytes of crypto is a braindead idea to
start with. To preve3nt idiots like you from abusing it we should
simply limit any userlevel crypto API to:
a) hardware crypto that is not directly user space accesible
b) page size or larger data
----- "Herbert Xu" <[email protected]> wrote:
> On Tue, Sep 07, 2010 at 10:34:25AM -0400, Miloslav Trmac wrote:
> >
> > > > > /* 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);
> > > > So that is 8 syscalls to initialize a single AEAD operation.
> > >
> > > If this interface is fast enough for TCP, it ought to be fast
> > > enough for crypto.
> > Crypto has much smaller granularity than TCP. A single TLS
> handshake involves something on the order of 20 separate crypto
> operations in addition to setting up the four transforms used
> throughout the life of the session.
> >
> > A single SHA-256 password verification is more than 5000 hash
> operations by default.
>
> If you're processing a small amount of data the last thing you want
> is to go through the kernel if you care about performance.
>
> Now on the other hand if you had to go through the kernel for
> certification reasons then why are you talking about performance?
Because in the real world people want both certification, features _and_ performance. If all they cared about is certification they could just as well buy a pencil.
Mirek
----- "Christoph Hellwig" <[email protected]> wrote:
> On Tue, Sep 07, 2010 at 10:34:25AM -0400, Miloslav Trmac wrote:
> > - Don't use a FD for associated data that is limited to 16? bytes
> >
> > - Don't use file descriptors for input data at all, if it makes the
> interface so complex.
>
> Calling into the kernel for 16 bytes of crypto is a braindead idea to
> start with. To preve3nt idiots like you
1) It was Herbert who used AEAD as an example
2) That's how AEAD works: One large input stream, one very small.
Mirek
On Tue, Sep 07, 2010 at 10:52:03AM -0400, Miloslav Trmac wrote:
> Because in the real world people want both certification, features _and_ performance. If all they cared about is certification they could just as well buy a pencil.
Okay Mr Smartass. Please put away your crackpipe and get down to earth.
There is absolutely no good reason to ever do crypto for userspace
applications in the kernel. If any certification requires that it's not
worth the paper it's written on. In fact there's more enough criticial
systems that do not even have separate kernel vs userspace boundaries.
On Tue, Sep 7, 2010 at 4:06 PM, Christoph Hellwig <[email protected]> wrote:
>> This is what I am proposing for the Crypto API user-interface.
>
> Can you explain why we would ever want a userspace interface to it?
>
> doing crypto in kernel for userspace consumers sis simply insane.
> It's computational intensive code which has no business in kernel space
> unless absolutely required (e.g. for kernel consumers). In addition
> to that adding the context switch overhead and address space transitions
> is god awfull too.
> This all very much sounds like someone had far too much crack.
Or that someone is not really aware of some cryptographic uses.
Embedded systems have crypto accelerators in hardware available
through kernel device drivers. In the systems I worked the
accelerators via a crypto device interface gave a 50x to 100x boost in
crypto operations and relieved the CPU from doing them.
regards,
Nikos
On Tue, Sep 07, 2010 at 04:57:04PM +0200, Nikos Mavrogiannopoulos wrote:
> Or that someone is not really aware of some cryptographic uses.
> Embedded systems have crypto accelerators in hardware available
> through kernel device drivers. In the systems I worked the
> accelerators via a crypto device interface gave a 50x to 100x boost in
> crypto operations and relieved the CPU from doing them.
An interface to external crypto co-process _can_ be useful. It
certainly isn't for the tiny requests where mr crackhead complains about
the overhead. So if we do want to design an interface for addons cards
we need to expose a threshold from which it makes sense to use it, and
not even bother using for the simply software in-kernel algorithms.
Which is something that could be done easily using a variant of
Herbert's interface.
On Tue, Sep 07, 2010 at 04:42:13PM +0800, Herbert Xu wrote:
>
> 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.
OK I've gone ahead and implemented the user-space API for hashes
and ciphers.
To recap this interface is designed to allow user-space programs
to access hardware cryptographic accelerators that we have added
to the kernel.
The intended usage scenario is where a large amount of data needs
to be processed where the benefits offered by hardware acceleration
that is normally unavailable in user-space (as opposed to ones
such as the Intel AES instruction which may be used directly from
user-space) outweigh the overhead of going through the kernel.
In order to further minimise the overhead in these cases, this
interface offers the option of avoiding copying data between
user-space and the kernel where possible and appropriate. For
ciphers this means the use of the splice(2) interface instead of
sendmsg(2)
Here is a sample hash program (note that these only illustrate
what the interface looks like and are not meant to be good examples
of coding :)
int main(void)
{
int opfd;
int tfmfd;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "hash",
.salg_name = "sha1"
};
char buf[20];
int i;
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa));
opfd = accept(tfmfd, NULL, 0);
write(opfd, "abc", 3);
read(opfd, buf, 20);
for (i = 0; i < 20; i++) {
printf("%02x", (unsigned char)buf[i]);
}
printf("\n");
close(opfd);
close(tfmfd);
return 0;
}
And here is one for ciphers:
int main(void)
{
int opfd;
int tfmfd;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "skcipher",
.salg_name = "cbc(aes)"
};
struct msghdr msg = {};
struct cmsghdr *cmsg;
char cbuf[CMSG_SPACE(4) + CMSG_SPACE(20)];
char buf[16];
struct af_alg_iv *iv;
struct iovec iov;
int i;
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa));
setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY,
"\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
"\x51\x2e\x03\xd5\x34\x12\x00\x06", 16);
opfd = accept(tfmfd, NULL, 0);
msg.msg_control = cbuf;
msg.msg_controllen = sizeof(cbuf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_ALG;
cmsg->cmsg_type = ALG_SET_OP;
cmsg->cmsg_len = CMSG_LEN(4);
*(__u32 *)CMSG_DATA(cmsg) = ALG_OP_ENCRYPT;
cmsg = CMSG_NXTHDR(&msg, cmsg);
cmsg->cmsg_level = SOL_ALG;
cmsg->cmsg_type = ALG_SET_IV;
cmsg->cmsg_len = CMSG_LEN(20);
iv = (void *)CMSG_DATA(cmsg);
iv->ivlen = 16;
memcpy(iv->iv, "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
"\xb4\x22\xda\x80\x2c\x9f\xac\x41", 16);
iov.iov_base = "Single block msg";
iov.iov_len = 16;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
sendmsg(opfd, &msg, 0);
read(opfd, buf, 16);
for (i = 0; i < 16; i++) {
printf("%02x", (unsigned char)buf[i]);
}
printf("\n");
close(opfd);
close(tfmfd);
return 0;
}
Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Tue, Oct 19, 2010 at 3:44 PM, Herbert Xu
<[email protected]> wrote:
> OK I've gone ahead and implemented the user-space API for hashes
> and ciphers.
> To recap this interface is designed to allow user-space programs
> to access hardware cryptographic accelerators that we have added
> to the kernel.
> The intended usage scenario is where a large amount of data needs
> to be processed where the benefits offered by hardware acceleration
> that is normally unavailable in user-space (as opposed to ones
> such as the Intel AES instruction which may be used directly from
> user-space) outweigh the overhead of going through the kernel.
What is the overall advantage of this API comparing to other existing
ones that achieve similar goals[0][1]?
Some observations:
1. To perform an encryption of data 6 system calls are made (I don't
count the 2 used for socket initialization since I suppose can be global
for all operations) and a file descriptor is assigned. The number of
system calls
made has great impact to the actual speed seen by userspace (as you said this
API is for user-space to access the high-speed peripherals that do encryption).
2. Due to the usage of read() and write() no zero-copy can happen for
user-space buffers[3].
regards,
Nikos
[0]. http://home.gna.org/cryptodev-linux/
[1]. http://home.gna.org/cryptodev-linux/ncr.html
[2]. The openbsd[0] api can do it with 3 system calls and NCR[1] with one,
and both require no file descriptor for each operation.
[3]. The openbsd[0] api and NCR[1] do zero-copy for user-space buffers.
On Tue, Oct 19, 2010 at 09:44:18PM +0800, Herbert Xu wrote:
>
> OK I've gone ahead and implemented the user-space API for hashes
> and ciphers.
Here is a revised series with bug fixes and improvements. The
main change is that hashes can now be finalised by recvmsg instead
of requiring a preceding sendmsg with no MSG_MORE.
Thakns to Miloslav Trmac for reviewing this and contributing
fixes and improvements.
Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
On Thu, Nov 04, 2010 at 01:43:16PM -0400, Miloslav Trmac wrote:
>
> shash_async_import() - it assumes that the struct shash_desc placed in ahash_request_ctx() of the struct ahash_request was initialized to point to the tfm, which is only done in shash_async_init().
Thanks for catching this. This patch should fix the problem.
commit 8850e3641dcc7446628681bd7c5f771005e0b208
Author: Herbert Xu <[email protected]>
Date: Thu Nov 4 13:00:22 2010 -0500
crypto: hash - Fix async import on shash algorithm
The function shash_async_import did not initialise the descriptor
correctly prior to calling the underlying shash import function.
This patch adds the required initialisation.
Reported-by: Miloslav Trmac <[email protected]>
Signed-off-by: Herbert Xu <[email protected]>
diff --git a/crypto/shash.c b/crypto/shash.c
index 22fd943..76f74b9 100644
--- a/crypto/shash.c
+++ b/crypto/shash.c
@@ -310,7 +310,13 @@ static int shash_async_export(struct ahash_request *req, void *out)
static int shash_async_import(struct ahash_request *req, const void *in)
{
- return crypto_shash_import(ahash_request_ctx(req), in);
+ struct crypto_shash **ctx = crypto_ahash_ctx(crypto_ahash_reqtfm(req));
+ struct shash_desc *desc = ahash_request_ctx(req);
+
+ desc->tfm = *ctx;
+ desc->flags = req->base.flags;
+
+ return crypto_shash_import(desc, in);
}
static void crypto_exit_shash_ops_async(struct crypto_tfm *tfm)
Cheers,
--
Email: Herbert Xu <[email protected]>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Hi,
This is regarding the hash computation over a file with AF_ALG from
user space. [without OpenSSL]
The following link has the mail from Herbert with subject : "RFC:
Crypto API User-interface"
http://lwn.net/Articles/410848/
I was trying to take help from the code snippet he has put in his mail
and I was doing the following to compute
hash over a file of 16 bytes. The file contents are "123456789012345\n".
I read the first 10 bytes first and computed hash over it. Then I read
the next 6 bytes from
the file and computed the hash and I had taken care of using the flags
MSG_MORE and MSG_OOB.
Following is what I am doing:
1. send(opfd, sbuf, len, MSG_MORE);
2. read(opfd, state, 20);
3. send(opfd, state, 20, MSG_OOB);
4. send(opfd, sbuf, len, MSG_MORE);
5. read(opfd, state, 20);
6. /*restore from a partial hash state */
7. send(opfd, state, 20, MSG_OOB);
8. /* finalize */
9. send(opfd, sbuf, 0, 0);
10. read(opfd, buf, 20);
sbuf
in line 1 contains: "1234567890" (the " is not part of the data, the
data is plain 10 ascii bytes for 1 through 9), len is 10.
the state after line 2 contains correct hash of the above data.
sbuf in line 4 contains: "12345\n". Len is 6.
The hash I am seeing in buf after line 10 is not correct one.
Is there anything obviously wrong with the above code? I am using
2.6.39.4 kernel on rhel 6.4 (santiago)
Thanks for the help!
~Jitendra
Hi,
http://lwn.net/Articles/410848/
The following code is taken from the above page:
int main(void)
{
int opfd;
int tfmfd;
struct sockaddr_alg sa = {
.salg_family = AF_ALG,
.salg_type = "skcipher",
.salg_name = "cbc(aes)"
};
struct msghdr msg = {};
struct cmsghdr *cmsg;
char cbuf[CMSG_SPACE(4) + CMSG_SPACE(20)];
char buf[16];
struct af_alg_iv *iv;
struct iovec iov;
int i;
tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(tfmfd, (struct sockaddr *)&sa, sizeof(sa));
setsockopt(tfmfd, SOL_ALG, ALG_SET_KEY,
"\x06\xa9\x21\x40\x36\xb8\xa1\x5b"
"\x51\x2e\x03\xd5\x34\x12\x00\x06", 16);
opfd = accept(tfmfd, NULL, 0);
msg.msg_control = cbuf;
msg.msg_controllen = sizeof(cbuf);
cmsg = CMSG_FIRSTHDR(&msg);
cmsg->cmsg_level = SOL_ALG;
cmsg->cmsg_type = ALG_SET_OP;
cmsg->cmsg_len = CMSG_LEN(4);
*(__u32 *)CMSG_DATA(cmsg) = ALG_OP_ENCRYPT;
cmsg = CMSG_NXTHDR(&msg, cmsg);
cmsg->cmsg_level = SOL_ALG;
cmsg->cmsg_type = ALG_SET_IV;
cmsg->cmsg_len = CMSG_LEN(20);
iv = (void *)CMSG_DATA(cmsg);
iv->ivlen = 16;
memcpy(iv->iv, "\x3d\xaf\xba\x42\x9d\x9e\xb4\x30"
"\xb4\x22\xda\x80\x2c\x9f\xac\x41", 16);
iov.iov_base = "Single block msg";
iov.iov_len = 16;
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
sendmsg(opfd, &msg, 0);
read(opfd, buf, 16);
for (i = 0; i < 16; i++) {
printf("%02x", (unsigned char)buf[i]);
}
printf("\n");
close(opfd);
close(tfmfd);
return 0;
}
Here the following small change is needed for this program to work:
memset(cbuf, 0, CMSG_SPACE(4) + CMSG_SPACE(20));
This memset is required otherwise the CMSG_NXTHDR may return a NULL
causing a seg fault in the following line:
cmsg->cmsg_level = SOL_ALG;
I have tried this on 3.3.4-5.fc17.x86_64.
Posting this as it may help people who want to use/refer this example code.
However, can somebody please point me to some more examples which use
af_alg socket (without Openssl! as the af_alg engine for openssl
(http://src.carnivore.it/users/common/af_alg/) is incomplete
supporting only aes-cbc,sha1,sha2 only as of today. No other aes
variants supported in af_alg engine.)
I am particulart wanting to know how I can compute hmac and aes-xts or
ctr modes with af_alg without having to go via openssl.
~Jitendra