--- //depot/vendor/freebsd/src/share/man/man4/crypto.4.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/share/man/man4/crypto.4 2014-09-02 16:11:00.000000000 -0700 @@ -1,8 +1,16 @@ -.\" $OpenBSD: crypto.4,v 1.4 2002/09/12 07:15:03 deraadt Exp $ +.\" $NetBSD: crypto.4,v 1.24 2014/01/27 21:23:59 pgoyette Exp $ .\" -.\" Copyright (c) 2001 Theo de Raadt +.\" Copyright (c) 2008 The NetBSD Foundation, Inc. +.\" Copyright (c) 2014 The FreeBSD Foundation .\" All rights reserved. .\" +.\" Portions of this documentation were written by John-Mark Gurney +.\" under sponsorship of the FreeBSD Foundation and +.\" Rubicon Communications, LLC (Netgate). +.\" +.\" This code is derived from software contributed to The NetBSD Foundation +.\" by Coyote Point Systems, Inc. +.\" .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: @@ -11,99 +19,376 @@ .\" 2. Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in the .\" documentation and/or other materials provided with the distribution. -.\" 3. The name of the author may not be used to endorse or promote products -.\" derived from this software without specific prior written permission. .\" -.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -.\" IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -.\" WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -.\" DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -.\" INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -.\" (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -.\" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -.\" STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN -.\" ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS +.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +.\" PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE .\" POSSIBILITY OF SUCH DAMAGE. .\" -.\" $FreeBSD: head/share/man/man4/crypto.4 263110 2014-03-13 16:19:36Z jmg $ +.\" +.\" +.\" Copyright (c) 2004 +.\" Jonathan Stone . All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY Jonathan Stone AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL Jonathan Stone OR THE VOICES IN HIS HEAD +.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +.\" THE POSSIBILITY OF SUCH DAMAGE. .\" -.Dd September 7, 2010 +.Dd November 6, 2014 .Dt CRYPTO 4 .Os .Sh NAME .Nm crypto , .Nm cryptodev -.Nd hardware crypto access driver +.Nd user-mode access to hardware-accelerated cryptography .Sh SYNOPSIS .Cd device crypto .Cd device cryptodev +.Pp +.In sys/ioctl.h +.In sys/time.h +.In crypto/cryptodev.h .Sh DESCRIPTION The .Nm -driver provides a device-independent framework to support -cryptographic operations in the kernel. +driver gives user-mode applications access to hardware-accelerated +cryptographic transforms, as implemented by the +.Xr opencrypto 9 +in-kernel interface. +.Pp The -.Nm cryptodev -driver provides userland applications access to this support -through the .Pa /dev/crypto -device. -This node primarily operates in an +special device provides an +.Xr ioctl 2 +based interface. +User-mode applications should open the special device, +then issue .Xr ioctl 2 -based model, permitting a variety of applications to query device capabilities, -submit transactions, and get results. +calls on the descriptor. +User-mode access to +.Pa /dev/crypto +is controlled by three +.Xr sysctl 8 +variables, +.Ic kern.userasymcrypto +and +.Ic kern.cryptodevallowsoft . +See +.Xr sysctl 7 +for additional details. +.Pp +The +.Nm +device provides two distinct modes of operation: one mode for +symmetric-keyed cryptographic requests, and a second mode for +both asymmetric-key (public-key/private-key) requests, and for +modular arithmetic (for Diffie-Hellman key exchange and other +cryptographic protocols). +The two modes are described separately below. +.Sh THEORY OF OPERATION +Regardless of whether symmetric-key or asymmetric-key operations are +to be performed, use of the device requires a basic series of steps: +.Pp +.Bl -enum +.It +Open a file descriptor for the device. +See +.Xr open 2 . +.It +If any symmetric operation will be performed, +create one session, with +.Dv CIOCGSESSION . +Most applications will require at least one symmetric session. +Since cipher and MAC keys are tied to sessions, many +applications will require more. +Asymmetric operations do not use sessions. +.It +Submit requests, synchronously with +.Dv CIOCCRYPT +(symmetric) +or +.Dv CIOCKEY +(asymmetric). +.It +Destroy one session with +.Dv CIOCFSESSION . +.It +Close the device with +.Xr close 2 . +.El +.Sh SYMMETRIC-KEY OPERATION +The symmetric-key operation mode provides a context-based API +to traditional symmetric-key encryption (or privacy) algorithms, +or to keyed and unkeyed one-way hash (HMAC and MAC) algorithms. +The symmetric-key mode also permits fused operation, +where the hardware performs both a privacy algorithm and an integrity-check +algorithm in a single pass over the data: either a fused +encrypt/HMAC-generate operation, or a fused HMAC-verify/decrypt operation. .Pp +To use symmetric mode, you must first create a session specifying +the algorithm(s) and key(s) to use; then issue encrypt or decrypt +requests against the session. +.Ss Algorithms +For a list of supported algorithms, see +.Xr crypto 7 +and +.Xr crypto 9 . +.Ss IOCTL Request Descriptions +.\" +.Bl -tag -width CIOCGSESSION +.\" +.It Dv CRIOGET Fa int *fd +Clone the fd argument to +.Xr ioctl 2 , +yielding a new file descriptor for the creation of sessions. +.\" +.It Dv CIOCFINDDEV Fa struct crypt_find_op *fop +.Bd -literal +struct crypt_find_op { + int crid; /* driver id + flags */ + char name[32]; /* device/driver name */ +}; + +.Ed +If +.Fa crid +is -1, then find the driver named +.Fa name +and return the id in +.Fa crid . If -.Ar count -given in the specification, and is greater than 0, a maximum of one -.Nm -device is created. +.Fa crid +is not -1, return the name of the driver with +.Fa crid +in +.Fa name . +In either case, if the driver is not found, +.Dv ENOENT +is returned. +.It Dv CIOCGSESSION Fa struct session_op *sessp +.Bd -literal +struct session_op { + u_int32_t cipher; /* e.g. CRYPTO_DES_CBC */ + u_int32_t mac; /* e.g. CRYPTO_MD5_HMAC */ + + u_int32_t keylen; /* cipher key */ + void * key; + int mackeylen; /* mac key */ + void * mackey; + + u_int32_t ses; /* returns: ses # */ +}; + +.Ed +Create a new cryptographic session on a file descriptor for the device; +that is, a persistent object specific to the chosen +privacy algorithm, integrity algorithm, and keys specified in +.Fa sessp . +The special value 0 for either privacy or integrity +is reserved to indicate that the indicated operation (privacy or integrity) +is not desired for this session. +.Pp +Multiple sessions may be bound to a single file descriptor. +The session ID returned in +.Fa sessp-\*[Gt]ses +is supplied as a required field in the symmetric-operation structure +.Fa crypt_op +for future encryption or hashing requests. +.\" .Pp +.\" This implementation will never return a session ID of 0 for a successful +.\" creation of a session, which is a +.\" .Nx +.\" extension. +.Pp +For non-zero symmetric-key privacy algorithms, the privacy algorithm +must be specified in +.Fa sessp-\*[Gt]cipher , +the key length in +.Fa sessp-\*[Gt]keylen , +and the key value in the octets addressed by +.Fa sessp-\*[Gt]key . +.Pp +For keyed one-way hash algorithms, the one-way hash must be specified +in +.Fa sessp-\*[Gt]mac , +the key length in +.Fa sessp-\*[Gt]mackey , +and the key value in the octets addressed by +.Fa sessp-\*[Gt]mackeylen . +.\" .Pp -The following +Support for a specific combination of fused privacy and +integrity-check algorithms depends on whether the underlying +hardware supports that combination. +Not all combinations are supported +by all hardware, even if the hardware supports each operation as a +stand-alone non-fused operation. +.It Dv CIOCCRYPT Fa struct crypt_op *cr_op +.Bd -literal +struct crypt_op { + u_int32_t ses; + u_int16_t op; /* e.g. COP_ENCRYPT */ + u_int16_t flags; + u_int len; + caddr_t src, dst; + caddr_t mac; /* must be large enough for result */ + caddr_t iv; +}; + +.Ed +Request a symmetric-key (or hash) operation. +The file descriptor argument to .Xr ioctl 2 -calls apply only to the -.Nm -devices: -.Bl -tag -width ".Dv CIOCGSESSION" -.It Dv CIOCGSESSION -Setup a new crypto session for a new type of operation. -.It Dv CIOCFSESSION -Free a previously established session. -.It Dv CIOCCRYPT -Perform a crypto operation against a previously setup session. +must have been bound to a valid session. +To encrypt, set +.Fa cr_op-\*[Gt]op +to +.Dv COP_ENCRYPT . +To decrypt, set +.Fa cr_op-\*[Gt]op +to +.Dv COP_DECRYPT . +The field +.Fa cr_op-\*[Gt]len +supplies the length of the input buffer; the fields +.Fa cr_op-\*[Gt]src , +.Fa cr_op-\*[Gt]dst , +.Fa cr_op-\*[Gt]mac , +.Fa cr_op-\*[Gt]iv +supply the addresses of the input buffer, output buffer, +one-way hash, and initialization vector, respectively. +.It Dv CIOCCRYPTAEAD Fa struct crypt_aead *cr_aead +.Bd -literal +struct crypt_aead { + u_int32_t ses; + u_int16_t op; /* e.g. COP_ENCRYPT */ + u_int16_t flags; + u_int len; + u_int aadlen; + u_int ivlen; + caddr_t src, dst; + caddr_t aad; + caddr_t tag; /* must be large enough for result */ + caddr_t iv; +}; + +.Ed +The +.Dv CIOCCRYPTAEAD +is similar to the +.Dv CIOCCRYPT +but provides additional data in +.Fa cr_aead-\*[Gt]aad +to include in the authentication mode. +.It Dv CIOCFSESSION Fa u_int32_t ses_id +Destroys the /dev/crypto session associated with the file-descriptor +argument. +.It Dv CIOCNFSESSION Fa struct crypt_sfop *sfop ; +.Bd -literal +struct crypt_sfop { + size_t count; + u_int32_t *sesid; +}; + +.Ed +Destroys the +.Fa sfop-\*[Gt]count +sessions specified by the +.Fa sfop +array of session identifiers. .El -.Sh FEATURES -Depending on hardware being present, the following symmetric and -asymmetric cryptographic features are potentially available from -.Pa /dev/crypto : +.\" +.Sh ASYMMETRIC-KEY OPERATION +.Ss Asymmetric-key algorithms +Contingent upon hardware support, the following asymmetric +(public-key/private-key; or key-exchange subroutine) operations may +also be available: .Pp -.Bl -tag -width ".Dv CRYPTO_RIPEMD160_HMAC" -offset indent -compact -.It Dv CRYPTO_DES_CBC -.It Dv CRYPTO_3DES_CBC -.It Dv CRYPTO_BLF_CBC -.It Dv CRYPTO_CAMELLIA_CBC -.It Dv CRYPTO_CAST_CBC -.It Dv CRYPTO_SKIPJACK_CBC -.It Dv CRYPTO_MD5_HMAC -.It Dv CRYPTO_SHA1_HMAC -.It Dv CRYPTO_RIPEMD160_HMAC -.It Dv CRYPTO_MD5_KPDK -.It Dv CRYPTO_SHA1_KPDK -.It Dv CRYPTO_AES_CBC -.It Dv CRYPTO_ARC4 -.It Dv CRYPTO_MD5 -.It Dv CRYPTO_SHA1 -.It Dv CRK_MOD_EXP -.It Dv CRK_MOD_EXP_CRT -.It Dv CRK_DSA_SIGN -.It Dv CRK_DSA_VERIFY -.It Dv CRK_DH_COMPUTE_KEY +.Bl -column "CRK_DH_COMPUTE_KEY" "Input parameter" "Output parameter" -offset indent -compact +.It Em "Algorithm" Ta "Input parameter" Ta "Output parameter" +.It Em " " Ta "Count" Ta "Count" +.It Dv CRK_MOD_EXP Ta 3 Ta 1 +.It Dv CRK_MOD_EXP_CRT Ta 6 Ta 1 +.It Dv CRK_DSA_SIGN Ta 5 Ta 2 +.It Dv CRK_DSA_VERIFY Ta 7 Ta 0 +.It Dv CRK_DH_COMPUTE_KEY Ta 3 Ta 1 .El -.Sh FILES -.Bl -tag -width ".Pa /dev/crypto" -compact -.It Pa /dev/crypto -crypto access device +.Pp +See below for discussion of the input and output parameter counts. +.Ss Asymmetric-key commands +.Bl -tag -width CIOCKEY +.It Dv CIOCASYMFEAT Fa int *feature_mask +Returns a bitmask of supported asymmetric-key operations. +Each of the above-listed asymmetric operations is present +if and only if the bit position numbered by the code for that operation +is set. +For example, +.Dv CRK_MOD_EXP +is available if and only if the bit +.Pq 1 \*[Lt]\*[Lt] Dv CRK_MOD_EXP +is set. +.It Dv CIOCKEY Fa struct crypt_kop *kop +.Bd -literal +struct crypt_kop { + u_int crk_op; /* e.g. CRK_MOD_EXP */ + u_int crk_status; /* return status */ + u_short crk_iparams; /* # of input params */ + u_short crk_oparams; /* # of output params */ + u_int crk_pad1; + struct crparam crk_param[CRK_MAXPARAM]; +}; + +/* Bignum parameter, in packed bytes. */ +struct crparam { + void * crp_p; + u_int crp_nbits; +}; + +.Ed +Performs an asymmetric-key operation from the list above. +The specific operation is supplied in +.Fa kop-\*[Gt]crk_op ; +final status for the operation is returned in +.Fa kop-\*[Gt]crk_status . +The number of input arguments and the number of output arguments +is specified in +.Fa kop-\*[Gt]crk_iparams +and +.Fa kop-\*[Gt]crk_iparams , +respectively. +The field +.Fa crk_param[] +must be filled in with exactly +.Fa kop-\*[Gt]crk_iparams + kop-\*[Gt]crk_oparams +arguments, each encoded as a +.Fa struct crparam +(address, bitlength) pair. +.Pp +The semantics of these arguments are currently undocumented. .El .Sh SEE ALSO .Xr aesni 4 , @@ -112,6 +397,7 @@ .Xr padlock 4 , .Xr safe 4 , .Xr ubsec 4 , +.Xr crypto 7 , .Xr geli 8 , .Xr crypto 9 .Sh HISTORY @@ -123,3 +409,24 @@ .Nm driver was imported to .Fx 5.0 . +.Sh BUGS +Error checking and reporting is weak. +.Pp +The values specified for symmetric-key key sizes to +.Dv CIOCGSESSION +must exactly match the values expected by +.Xr opencrypto 9 . +The output buffer and MAC buffers supplied to +.Dv CIOCCRYPT +must follow whether privacy or integrity algorithms were specified for +session: if you request a +.No non- Ns Dv NULL +algorithm, you must supply a suitably-sized buffer. +.Pp +The scheme for passing arguments for asymmetric requests is baroque. +.Pp +The naming inconsistency between +.Dv CRIOGET +and the various +.Dv CIOC Ns \&* +names is an unfortunate historical artifact. --- //depot/vendor/freebsd/src/share/man/man7/Makefile.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/share/man/man7/Makefile 2014-09-02 16:11:00.000000000 -0700 @@ -9,6 +9,7 @@ bsd.snmpmod.mk.7 \ build.7 \ clocks.7 \ + crypto.7 \ c99.7 \ development.7 \ environ.7 \ --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/share/man/man7/crypto.7 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,141 @@ +.\" Copyright (c) 2014 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by John-Mark Gurney under +.\" the sponsorship of the FreeBSD Foundation and +.\" Rubicon Communications, LLC (Netgate). +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 18, 2014 +.Dt CRYPTO 7 +.Os +.Sh NAME +.Nm crypto +.Nd OpenCrypto algorithms +.Sh SYNOPSIS +In the kernel configuration file: +.Cd "device crypto" +.Pp +Or load the crypto.ko module. +.Sh DESCRIPTION +The following cryptographic algorithms that are part of the OpenCrypto +framework have the following requirements. +.Pp +Cipher algorithms: +.Bl -tag -width ".Dv CRYPTO_AES_CBC" +.It Dv CRYPTO_AES_CBC +.Bl -tag -width "Block size :" -compact -offset indent +.It IV size : +16 +.It Block size : +16 +.It Key size : +16, 24 or 32 +.El +.Pp +This algorithm implements Cipher-block chaining. +.It Dv CRYPTO_AES_NIST_GCM_16 +.Bl -tag -width "Block size :" -compact -offset indent +.It IV size : +12 +.It Block size : +1 +.It Key size : +16, 24 or 32 +.It Digest size : +16 +.El +.Pp +This algorithm implements Galois/Counter Mode. +This is the cipher part of an AEAD +.Pq Authenticated Encryption with Associated Data +mode. +This requires use of the use of a proper authentication mode, one of +.Dv CRYPTO_AES_128_NIST_GMAC , +.Dv CRYPTO_AES_192_NIST_GMAC +or +.Dv CRYPTO_AES_256_NIST_GMAC , +that corresponds with the number of bits in the key that you are using. +.Pp +The associated data (if any) must be provided by the authentication mode op. +The authentication tag will be read/written from/to the offset crd_inject +specified in the descriptor for the authentication mode. +.Pp +Note: You must provide an IV on every call. +.It Dv CRYPTO_AES_ICM +.Bl -tag -width "Block size :" -compact -offset indent +.It IV size : +16 +.It Block size : +1 (aesni), 16 (software) +.It Key size : +16, 24 or 32 +.El +.Pp +This algorithm implements Integer Counter Mode. +This is similar to what most people call counter mode, but instead of the +counter being split into a nonce and a counter part, then entire nonce is +used as the initial counter. +This does mean that if a counter is required that rolls over at 32 bits, +the transaction need to be split into two parts where the counter rolls over. +The counter incremented as a 128-bit big endian number. +.Pp +Note: You must provide an IV on every call. +.It Dv CRYPTO_AES_XTS +.Bl -tag -width "Block size :" -compact -offset indent +.It IV size : +16 +.It Block size : +16 +.It Key size : +32 or 64 +.El +.Pp +This algorithm implements XEX Tweakable Block Cipher with Ciphertext Stealing +as defined in NIST SP 800-38E. +.Pp +NOTE: The ciphertext stealing part is not implemented which is why this cipher +is listed as having a block size of 16 instead of 1. +.El +.Pp +Authentication algorithms: +.Bl -tag -width ".Dv CRYPTO_AES_256_NIST_GMAC" +.It CRYPTO_AES_128_NIST_GMAC +See +.Dv CRYPTO_AES_NIST_GCM_16 +in the cipher mode section. +.It CRYPTO_AES_192_NIST_GMAC +See +.Dv CRYPTO_AES_NIST_GCM_16 +in the cipher mode section. +.It CRYPTO_AES_256_NIST_GMAC +See +.Dv CRYPTO_AES_NIST_GCM_16 +in the cipher mode section. +.El +.Sh SEE ALSO +.Xr crypto 4 , +.Xr crypto 9 +.Sh BUGS +Not all the implemented algorithms are listed. --- //depot/vendor/freebsd/src/share/man/man9/crypto.9.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/share/man/man9/crypto.9 2014-09-02 16:11:00.000000000 -0700 @@ -17,7 +17,7 @@ .\" .\" $FreeBSD: head/share/man/man9/crypto.9 267936 2014-06-26 21:44:30Z bapt $ .\" -.Dd April 18, 2014 +.Dd September 8, 2014 .Dt CRYPTO 9 .Os .Sh NAME @@ -175,17 +175,26 @@ Currently supported algorithms are: .Pp .Bl -tag -width ".Dv CRYPTO_RIPEMD160_HMAC" -compact +.It Dv CRYPTO_AES_128_NIST_GMAC +.It Dv CRYPTO_AES_192_NIST_GMAC +.It Dv CRYPTO_AES_256_NIST_GMAC .It Dv CRYPTO_AES_CBC +.It Dv CRYPTO_AES_ICM +.It Dv CRYPTO_AES_NIST_GCM_16 +.It Dv CRYPTO_AES_NIST_GMAC +.It Dv CRYPTO_AES_XTS .It Dv CRYPTO_ARC4 .It Dv CRYPTO_BLF_CBC .It Dv CRYPTO_CAMELLIA_CBC .It Dv CRYPTO_CAST_CBC +.It Dv CRYPTO_DEFLATE_COMP .It Dv CRYPTO_DES_CBC .It Dv CRYPTO_3DES_CBC -.It Dv CRYPTO_SKIPJACK_CBC .It Dv CRYPTO_MD5 .It Dv CRYPTO_MD5_HMAC .It Dv CRYPTO_MD5_KPDK +.It Dv CRYPTO_NULL_HMAC +.It Dv CRYPTO_NULL_CBC .It Dv CRYPTO_RIPEMD160_HMAC .It Dv CRYPTO_SHA1 .It Dv CRYPTO_SHA1_HMAC @@ -193,8 +202,7 @@ .It Dv CRYPTO_SHA2_256_HMAC .It Dv CRYPTO_SHA2_384_HMAC .It Dv CRYPTO_SHA2_512_HMAC -.It Dv CRYPTO_NULL_HMAC -.It Dv CRYPTO_NULL_CBC +.It Dv CRYPTO_SKIPJACK_CBC .El .It Va cri_klen Specifies the length of the key in bits, for variable-size key @@ -207,7 +215,8 @@ .It Va cri_iv Contains an explicit initialization vector (IV), if it does not prefix the data. -This field is ignored during initialization. +This field is ignored during initialization +.Pq Nm crypto_newsession . If no IV is explicitly passed (see below on details), a random IV is used by the device driver processing the request. .It Va cri_next @@ -296,8 +305,6 @@ is an .Vt uio structure. -.It Dv CRYPTO_F_REL -Must return data in the same place. .It Dv CRYPTO_F_BATCH Batch operation if possible. .It Dv CRYPTO_F_CBIMM @@ -363,7 +370,7 @@ For encryption algorithms, this bit is set when encryption is required (when not set, decryption is performed). .It Dv CRD_F_IV_PRESENT -For encryption algorithms, this bit is set when the IV already +For encryption, this bit is set when the IV already precedes the data, so the .Va crd_inject value will be ignored and no IV will be written in the buffer. @@ -372,7 +379,7 @@ .Va crd_inject . The IV length is assumed to be equal to the blocksize of the encryption algorithm. -Some applications that do special +Applications that do special .Dq "IV cooking" , such as the half-IV mode in .Xr ipsec 4 , @@ -403,6 +410,8 @@ Otherwise, the key is taken at newsession time from the .Va cri_key field. +As calculating the key schedule may take a while, it is recommended that often +used keys are given their own session. .It Dv CRD_F_COMP For compression algorithms, this bit is set when compression is required (when not set, decompression is performed). @@ -642,6 +651,7 @@ .Sh SEE ALSO .Xr crypto 4 , .Xr ipsec 4 , +.Xr crypto 7 , .Xr malloc 9 , .Xr sleep 9 .Sh HISTORY --- //depot/vendor/freebsd/src/sys/conf/files.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/conf/files 2014-09-02 16:11:00.000000000 -0700 @@ -3208,6 +3208,7 @@ libkern/strtoul.c standard libkern/strtouq.c standard libkern/strvalid.c standard +libkern/timingsafe_bcmp.c standard net/bpf.c standard net/bpf_buffer.c optional bpf net/bpf_jitter.c optional bpf_jitter @@ -3865,6 +3866,8 @@ opencrypto/cryptodev_if.m optional crypto opencrypto/cryptosoft.c optional crypto opencrypto/cryptodeflate.c optional crypto +opencrypto/gmac.c optional crypto +opencrypto/gfmult.c optional crypto opencrypto/rmd160.c optional crypto | ipsec opencrypto/skipjack.c optional crypto opencrypto/xform.c optional crypto --- //depot/vendor/freebsd/src/sys/conf/files.amd64.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/conf/files.amd64 2014-09-02 16:11:00.000000000 -0700 @@ -129,6 +129,11 @@ cddl/contrib/opensolaris/common/atomic/amd64/opensolaris_atomic.S optional zfs compile-with "${ZFS_S}" crypto/aesni/aeskeys_amd64.S optional aesni crypto/aesni/aesni.c optional aesni +aesni_ghash.o optional aesni \ + dependency "$S/crypto/aesni/aesni_ghash.c" \ + compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \ + no-implicit-rule \ + clean "aesni_ghash.o" aesni_wrap.o optional aesni \ dependency "$S/crypto/aesni/aesni_wrap.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} -mmmx -msse -maes ${.IMPSRC}" \ --- //depot/vendor/freebsd/src/sys/conf/files.i386.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/conf/files.i386 2014-09-02 16:11:00.000000000 -0700 @@ -116,6 +116,11 @@ no-implicit-rule crypto/aesni/aeskeys_i386.S optional aesni crypto/aesni/aesni.c optional aesni +aesni_ghash.o optional aesni \ + dependency "$S/crypto/aesni/aesni_ghash.c" \ + compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC}" \ + no-implicit-rule \ + clean "aesni_ghash.o" aesni_wrap.o optional aesni \ dependency "$S/crypto/aesni/aesni_wrap.c" \ compile-with "${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} -mmmx -msse -maes ${.IMPSRC}" \ --- //depot/vendor/freebsd/src/sys/crypto/aesni/aesni.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/crypto/aesni/aesni.c 2014-09-02 16:11:00.000000000 -0700 @@ -1,8 +1,13 @@ /*- * Copyright (c) 2005-2008 Pawel Jakub Dawidek * Copyright (c) 2010 Konstantin Belousov + * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,13 +39,16 @@ #include #include #include +#include #include #include #include #include #include +#include #include #include +#include struct aesni_softc { int32_t cid; @@ -56,7 +64,7 @@ static int aesni_cipher_setup(struct aesni_session *ses, struct cryptoini *encini); static int aesni_cipher_process(struct aesni_session *ses, - struct cryptodesc *enccrd, struct cryptop *crp); + struct cryptodesc *enccrd, struct cryptodesc *authcrd, struct cryptop *crp); MALLOC_DEFINE(M_AESNI, "aesni_data", "AESNI Data"); @@ -79,12 +87,12 @@ return (EINVAL); } - if ((cpu_feature & CPUID_SSE2) == 0) { - device_printf(dev, "No SSE2 support but AESNI!?!\n"); + if ((cpu_feature2 & CPUID2_SSE41) == 0) { + device_printf(dev, "No SSE4.1 support.\n"); return (EINVAL); } - device_set_desc_copy(dev, "AES-CBC,AES-XTS"); + device_set_desc_copy(dev, "AES-CBC,AES-XTS,AES-GCM,AES-ICM"); return (0); } @@ -105,6 +113,11 @@ rw_init(&sc->lock, "aesni_lock"); crypto_register(sc->cid, CRYPTO_AES_CBC, 0, 0); + crypto_register(sc->cid, CRYPTO_AES_ICM, 0, 0); + crypto_register(sc->cid, CRYPTO_AES_NIST_GCM_16, 0, 0); + crypto_register(sc->cid, CRYPTO_AES_128_NIST_GMAC, 0, 0); + crypto_register(sc->cid, CRYPTO_AES_192_NIST_GMAC, 0, 0); + crypto_register(sc->cid, CRYPTO_AES_256_NIST_GMAC, 0, 0); crypto_register(sc->cid, CRYPTO_AES_XTS, 0, 0); return (0); } @@ -128,6 +141,7 @@ while ((ses = TAILQ_FIRST(&sc->sessions)) != NULL) { TAILQ_REMOVE(&sc->sessions, ses, next); fpu_kern_free_ctx(ses->fpu_ctx); + mtx_destroy(&ses->lck); free(ses, M_AESNI); } rw_wunlock(&sc->lock); @@ -144,8 +158,10 @@ struct cryptoini *encini; int error; - if (sidp == NULL || cri == NULL) + if (sidp == NULL || cri == NULL) { + CRYPTDEB("no sidp or cri"); return (EINVAL); + } sc = device_get_softc(dev); ses = NULL; @@ -153,17 +169,32 @@ for (; cri != NULL; cri = cri->cri_next) { switch (cri->cri_alg) { case CRYPTO_AES_CBC: + case CRYPTO_AES_ICM: case CRYPTO_AES_XTS: - if (encini != NULL) + case CRYPTO_AES_NIST_GCM_16: + if (encini != NULL) { + CRYPTDEB("encini already set"); return (EINVAL); + } encini = cri; break; + case CRYPTO_AES_128_NIST_GMAC: + case CRYPTO_AES_192_NIST_GMAC: + case CRYPTO_AES_256_NIST_GMAC: + /* + * nothing to do here, maybe in the future cache some + * values for GHASH + */ + break; default: + CRYPTDEB("unhandled algorithm"); return (EINVAL); } } - if (encini == NULL) + if (encini == NULL) { + CRYPTDEB("no cipher"); return (EINVAL); + } rw_wlock(&sc->lock); /* @@ -184,6 +215,7 @@ rw_wunlock(&sc->lock); return (ENOMEM); } + mtx_init(&ses->lck, "aesni session", NULL, MTX_DEF); ses->id = sc->sid++; } else { TAILQ_REMOVE(&sc->sessions, ses, next); @@ -195,6 +227,7 @@ error = aesni_cipher_setup(ses, encini); if (error != 0) { + CRYPTDEB("setup failed"); rw_wlock(&sc->lock); aesni_freesession_locked(sc, ses); rw_wunlock(&sc->lock); @@ -210,13 +243,16 @@ { struct fpu_kern_ctx *ctx; uint32_t sid; + struct mtx lck; sid = ses->id; + lck = ses->lck; TAILQ_REMOVE(&sc->sessions, ses, next); ctx = ses->fpu_ctx; - bzero(ses, sizeof(*ses)); + *ses = (struct aesni_session){}; ses->id = sid; ses->fpu_ctx = ctx; + ses->lck = lck; TAILQ_INSERT_HEAD(&sc->sessions, ses, next); } @@ -248,11 +284,13 @@ { struct aesni_softc *sc = device_get_softc(dev); struct aesni_session *ses = NULL; - struct cryptodesc *crd, *enccrd; - int error; + struct cryptodesc *crd, *enccrd, *authcrd; + int error, needauth; error = 0; enccrd = NULL; + authcrd = NULL; + needauth = 0; /* Sanity check. */ if (crp == NULL) @@ -266,6 +304,7 @@ for (crd = crp->crp_desc; crd != NULL; crd = crd->crd_next) { switch (crd->crd_alg) { case CRYPTO_AES_CBC: + case CRYPTO_AES_ICM: case CRYPTO_AES_XTS: if (enccrd != NULL) { error = EINVAL; @@ -273,11 +312,41 @@ } enccrd = crd; break; + + case CRYPTO_AES_NIST_GCM_16: + if (enccrd != NULL) { + error = EINVAL; + goto out; + } + enccrd = crd; + needauth = 1; + break; + + case CRYPTO_AES_128_NIST_GMAC: + case CRYPTO_AES_192_NIST_GMAC: + case CRYPTO_AES_256_NIST_GMAC: + if (authcrd != NULL) { + error = EINVAL; + goto out; + } + authcrd = crd; + needauth = 1; + break; + default: - return (EINVAL); + error = EINVAL; + goto out; } } - if (enccrd == NULL || (enccrd->crd_len % AES_BLOCK_LEN) != 0) { + + if (enccrd == NULL || (needauth && authcrd == NULL)) { + error = EINVAL; + goto out; + } + + /* CBC & XTS can only handle full blocks for now */ + if ((enccrd->crd_alg == CRYPTO_AES_CBC || enccrd->crd_alg == + CRYPTO_AES_XTS) && (enccrd->crd_len % AES_BLOCK_LEN) != 0) { error = EINVAL; goto out; } @@ -293,7 +362,7 @@ goto out; } - error = aesni_cipher_process(ses, enccrd, crp); + error = aesni_cipher_process(ses, enccrd, authcrd, crp); if (error != 0) goto out; @@ -307,21 +376,26 @@ aesni_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, int *allocated) { + struct mbuf *m; struct uio *uio; struct iovec *iov; uint8_t *addr; - if (crp->crp_flags & CRYPTO_F_IMBUF) - goto alloc; - else if (crp->crp_flags & CRYPTO_F_IOV) { + if (crp->crp_flags & CRYPTO_F_IMBUF) { + m = (struct mbuf *)crp->crp_buf; + if (m->m_next != NULL) + goto alloc; + addr = mtod(m, uint8_t *); + } else if (crp->crp_flags & CRYPTO_F_IOV) { uio = (struct uio *)crp->crp_buf; if (uio->uio_iovcnt != 1) goto alloc; iov = uio->uio_iov; - addr = (u_char *)iov->iov_base + enccrd->crd_skip; + addr = (uint8_t *)iov->iov_base; } else - addr = (u_char *)crp->crp_buf; + addr = (uint8_t *)crp->crp_buf; *allocated = 0; + addr += enccrd->crd_skip; return (addr); alloc: @@ -366,29 +440,56 @@ int error; td = curthread; + mtx_lock(&ses->lck); error = fpu_kern_enter(td, ses->fpu_ctx, FPU_KERN_NORMAL | FPU_KERN_KTHR); - if (error != 0) + if (error != 0) { + mtx_unlock(&ses->lck); return (error); + } error = aesni_cipher_setup_common(ses, encini->cri_key, encini->cri_klen); fpu_kern_leave(td, ses->fpu_ctx); + mtx_unlock(&ses->lck); return (error); } +/* + * authcrd contains the associated date. + */ static int aesni_cipher_process(struct aesni_session *ses, struct cryptodesc *enccrd, - struct cryptop *crp) + struct cryptodesc *authcrd, struct cryptop *crp) { + uint8_t tag[GMAC_DIGEST_LEN]; struct thread *td; - uint8_t *buf; - int error, allocated; + uint8_t *buf, *authbuf; + int error, allocated, authallocated; + int ivlen, encflag; + + encflag = (enccrd->crd_flags & CRD_F_ENCRYPT) == CRD_F_ENCRYPT; + + if ((enccrd->crd_alg == CRYPTO_AES_ICM || + enccrd->crd_alg == CRYPTO_AES_NIST_GCM_16) && + (enccrd->crd_flags & CRD_F_IV_EXPLICIT) == 0) + return (EINVAL); buf = aesni_cipher_alloc(enccrd, crp, &allocated); if (buf == NULL) return (ENOMEM); + authbuf = NULL; + authallocated = 0; + if (authcrd != NULL) { + authbuf = aesni_cipher_alloc(authcrd, crp, &authallocated); + if (authbuf == NULL) { + error = ENOMEM; + goto out1; + } + } + td = curthread; + mtx_lock(&ses->lck); error = fpu_kern_enter(td, ses->fpu_ctx, FPU_KERN_NORMAL | FPU_KERN_KTHR); if (error != 0) @@ -401,48 +502,100 @@ goto out; } - if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) { - if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) - bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN); - if ((enccrd->crd_flags & CRD_F_IV_PRESENT) == 0) - crypto_copyback(crp->crp_flags, crp->crp_buf, - enccrd->crd_inject, AES_BLOCK_LEN, ses->iv); - if (ses->algo == CRYPTO_AES_CBC) { + /* XXX - validate that enccrd and authcrd have/use same key? */ + switch (enccrd->crd_alg) { + case CRYPTO_AES_CBC: + case CRYPTO_AES_ICM: + ivlen = AES_BLOCK_LEN; + break; + case CRYPTO_AES_XTS: + ivlen = 8; + break; + case CRYPTO_AES_NIST_GCM_16: + ivlen = 12; /* should support arbitarily larger */ + break; + } + + /* Setup ses->iv */ + bzero(ses->iv, sizeof ses->iv); + if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) + bcopy(enccrd->crd_iv, ses->iv, ivlen); + else if (encflag && ((enccrd->crd_flags & CRD_F_IV_PRESENT) != 0)) + arc4rand(ses->iv, ivlen, 0); + else + crypto_copydata(crp->crp_flags, crp->crp_buf, + enccrd->crd_inject, ivlen, ses->iv); + + if (authcrd != NULL && !encflag) + crypto_copydata(crp->crp_flags, crp->crp_buf, + authcrd->crd_inject, GMAC_DIGEST_LEN, tag); + else + bzero(tag, sizeof tag); + + /* Do work */ + switch (ses->algo) { + case CRYPTO_AES_CBC: + if (encflag) aesni_encrypt_cbc(ses->rounds, ses->enc_schedule, enccrd->crd_len, buf, buf, ses->iv); - } else /* if (ses->algo == CRYPTO_AES_XTS) */ { + else + aesni_decrypt_cbc(ses->rounds, ses->dec_schedule, + enccrd->crd_len, buf, ses->iv); + break; + case CRYPTO_AES_ICM: + /* encryption & decryption are the same */ + aesni_encrypt_icm(ses->rounds, ses->enc_schedule, + enccrd->crd_len, buf, buf, ses->iv); + break; + case CRYPTO_AES_XTS: + if (encflag) aesni_encrypt_xts(ses->rounds, ses->enc_schedule, ses->xts_schedule, enccrd->crd_len, buf, buf, ses->iv); - } - } else { - if ((enccrd->crd_flags & CRD_F_IV_EXPLICIT) != 0) - bcopy(enccrd->crd_iv, ses->iv, AES_BLOCK_LEN); else - crypto_copydata(crp->crp_flags, crp->crp_buf, - enccrd->crd_inject, AES_BLOCK_LEN, ses->iv); - if (ses->algo == CRYPTO_AES_CBC) { - aesni_decrypt_cbc(ses->rounds, ses->dec_schedule, - enccrd->crd_len, buf, ses->iv); - } else /* if (ses->algo == CRYPTO_AES_XTS) */ { aesni_decrypt_xts(ses->rounds, ses->dec_schedule, ses->xts_schedule, enccrd->crd_len, buf, buf, ses->iv); + break; + case CRYPTO_AES_NIST_GCM_16: + if (encflag) + AES_GCM_encrypt(buf, buf, authbuf, ses->iv, tag, + enccrd->crd_len, authcrd->crd_len, ivlen, + ses->enc_schedule, ses->rounds); + else { + if (!AES_GCM_decrypt(buf, buf, authbuf, ses->iv, tag, + enccrd->crd_len, authcrd->crd_len, ivlen, + ses->enc_schedule, ses->rounds)) + error = EBADMSG; } + break; } + if (allocated) crypto_copyback(crp->crp_flags, crp->crp_buf, enccrd->crd_skip, enccrd->crd_len, buf); - if ((enccrd->crd_flags & CRD_F_ENCRYPT) != 0) - crypto_copydata(crp->crp_flags, crp->crp_buf, - enccrd->crd_skip + enccrd->crd_len - AES_BLOCK_LEN, - AES_BLOCK_LEN, ses->iv); + + /* + * OpenBSD doesn't copy this back. This primes the IV for the next + * chain. Why do we not do it for decrypt? + */ + if (encflag && enccrd->crd_alg == CRYPTO_AES_CBC) + bcopy(buf + enccrd->crd_len - AES_BLOCK_LEN, ses->iv, AES_BLOCK_LEN); + + if (!error && authcrd != NULL) { + crypto_copyback(crp->crp_flags, crp->crp_buf, + authcrd->crd_inject, GMAC_DIGEST_LEN, tag); + } + out: fpu_kern_leave(td, ses->fpu_ctx); + mtx_unlock(&ses->lck); out1: if (allocated) { bzero(buf, enccrd->crd_len); free(buf, M_AESNI); } + if (authallocated) + free(authbuf, M_AESNI); return (error); } --- //depot/vendor/freebsd/src/sys/crypto/aesni/aesni.h.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/crypto/aesni/aesni.h 2014-09-02 16:11:00.000000000 -0700 @@ -66,6 +66,7 @@ uint32_t id; TAILQ_ENTRY(aesni_session) next; struct fpu_kern_ctx *fpu_ctx; + struct mtx lck; }; /* @@ -88,6 +89,9 @@ size_t len, const uint8_t *from, uint8_t *to); void aesni_decrypt_ecb(int rounds, const void *key_schedule /*__aligned(16)*/, size_t len, const uint8_t *from, uint8_t *to); +void aesni_encrypt_icm(int rounds, const void *key_schedule /*__aligned(16)*/, + size_t len, const uint8_t *from, uint8_t *to, + const uint8_t iv[AES_BLOCK_LEN]); void aesni_encrypt_xts(int rounds, const void *data_schedule /*__aligned(16)*/, const void *tweak_schedule /*__aligned(16)*/, size_t len, @@ -96,6 +100,16 @@ const void *tweak_schedule /*__aligned(16)*/, size_t len, const uint8_t *from, uint8_t *to, const uint8_t iv[AES_BLOCK_LEN]); +/* GCM & GHASH functions */ +void AES_GCM_encrypt(const unsigned char *in, unsigned char *out, + const unsigned char *addt, const unsigned char *ivec, + unsigned char *tag, uint32_t nbytes, uint32_t abytes, int ibytes, + const unsigned char *key, int nr); +int AES_GCM_decrypt(const unsigned char *in, unsigned char *out, + const unsigned char *addt, const unsigned char *ivec, + unsigned char *tag, uint32_t nbytes, uint32_t abytes, int ibytes, + const unsigned char *key, int nr); + int aesni_cipher_setup_common(struct aesni_session *ses, const uint8_t *key, int keylen); uint8_t *aesni_cipher_alloc(struct cryptodesc *enccrd, struct cryptop *crp, --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/sys/crypto/aesni/aesni_ghash.c 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,786 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by John-Mark Gurney under + * the sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + * $FreeBSD$ + * + */ + +/* + * Figure 5, 8 and 12 are copied from the Intel white paper: + * Intel® Carry-Less Multiplication Instruction and its Usage for + * Computing the GCM Mode + * + * and as such are: + * Copyright © 2010 Intel Corporation. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifdef _KERNEL +#include +#else +#include +#endif + +#include +#include +#include + +static inline int +m128icmp(__m128i a, __m128i b) +{ + __m128i cmp; + + cmp = _mm_cmpeq_epi32(a, b); + + return _mm_movemask_epi8(cmp) == 0xffff; +} + +/* some code from carry-less-multiplication-instruction-in-gcm-mode-paper.pdf */ + +/* Figure 5. Code Sample - Performing Ghash Using Algorithms 1 and 5 (C) */ +static void +gfmul(__m128i a, __m128i b, __m128i *res) +{ + __m128i tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9; + + tmp3 = _mm_clmulepi64_si128(a, b, 0x00); + tmp4 = _mm_clmulepi64_si128(a, b, 0x10); + tmp5 = _mm_clmulepi64_si128(a, b, 0x01); + tmp6 = _mm_clmulepi64_si128(a, b, 0x11); + + tmp4 = _mm_xor_si128(tmp4, tmp5); + tmp5 = _mm_slli_si128(tmp4, 8); + tmp4 = _mm_srli_si128(tmp4, 8); + tmp3 = _mm_xor_si128(tmp3, tmp5); + tmp6 = _mm_xor_si128(tmp6, tmp4); + + tmp7 = _mm_srli_epi32(tmp3, 31); + tmp8 = _mm_srli_epi32(tmp6, 31); + tmp3 = _mm_slli_epi32(tmp3, 1); + tmp6 = _mm_slli_epi32(tmp6, 1); + + tmp9 = _mm_srli_si128(tmp7, 12); + tmp8 = _mm_slli_si128(tmp8, 4); + tmp7 = _mm_slli_si128(tmp7, 4); + tmp3 = _mm_or_si128(tmp3, tmp7); + tmp6 = _mm_or_si128(tmp6, tmp8); + tmp6 = _mm_or_si128(tmp6, tmp9); + + tmp7 = _mm_slli_epi32(tmp3, 31); + tmp8 = _mm_slli_epi32(tmp3, 30); + tmp9 = _mm_slli_epi32(tmp3, 25); + + tmp7 = _mm_xor_si128(tmp7, tmp8); + tmp7 = _mm_xor_si128(tmp7, tmp9); + tmp8 = _mm_srli_si128(tmp7, 4); + tmp7 = _mm_slli_si128(tmp7, 12); + tmp3 = _mm_xor_si128(tmp3, tmp7); + + tmp2 = _mm_srli_epi32(tmp3, 1); + tmp4 = _mm_srli_epi32(tmp3, 2); + tmp5 = _mm_srli_epi32(tmp3, 7); + tmp2 = _mm_xor_si128(tmp2, tmp4); + tmp2 = _mm_xor_si128(tmp2, tmp5); + tmp2 = _mm_xor_si128(tmp2, tmp8); + tmp3 = _mm_xor_si128(tmp3, tmp2); + tmp6 = _mm_xor_si128(tmp6, tmp3); + + *res = tmp6; +} + +/* + * Figure 8. Code Sample - Performing Ghash Using an Aggregated Reduction + * Method */ +static void +reduce4(__m128i H1, __m128i H2, __m128i H3, __m128i H4, + __m128i X1, __m128i X2, __m128i X3, __m128i X4, __m128i *res) +{ + /*algorithm by Krzysztof Jankowski, Pierre Laurent - Intel*/ + __m128i H1_X1_lo, H1_X1_hi, H2_X2_lo, H2_X2_hi, H3_X3_lo, + H3_X3_hi, H4_X4_lo, H4_X4_hi, lo, hi; + __m128i tmp0, tmp1, tmp2, tmp3; + __m128i tmp4, tmp5, tmp6, tmp7; + __m128i tmp8, tmp9; + + H1_X1_lo = _mm_clmulepi64_si128(H1, X1, 0x00); + H2_X2_lo = _mm_clmulepi64_si128(H2, X2, 0x00); + H3_X3_lo = _mm_clmulepi64_si128(H3, X3, 0x00); + H4_X4_lo = _mm_clmulepi64_si128(H4, X4, 0x00); + + lo = _mm_xor_si128(H1_X1_lo, H2_X2_lo); + lo = _mm_xor_si128(lo, H3_X3_lo); + lo = _mm_xor_si128(lo, H4_X4_lo); + + H1_X1_hi = _mm_clmulepi64_si128(H1, X1, 0x11); + H2_X2_hi = _mm_clmulepi64_si128(H2, X2, 0x11); + H3_X3_hi = _mm_clmulepi64_si128(H3, X3, 0x11); + H4_X4_hi = _mm_clmulepi64_si128(H4, X4, 0x11); + + hi = _mm_xor_si128(H1_X1_hi, H2_X2_hi); + hi = _mm_xor_si128(hi, H3_X3_hi); + hi = _mm_xor_si128(hi, H4_X4_hi); + + tmp0 = _mm_shuffle_epi32(H1, 78); + tmp4 = _mm_shuffle_epi32(X1, 78); + tmp0 = _mm_xor_si128(tmp0, H1); + tmp4 = _mm_xor_si128(tmp4, X1); + tmp1 = _mm_shuffle_epi32(H2, 78); + tmp5 = _mm_shuffle_epi32(X2, 78); + tmp1 = _mm_xor_si128(tmp1, H2); + tmp5 = _mm_xor_si128(tmp5, X2); + tmp2 = _mm_shuffle_epi32(H3, 78); + tmp6 = _mm_shuffle_epi32(X3, 78); + tmp2 = _mm_xor_si128(tmp2, H3); + tmp6 = _mm_xor_si128(tmp6, X3); + tmp3 = _mm_shuffle_epi32(H4, 78); + tmp7 = _mm_shuffle_epi32(X4, 78); + tmp3 = _mm_xor_si128(tmp3, H4); + tmp7 = _mm_xor_si128(tmp7, X4); + + tmp0 = _mm_clmulepi64_si128(tmp0, tmp4, 0x00); + tmp1 = _mm_clmulepi64_si128(tmp1, tmp5, 0x00); + tmp2 = _mm_clmulepi64_si128(tmp2, tmp6, 0x00); + tmp3 = _mm_clmulepi64_si128(tmp3, tmp7, 0x00); + + tmp0 = _mm_xor_si128(tmp0, lo); + tmp0 = _mm_xor_si128(tmp0, hi); + tmp0 = _mm_xor_si128(tmp1, tmp0); + tmp0 = _mm_xor_si128(tmp2, tmp0); + tmp0 = _mm_xor_si128(tmp3, tmp0); + + tmp4 = _mm_slli_si128(tmp0, 8); + tmp0 = _mm_srli_si128(tmp0, 8); + + lo = _mm_xor_si128(tmp4, lo); + hi = _mm_xor_si128(tmp0, hi); + + tmp3 = lo; + tmp6 = hi; + + tmp7 = _mm_srli_epi32(tmp3, 31); + tmp8 = _mm_srli_epi32(tmp6, 31); + tmp3 = _mm_slli_epi32(tmp3, 1); + tmp6 = _mm_slli_epi32(tmp6, 1); + + tmp9 = _mm_srli_si128(tmp7, 12); + tmp8 = _mm_slli_si128(tmp8, 4); + tmp7 = _mm_slli_si128(tmp7, 4); + tmp3 = _mm_or_si128(tmp3, tmp7); + tmp6 = _mm_or_si128(tmp6, tmp8); + tmp6 = _mm_or_si128(tmp6, tmp9); + + tmp7 = _mm_slli_epi32(tmp3, 31); + tmp8 = _mm_slli_epi32(tmp3, 30); + tmp9 = _mm_slli_epi32(tmp3, 25); + + tmp7 = _mm_xor_si128(tmp7, tmp8); + tmp7 = _mm_xor_si128(tmp7, tmp9); + tmp8 = _mm_srli_si128(tmp7, 4); + tmp7 = _mm_slli_si128(tmp7, 12); + tmp3 = _mm_xor_si128(tmp3, tmp7); + + tmp2 = _mm_srli_epi32(tmp3, 1); + tmp4 = _mm_srli_epi32(tmp3, 2); + tmp5 = _mm_srli_epi32(tmp3, 7); + tmp2 = _mm_xor_si128(tmp2, tmp4); + tmp2 = _mm_xor_si128(tmp2, tmp5); + tmp2 = _mm_xor_si128(tmp2, tmp8); + tmp3 = _mm_xor_si128(tmp3, tmp2); + tmp6 = _mm_xor_si128(tmp6, tmp3); + + *res = tmp6; +} + +/* + * Figure 12. AES-GCM: Processing Four Blocks in Parallel with Aggregated + * Every Four Blocks + */ +/* + * per NIST SP-800-38D, 5.2.1.1, len(p) <= 2^39-256 (in bits), or + * 2^32-256*8*16 bytes. + */ +void +AES_GCM_encrypt(const unsigned char *in, unsigned char *out, + const unsigned char *addt, const unsigned char *ivec, + unsigned char *tag, uint32_t nbytes, uint32_t abytes, int ibytes, + const unsigned char *key, int nr) +{ + int i, j ,k; + __m128i tmp1, tmp2, tmp3, tmp4; + __m128i tmp5, tmp6, tmp7, tmp8; + __m128i H, H2, H3, H4, Y, T; + __m128i *KEY = (__m128i*)key; + __m128i ctr1, ctr2, ctr3, ctr4; + __m128i ctr5, ctr6, ctr7, ctr8; + __m128i last_block = _mm_setzero_si128(); + __m128i ONE = _mm_set_epi32(0, 1, 0, 0); + __m128i EIGHT = _mm_set_epi32(0, 8, 0, 0); + __m128i BSWAP_EPI64 = _mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6, + 7); + __m128i BSWAP_MASK = _mm_set_epi8(0,1,2,3,4,5,6,7,8,9,10,11,12,13,14, + 15); + __m128i X = _mm_setzero_si128(); + + if (ibytes == 96/8) { + Y = _mm_loadu_si128((__m128i*)ivec); + Y = _mm_insert_epi32(Y, 0x1000000, 3); + /*(Compute E[ZERO, KS] and E[Y0, KS] together*/ + tmp1 = _mm_xor_si128(X, KEY[0]); + tmp2 = _mm_xor_si128(Y, KEY[0]); + for (j=1; j < nr-1; j+=2) { + tmp1 = _mm_aesenc_si128(tmp1, KEY[j]); + tmp2 = _mm_aesenc_si128(tmp2, KEY[j]); + + tmp1 = _mm_aesenc_si128(tmp1, KEY[j+1]); + tmp2 = _mm_aesenc_si128(tmp2, KEY[j+1]); + } + tmp1 = _mm_aesenc_si128(tmp1, KEY[nr-1]); + tmp2 = _mm_aesenc_si128(tmp2, KEY[nr-1]); + + H = _mm_aesenclast_si128(tmp1, KEY[nr]); + T = _mm_aesenclast_si128(tmp2, KEY[nr]); + + H = _mm_shuffle_epi8(H, BSWAP_MASK); + } else { + tmp1 = _mm_xor_si128(X, KEY[0]); + for (j=1; j * Copyright (c) 2010-2011 Pawel Jakub Dawidek * Copyright 2012-2013 John-Mark Gurney + * Copyright (c) 2014 The FreeBSD Foundation * All rights reserved. * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -29,15 +34,18 @@ #include __FBSDID("$FreeBSD: head/sys/crypto/aesni/aesni_wrap.c 267815 2014-06-24 06:55:49Z kib $"); - + #include #include #include #include #include #include - + +#include + #include "aesencdec.h" +#include MALLOC_DECLARE(M_AESNI); @@ -176,6 +184,104 @@ } } +/* + * mixed endian increment, low 64bits stored in hi word to be compatible + * with _icm's BSWAP. + */ +static inline __m128i +nextc(__m128i x) +{ + const __m128i ONE = _mm_setr_epi32(0, 0, 1, 0); + const __m128i ZERO = _mm_setzero_si128(); + + x = _mm_add_epi64(x, ONE); + __m128i t = _mm_cmpeq_epi64(x, ZERO); + t = _mm_unpackhi_epi64(t, ZERO); + x = _mm_sub_epi64(x, t); + + return x; +} + +void +aesni_encrypt_icm(int rounds, const void *key_schedule, size_t len, + const uint8_t *from, uint8_t *to, const uint8_t iv[AES_BLOCK_LEN]) +{ + __m128i tot; + __m128i tmp1, tmp2, tmp3, tmp4; + __m128i tmp5, tmp6, tmp7, tmp8; + __m128i ctr1, ctr2, ctr3, ctr4; + __m128i ctr5, ctr6, ctr7, ctr8; + __m128i BSWAP_EPI64; + __m128i tout[8]; + struct blocks8 *top; + const struct blocks8 *blks; + size_t i, cnt; + + BSWAP_EPI64 = _mm_set_epi8(8,9,10,11,12,13,14,15,0,1,2,3,4,5,6,7); + + ctr1 = _mm_loadu_si128((__m128i*)iv); + ctr1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64); + + cnt = len / AES_BLOCK_LEN / 8; + for (i = 0; i < cnt; i++) { + tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64); + ctr2 = nextc(ctr1); + tmp2 = _mm_shuffle_epi8(ctr2, BSWAP_EPI64); + ctr3 = nextc(ctr2); + tmp3 = _mm_shuffle_epi8(ctr3, BSWAP_EPI64); + ctr4 = nextc(ctr3); + tmp4 = _mm_shuffle_epi8(ctr4, BSWAP_EPI64); + ctr5 = nextc(ctr4); + tmp5 = _mm_shuffle_epi8(ctr5, BSWAP_EPI64); + ctr6 = nextc(ctr5); + tmp6 = _mm_shuffle_epi8(ctr6, BSWAP_EPI64); + ctr7 = nextc(ctr6); + tmp7 = _mm_shuffle_epi8(ctr7, BSWAP_EPI64); + ctr8 = nextc(ctr7); + tmp8 = _mm_shuffle_epi8(ctr8, BSWAP_EPI64); + ctr1 = nextc(ctr8); + + blks = (const struct blocks8 *)from; + top = (struct blocks8 *)to; + aesni_enc8(rounds - 1, key_schedule, tmp1, tmp2, tmp3, tmp4, + tmp5, tmp6, tmp7, tmp8, tout); + + top->blk[0] = blks->blk[0] ^ tout[0]; + top->blk[1] = blks->blk[1] ^ tout[1]; + top->blk[2] = blks->blk[2] ^ tout[2]; + top->blk[3] = blks->blk[3] ^ tout[3]; + top->blk[4] = blks->blk[4] ^ tout[4]; + top->blk[5] = blks->blk[5] ^ tout[5]; + top->blk[6] = blks->blk[6] ^ tout[6]; + top->blk[7] = blks->blk[7] ^ tout[7]; + + from += AES_BLOCK_LEN * 8; + to += AES_BLOCK_LEN * 8; + } + i *= 8; + cnt = len / AES_BLOCK_LEN; + for (; i < cnt; i++) { + tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64); + ctr1 = nextc(ctr1); + + tot = aesni_enc(rounds - 1, key_schedule, tmp1); + + tot = tot ^ _mm_loadu_si128((const __m128i *)from); + _mm_storeu_si128((__m128i *)to, tot); + + from += AES_BLOCK_LEN; + to += AES_BLOCK_LEN; + } + + /* handle remaining partial round */ + if (len % AES_BLOCK_LEN != 0) { + tmp1 = _mm_shuffle_epi8(ctr1, BSWAP_EPI64); + tot = aesni_enc(rounds - 1, key_schedule, tmp1); + tot = tot ^ _mm_loadu_si128((const __m128i *)from); + memcpy(to, &tot, len % AES_BLOCK_LEN); + } +} + #define AES_XTS_BLOCKSIZE 16 #define AES_XTS_IVSIZE 8 #define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ @@ -333,8 +439,15 @@ aesni_cipher_setup_common(struct aesni_session *ses, const uint8_t *key, int keylen) { + int decsched; + + decsched = 1; switch (ses->algo) { + case CRYPTO_AES_ICM: + case CRYPTO_AES_NIST_GCM_16: + decsched = 0; + /* FALLTHROUGH */ case CRYPTO_AES_CBC: switch (keylen) { case 128: @@ -347,6 +460,7 @@ ses->rounds = AES256_ROUNDS; break; default: + CRYPTDEB("invalid CBC/ICM/GCM key length"); return (EINVAL); } break; @@ -359,6 +473,7 @@ ses->rounds = AES256_ROUNDS; break; default: + CRYPTDEB("invalid XTS key length"); return (EINVAL); } break; @@ -367,13 +482,13 @@ } aesni_set_enckey(key, ses->enc_schedule, ses->rounds); - aesni_set_deckey(ses->enc_schedule, ses->dec_schedule, ses->rounds); - if (ses->algo == CRYPTO_AES_CBC) - arc4rand(ses->iv, sizeof(ses->iv), 0); - else /* if (ses->algo == CRYPTO_AES_XTS) */ { + if (decsched) + aesni_set_deckey(ses->enc_schedule, ses->dec_schedule, + ses->rounds); + + if (ses->algo == CRYPTO_AES_XTS) aesni_set_enckey(key + keylen / 16, ses->xts_schedule, ses->rounds); - } return (0); } --- //depot/vendor/freebsd/src/sys/crypto/via/padlock_hash.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/crypto/via/padlock_hash.c 2014-09-02 16:11:00.000000000 -0700 @@ -75,7 +75,7 @@ CTASSERT(sizeof(struct padlock_sha_ctx) <= sizeof(union authctx)); static void padlock_sha_init(struct padlock_sha_ctx *ctx); -static int padlock_sha_update(struct padlock_sha_ctx *ctx, uint8_t *buf, +static int padlock_sha_update(struct padlock_sha_ctx *ctx, const uint8_t *buf, uint16_t bufsize); static void padlock_sha1_final(uint8_t *hash, struct padlock_sha_ctx *ctx); static void padlock_sha256_final(uint8_t *hash, struct padlock_sha_ctx *ctx); @@ -83,16 +83,16 @@ static struct auth_hash padlock_hmac_sha1 = { CRYPTO_SHA1_HMAC, "HMAC-SHA1", 20, SHA1_HASH_LEN, SHA1_HMAC_BLOCK_LEN, sizeof(struct padlock_sha_ctx), - (void (*)(void *))padlock_sha_init, - (int (*)(void *, uint8_t *, uint16_t))padlock_sha_update, + (void (*)(void *))padlock_sha_init, NULL, NULL, + (int (*)(void *, const uint8_t *, uint16_t))padlock_sha_update, (void (*)(uint8_t *, void *))padlock_sha1_final }; static struct auth_hash padlock_hmac_sha256 = { CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256", 32, SHA2_256_HASH_LEN, SHA2_256_HMAC_BLOCK_LEN, sizeof(struct padlock_sha_ctx), - (void (*)(void *))padlock_sha_init, - (int (*)(void *, uint8_t *, uint16_t))padlock_sha_update, + (void (*)(void *))padlock_sha_init, NULL, NULL, + (int (*)(void *, const uint8_t *, uint16_t))padlock_sha_update, (void (*)(uint8_t *, void *))padlock_sha256_final }; @@ -167,7 +167,7 @@ } static int -padlock_sha_update(struct padlock_sha_ctx *ctx, uint8_t *buf, uint16_t bufsize) +padlock_sha_update(struct padlock_sha_ctx *ctx, const uint8_t *buf, uint16_t bufsize) { if (ctx->psc_size - ctx->psc_offset < bufsize) { --- //depot/vendor/freebsd/src/sys/geom/eli/g_eli_crypto.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/geom/eli/g_eli_crypto.c 2014-09-02 16:11:00.000000000 -0700 @@ -101,7 +101,7 @@ crp->crp_opaque = NULL; crp->crp_callback = g_eli_crypto_done; crp->crp_buf = (void *)data; - crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_REL; + crp->crp_flags = CRYPTO_F_CBIFSYNC; crp->crp_desc = crd; error = crypto_dispatch(crp); --- //depot/vendor/freebsd/src/sys/geom/eli/g_eli_integrity.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/geom/eli/g_eli_integrity.c 2014-09-02 16:11:00.000000000 -0700 @@ -479,7 +479,7 @@ crp->crp_opaque = (void *)bp; crp->crp_buf = (void *)data; data += encr_secsize; - crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_REL; + crp->crp_flags = CRYPTO_F_CBIFSYNC; if (g_eli_batch) crp->crp_flags |= CRYPTO_F_BATCH; if (bp->bio_cmd == BIO_WRITE) { --- //depot/vendor/freebsd/src/sys/geom/eli/g_eli_privacy.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/geom/eli/g_eli_privacy.c 2014-09-02 16:11:00.000000000 -0700 @@ -286,7 +286,7 @@ crp->crp_callback = g_eli_crypto_write_done; else /* if (bp->bio_cmd == BIO_READ) */ crp->crp_callback = g_eli_crypto_read_done; - crp->crp_flags = CRYPTO_F_CBIFSYNC | CRYPTO_F_REL; + crp->crp_flags = CRYPTO_F_CBIFSYNC; if (g_eli_batch) crp->crp_flags |= CRYPTO_F_BATCH; crp->crp_desc = crd; --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/sys/libkern/timingsafe_bcmp.c 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,32 @@ +/* $OpenBSD: timingsafe_bcmp.c,v 1.2 2014/06/10 04:16:57 deraadt Exp $ */ +/* + * Copyright (c) 2010 Damien Miller. All rights reserved. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * $FreeBSD$ + * + */ + +#include + +int +timingsafe_bcmp(const void *b1, const void *b2, size_t n) +{ + const unsigned char *p1 = b1, *p2 = b2; + int ret = 0; + + for (; n > 0; n--) + ret |= *p1++ ^ *p2++; + return (ret != 0); +} --- //depot/vendor/freebsd/src/sys/mips/rmi/dev/sec/rmisec.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/mips/rmi/dev/sec/rmisec.c 2014-09-02 16:11:00.000000000 -0700 @@ -423,13 +423,8 @@ cmd->op.source_buf = (uint64_t) (unsigned long)crp->crp_buf; cmd->op.source_buf_size = crp->crp_ilen; - if (crp->crp_flags & CRYPTO_F_REL) { - cmd->op.dest_buf = (uint64_t) (unsigned long)crp->crp_buf; - cmd->op.dest_buf_size = crp->crp_ilen; - } else { - cmd->op.dest_buf = (uint64_t) (unsigned long)crp->crp_buf; - cmd->op.dest_buf_size = crp->crp_ilen; - } + cmd->op.dest_buf = (uint64_t) (unsigned long)crp->crp_buf; + cmd->op.dest_buf_size = crp->crp_ilen; cmd->op.num_packets = 1; cmd->op.num_fragments = 1; --- //depot/vendor/freebsd/src/sys/modules/aesni/Makefile.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/modules/aesni/Makefile 2014-09-02 16:11:00.000000000 -0700 @@ -7,13 +7,18 @@ SRCS+= aeskeys_${MACHINE_CPUARCH}.S SRCS+= device_if.h bus_if.h opt_bus.h cryptodev_if.h -OBJS+= aesni_wrap.o +OBJS+= aesni_ghash.o aesni_wrap.o # Remove -nostdinc so we can get the intrinsics. +aesni_ghash.o: aesni_ghash.c + # XXX - gcc won't understand -mpclmul + ${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} \ + -mmmx -msse -msse4 -maes -mpclmul ${.IMPSRC} + ${CTFCONVERT_CMD} + aesni_wrap.o: aesni_wrap.c ${CC} -c ${CFLAGS:C/^-O2$/-O3/:N-nostdinc} ${WERROR} ${PROF} \ - -mmmx -msse -maes ${.IMPSRC} + -mmmx -msse -msse4 -maes ${.IMPSRC} ${CTFCONVERT_CMD} .include - --- //depot/vendor/freebsd/src/sys/modules/crypto/Makefile.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/modules/crypto/Makefile 2014-09-02 16:11:00.000000000 -0700 @@ -18,6 +18,7 @@ SRCS += des_ecb.c des_enc.c des_setkey.c SRCS += sha1.c sha2.c sha256c.c SRCS += siphash.c +SRCS += gmac.c gfmult.c SRCS += opt_param.h cryptodev_if.h bus_if.h device_if.h SRCS += opt_ddb.h --- //depot/vendor/freebsd/src/sys/opencrypto/criov.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/criov.c 2014-09-02 16:11:00.000000000 -0700 @@ -99,35 +99,31 @@ } /* - * Return a pointer to iov/offset of location in iovec list. + * Return the index and offset of location in iovec list. */ -struct iovec * +int cuio_getptr(struct uio *uio, int loc, int *off) { - struct iovec *iov = uio->uio_iov; - int iol = uio->uio_iovcnt; + int ind, len; - while (loc >= 0) { - /* Normal end of search */ - if (loc < iov->iov_len) { + ind = 0; + while (loc >= 0 && ind < uio->uio_iovcnt) { + len = uio->uio_iov[ind].iov_len; + if (len > loc) { *off = loc; - return (iov); + return (ind); } + loc -= len; + ind++; + } - loc -= iov->iov_len; - if (iol == 0) { - if (loc == 0) { - /* Point at the end of valid data */ - *off = iov->iov_len; - return (iov); - } else - return (NULL); - } else { - iov++, iol--; - } - } + if (ind > 0 && loc == 0) { + ind--; + *off = uio->uio_iov[ind].iov_len; + return (ind); + } - return (NULL); + return (-1); } /* @@ -196,3 +192,47 @@ error = (*f)(arg, buf + off, len); return (error); } + +void +crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, int *cnt, + int *allocated) +{ + struct iovec *iov; + struct mbuf *m, *mtmp; + int i, j; + + *allocated = 0; + iov = *iovptr; + if (iov == NULL) + *cnt = 0; + + m = mbuf; + i = 0; + while (m != NULL) { + if (i == *cnt) { + /* we need to allocate a larger array */ + j = 1; + mtmp = m; + while ((mtmp = mtmp->m_next) != NULL) + j++; + iov = malloc(sizeof *iov * (i + j), M_CRYPTO_DATA, + M_WAITOK); + *allocated = 1; + *cnt = i + j; + memcpy(iov, *iovptr, sizeof *iov * i); + } + + iov[i].iov_base = m->m_data; + iov[i].iov_len = m->m_len; + + i++; + m = m->m_next; + } + + if (*allocated) + KASSERT(*cnt == i, ("did not allocate correct amount: %d != %d", + *cnt, i)); + + *iovptr = iov; + *cnt = i; +} --- //depot/vendor/freebsd/src/sys/opencrypto/crypto.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/crypto.c 2014-09-02 16:11:00.000000000 -0700 @@ -368,9 +368,8 @@ best = cap; } } - if (best != NULL) - return best; - if (match == CRYPTOCAP_F_HARDWARE && (flags & CRYPTOCAP_F_SOFTWARE)) { + if (best == NULL && match == CRYPTOCAP_F_HARDWARE && + (flags & CRYPTOCAP_F_SOFTWARE)) { /* sort of an Algol 68-style for loop */ match = CRYPTOCAP_F_SOFTWARE; goto again; @@ -421,9 +420,12 @@ (*sid) <<= 32; (*sid) |= (lid & 0xffffffff); cap->cc_sessions++; - } - } else + } else + CRYPTDEB("dev newsession failed"); + } else { + CRYPTDEB("no driver"); err = EINVAL; + } CRYPTO_DRIVER_UNLOCK(); return err; } --- //depot/vendor/freebsd/src/sys/opencrypto/cryptodev.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/cryptodev.c 2014-09-02 16:11:00.000000000 -0700 @@ -3,7 +3,13 @@ /*- * Copyright (c) 2001 Theo de Raadt * Copyright (c) 2002-2006 Sam Leffler, Errno Consulting + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -36,6 +42,7 @@ __FBSDID("$FreeBSD: head/sys/opencrypto/cryptodev.c 271983 2014-09-22 17:32:27Z jhb $"); #include "opt_compat.h" +#include "opt_kdtrace.h" #include #include @@ -55,10 +62,15 @@ #include #include #include +#include #include #include +SDT_PROVIDER_DECLARE(opencrypto); + +SDT_PROBE_DEFINE1(opencrypto, dev, ioctl, error, "int"/*line number*/); + #ifdef COMPAT_FREEBSD32 #include #include @@ -315,6 +327,8 @@ static int cryptodev_op(struct csession *, struct crypt_op *, struct ucred *, struct thread *td); +static int cryptodev_aead(struct csession *, struct crypt_aead *, + struct ucred *, struct thread *); static int cryptodev_key(struct crypt_kop *); static int cryptodev_find(struct crypt_find_op *); @@ -324,15 +338,23 @@ * by device name/class or through search constraints. */ static int -checkforsoftware(int crid) +checkforsoftware(int *cridp) { + int crid; + crid = *cridp; + if (!crypto_devallowsoft) { - if (crid & CRYPTOCAP_F_SOFTWARE) - return EINVAL; /* XXX */ + if (crid & CRYPTOCAP_F_SOFTWARE) { + if (crid & CRYPTOCAP_F_HARDWARE) { + *cridp = CRYPTOCAP_F_HARDWARE; + return 0; + } + return EINVAL; + } if ((crid & CRYPTOCAP_F_HARDWARE) == 0 && (crypto_getcaps(crid) & CRYPTOCAP_F_HARDWARE) == 0) - return EINVAL; /* XXX */ + return EINVAL; } return 0; } @@ -352,6 +374,7 @@ struct csession *cse; struct session_op *sop; struct crypt_op *cop; + struct crypt_aead *caead; struct enc_xform *txform = NULL; struct auth_hash *thash = NULL; struct crypt_kop *kop; @@ -412,7 +435,15 @@ case CRYPTO_CAMELLIA_CBC: txform = &enc_xform_camellia; break; + case CRYPTO_AES_ICM: + txform = &enc_xform_aes_icm; + break; + case CRYPTO_AES_NIST_GCM_16: + txform = &enc_xform_aes_nist_gcm; + break; + default: + CRYPTDEB("invalid cipher"); return (EINVAL); } @@ -437,6 +468,16 @@ case CRYPTO_RIPEMD160_HMAC: thash = &auth_hash_hmac_ripemd_160; break; + case CRYPTO_AES_128_NIST_GMAC: + thash = &auth_hash_nist_gmac_aes_128; + break; + case CRYPTO_AES_192_NIST_GMAC: + thash = &auth_hash_nist_gmac_aes_192; + break; + case CRYPTO_AES_256_NIST_GMAC: + thash = &auth_hash_nist_gmac_aes_256; + break; + #ifdef notdef case CRYPTO_MD5: thash = &auth_hash_md5; @@ -449,6 +490,7 @@ thash = &auth_hash_null; break; default: + CRYPTDEB("invalid mac"); return (EINVAL); } @@ -460,6 +502,7 @@ crie.cri_klen = sop->keylen * 8; if (sop->keylen > txform->maxkey || sop->keylen < txform->minkey) { + CRYPTDEB("invalid cipher parameters"); error = EINVAL; goto bail; } @@ -467,8 +510,10 @@ crie.cri_key = malloc(crie.cri_klen / 8, M_XDATA, M_WAITOK); if ((error = copyin(sop->key, crie.cri_key, - crie.cri_klen / 8))) + crie.cri_klen / 8))) { + CRYPTDEB("invalid key"); goto bail; + } if (thash) crie.cri_next = &cria; } @@ -477,6 +522,7 @@ cria.cri_alg = thash->type; cria.cri_klen = sop->mackeylen * 8; if (sop->mackeylen != thash->keysize) { + CRYPTDEB("invalid mac key length"); error = EINVAL; goto bail; } @@ -485,8 +531,10 @@ cria.cri_key = malloc(cria.cri_klen / 8, M_XDATA, M_WAITOK); if ((error = copyin(sop->mackey, cria.cri_key, - cria.cri_klen / 8))) + cria.cri_klen / 8))) { + CRYPTDEB("invalid mac key"); goto bail; + } } } @@ -497,14 +545,18 @@ #endif ) { crid = SES2(sop)->crid; - error = checkforsoftware(crid); - if (error) + error = checkforsoftware(&crid); + if (error) { + CRYPTDEB("checkforsoftware"); goto bail; + } } else crid = CRYPTOCAP_F_HARDWARE; error = crypto_newsession(&sid, (txform ? &crie : &cria), crid); - if (error) + if (error) { + CRYPTDEB("crypto_newsession"); goto bail; + } cse = csecreate(fcr, sid, crie.cri_key, crie.cri_klen, cria.cri_key, cria.cri_klen, sop->cipher, sop->mac, txform, @@ -513,6 +565,7 @@ if (cse == NULL) { crypto_freesession(sid); error = EINVAL; + CRYPTDEB("csecreate"); goto bail; } sop->ses = cse->ses; @@ -559,8 +612,10 @@ #endif cop = (struct crypt_op *)data; cse = csefind(fcr, cop->ses); - if (cse == NULL) + if (cse == NULL) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); return (EINVAL); + } error = cryptodev_op(cse, cop, active_cred, td); #ifdef COMPAT_FREEBSD32 if (error == 0 && cmd == CIOCCRYPT32) @@ -614,6 +669,13 @@ case CIOCFINDDEV: error = cryptodev_find((struct crypt_find_op *)data); break; + case CIOCCRYPTAEAD: + caead = (struct crypt_aead *)data; + cse = csefind(fcr, caead->ses); + if (cse == NULL) + return (EINVAL); + error = cryptodev_aead(cse, caead, active_cred, td); + break; default: error = EINVAL; break; @@ -636,12 +698,16 @@ struct cryptodesc *crde = NULL, *crda = NULL; int error; - if (cop->len > 256*1024-4) + if (cop->len > 256*1024-4) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); return (E2BIG); + } if (cse->txform) { - if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0) + if (cop->len == 0 || (cop->len % cse->txform->blocksize) != 0) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); return (EINVAL); + } } cse->uio.uio_iov = &cse->iovec; @@ -661,6 +727,7 @@ crp = crypto_getreq((cse->txform != NULL) + (cse->thash != NULL)); if (crp == NULL) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = ENOMEM; goto bail; } @@ -673,13 +740,17 @@ if (cse->txform) crde = crp->crp_desc; else { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = EINVAL; goto bail; } } - if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, cop->len))) + if ((error = copyin(cop->src, cse->uio.uio_iov[0].iov_base, + cop->len))) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); goto bail; + } if (crda) { crda->crd_skip = 0; @@ -714,15 +785,20 @@ if (cop->iv) { if (crde == NULL) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = EINVAL; goto bail; } if (cse->cipher == CRYPTO_ARC4) { /* XXX use flag? */ + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = EINVAL; goto bail; } - if ((error = copyin(cop->iv, cse->tmp_iv, cse->txform->blocksize))) + if ((error = copyin(cop->iv, cse->tmp_iv, + cse->txform->blocksize))) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); goto bail; + } bcopy(cse->tmp_iv, crde->crd_iv, cse->txform->blocksize); crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; crde->crd_skip = 0; @@ -735,6 +811,7 @@ } if (cop->mac && crda == NULL) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = EINVAL; goto bail; } @@ -753,8 +830,10 @@ error = msleep(crp, &cse->lock, PWAIT, "crydev", 0); mtx_unlock(&cse->lock); - if (error != 0) + if (error != 0) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); goto bail; + } if (crp->crp_etype == EAGAIN) { crp->crp_etype = 0; @@ -763,23 +842,30 @@ } if (crp->crp_etype != 0) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = crp->crp_etype; goto bail; } if (cse->error) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); error = cse->error; goto bail; } if (cop->dst && - (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, cop->len))) + (error = copyout(cse->uio.uio_iov[0].iov_base, cop->dst, + cop->len))) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); goto bail; + } if (cop->mac && (error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + cop->len, - cop->mac, cse->thash->hashsize))) + cop->mac, cse->thash->hashsize))) { + SDT_PROBE1(opencrypto, dev, ioctl, error, __LINE__); goto bail; + } bail: if (crp) @@ -791,6 +877,152 @@ } static int +cryptodev_aead( + struct csession *cse, + struct crypt_aead *caead, + struct ucred *active_cred, + struct thread *td) +{ + struct uio *uio; + struct cryptop *crp = NULL; + struct cryptodesc *crde = NULL, *crda = NULL; + int error; + + if (caead->len > 256*1024-4 || caead->aadlen > 256*1024-4) + return (E2BIG); + + if (cse->txform == NULL || cse->thash == NULL || caead->tag == NULL || + (caead->len % cse->txform->blocksize) != 0) + return (EINVAL); + + uio = &cse->uio; + uio->uio_iov = &cse->iovec; + uio->uio_iovcnt = 1; + uio->uio_offset = 0; + uio->uio_resid = caead->len + caead->aadlen + cse->thash->hashsize; + uio->uio_segflg = UIO_SYSSPACE; + uio->uio_rw = UIO_WRITE; + uio->uio_td = td; + uio->uio_iov[0].iov_len = uio->uio_resid; + + uio->uio_iov[0].iov_base = malloc(uio->uio_iov[0].iov_len, + M_XDATA, M_WAITOK); + + crp = crypto_getreq(2); + if (crp == NULL) { + error = ENOMEM; + goto bail; + } + + crda = crp->crp_desc; + crde = crda->crd_next; + + if ((error = copyin(caead->src, cse->uio.uio_iov[0].iov_base, + caead->len))) + goto bail; + + if ((error = copyin(caead->aad, (char *)cse->uio.uio_iov[0].iov_base + + caead->len, caead->aadlen))) + goto bail; + + crda->crd_skip = caead->len; + crda->crd_len = caead->aadlen; + crda->crd_inject = caead->len + caead->aadlen; + + crda->crd_alg = cse->mac; + crda->crd_key = cse->mackey; + crda->crd_klen = cse->mackeylen * 8; + + if (caead->op == COP_ENCRYPT) + crde->crd_flags |= CRD_F_ENCRYPT; + else + crde->crd_flags &= ~CRD_F_ENCRYPT; + /* crde->crd_skip set below */ + crde->crd_len = caead->len; + crde->crd_inject = 0; + + crde->crd_alg = cse->cipher; + crde->crd_key = cse->key; + crde->crd_klen = cse->keylen * 8; + + crp->crp_ilen = caead->len + caead->aadlen; + crp->crp_flags = CRYPTO_F_IOV | CRYPTO_F_CBIMM + | (caead->flags & COP_F_BATCH); + crp->crp_buf = (caddr_t)&cse->uio.uio_iov; + crp->crp_callback = (int (*) (struct cryptop *)) cryptodev_cb; + crp->crp_sid = cse->sid; + crp->crp_opaque = (void *)cse; + + if (caead->iv) { + if (caead->ivlen > sizeof cse->tmp_iv) { + error = EINVAL; + printf("a: %d, b: %lu\n", caead->ivlen, sizeof cse->tmp_iv); + goto bail; + } + + if ((error = copyin(caead->iv, cse->tmp_iv, caead->ivlen))) + goto bail; + bcopy(cse->tmp_iv, crde->crd_iv, caead->ivlen); + crde->crd_flags |= CRD_F_IV_EXPLICIT | CRD_F_IV_PRESENT; + crde->crd_skip = 0; + } else { + crde->crd_flags |= CRD_F_IV_PRESENT; + crde->crd_skip = cse->txform->blocksize; + crde->crd_len -= cse->txform->blocksize; + } + + if ((error = copyin(caead->tag, (caddr_t)cse->uio.uio_iov[0].iov_base + + caead->len + caead->aadlen, cse->thash->hashsize))) + goto bail; +again: + /* + * Let the dispatch run unlocked, then, interlock against the + * callback before checking if the operation completed and going + * to sleep. This insures drivers don't inherit our lock which + * results in a lock order reversal between crypto_dispatch forced + * entry and the crypto_done callback into us. + */ + error = crypto_dispatch(crp); + mtx_lock(&cse->lock); + if (error == 0 && (crp->crp_flags & CRYPTO_F_DONE) == 0) + error = msleep(crp, &cse->lock, PWAIT, "crydev", 0); + mtx_unlock(&cse->lock); + + if (error != 0) + goto bail; + + if (crp->crp_etype == EAGAIN) { + crp->crp_etype = 0; + crp->crp_flags &= ~CRYPTO_F_DONE; + goto again; + } + + if (crp->crp_etype != 0) { + error = crp->crp_etype; + goto bail; + } + + if (cse->error) { + error = cse->error; + goto bail; + } + + if (caead->dst && (error = copyout(cse->uio.uio_iov[0].iov_base, + caead->dst, caead->len))) + goto bail; + + if ((error = copyout((caddr_t)cse->uio.uio_iov[0].iov_base + + caead->len + caead->aadlen, caead->tag, cse->thash->hashsize))) + goto bail; + +bail: + crypto_freereq(crp); + free(cse->uio.uio_iov[0].iov_base, M_XDATA); + + return (error); +} + +static int cryptodev_cb(void *op) { struct cryptop *crp = (struct cryptop *) op; @@ -919,14 +1151,16 @@ cryptodev_find(struct crypt_find_op *find) { device_t dev; + size_t fnlen = sizeof find->name; if (find->crid != -1) { dev = crypto_find_device_byhid(find->crid); if (dev == NULL) return (ENOENT); - strlcpy(find->name, device_get_nameunit(dev), - sizeof(find->name)); + strncpy(find->name, device_get_nameunit(dev), fnlen); + find->name[fnlen - 1] = '\x0'; } else { + find->name[fnlen - 1] = '\x0'; find->crid = crypto_find_driver(find->name); if (find->crid == -1) return (ENOENT); --- //depot/vendor/freebsd/src/sys/opencrypto/cryptodev.h.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/cryptodev.h 2014-09-02 16:11:00.000000000 -0700 @@ -23,7 +23,13 @@ * PURPOSE. * * Copyright (c) 2001 Theo de Raadt + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -100,20 +106,23 @@ #define CAMELLIA_BLOCK_LEN 16 #define EALG_MAX_BLOCK_LEN AES_BLOCK_LEN /* Keep this updated */ +/* Maximum hash algorithm result length */ +#define AALG_MAX_RESULT_LEN 64 /* Keep this updated */ + #define CRYPTO_ALGORITHM_MIN 1 -#define CRYPTO_DES_CBC 1 -#define CRYPTO_3DES_CBC 2 -#define CRYPTO_BLF_CBC 3 -#define CRYPTO_CAST_CBC 4 -#define CRYPTO_SKIPJACK_CBC 5 -#define CRYPTO_MD5_HMAC 6 -#define CRYPTO_SHA1_HMAC 7 -#define CRYPTO_RIPEMD160_HMAC 8 -#define CRYPTO_MD5_KPDK 9 -#define CRYPTO_SHA1_KPDK 10 -#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */ -#define CRYPTO_AES_CBC 11 /* 128 bit blocksize -- the same as above */ -#define CRYPTO_ARC4 12 +#define CRYPTO_DES_CBC 1 +#define CRYPTO_3DES_CBC 2 +#define CRYPTO_BLF_CBC 3 +#define CRYPTO_CAST_CBC 4 +#define CRYPTO_SKIPJACK_CBC 5 +#define CRYPTO_MD5_HMAC 6 +#define CRYPTO_SHA1_HMAC 7 +#define CRYPTO_RIPEMD160_HMAC 8 +#define CRYPTO_MD5_KPDK 9 +#define CRYPTO_SHA1_KPDK 10 +#define CRYPTO_RIJNDAEL128_CBC 11 /* 128 bit blocksize */ +#define CRYPTO_AES_CBC 11 /* 128 bit blocksize -- the same as above */ +#define CRYPTO_ARC4 12 #define CRYPTO_MD5 13 #define CRYPTO_SHA1 14 #define CRYPTO_NULL_HMAC 15 @@ -122,9 +131,18 @@ #define CRYPTO_SHA2_256_HMAC 18 #define CRYPTO_SHA2_384_HMAC 19 #define CRYPTO_SHA2_512_HMAC 20 -#define CRYPTO_CAMELLIA_CBC 21 +#define CRYPTO_CAMELLIA_CBC 21 #define CRYPTO_AES_XTS 22 -#define CRYPTO_ALGORITHM_MAX 22 /* Keep updated - see below */ +#define CRYPTO_AES_ICM 23 /* commonly known as CTR mode */ +#define CRYPTO_AES_NIST_GMAC 24 /* cipher side */ +#define CRYPTO_AES_NIST_GCM_16 25 /* 16 byte ICV */ +#define CRYPTO_AES_128_NIST_GMAC 26 /* auth side */ +#define CRYPTO_AES_192_NIST_GMAC 27 /* auth side */ +#define CRYPTO_AES_256_NIST_GMAC 28 /* auth side */ +#define CRYPTO_ALGORITHM_MAX 28 /* Keep updated - see below */ + +#define CRYPTO_ALGO_VALID(x) ((x) >= CRYPTO_ALGORITHM_MIN && \ + (x) <= CRYPTO_ALGORITHM_MAX) /* Algorithm flags */ #define CRYPTO_ALG_FLAG_SUPPORTED 0x01 /* Algorithm is supported */ @@ -182,6 +200,20 @@ caddr_t iv; }; +/* op and flags the same as crypt_op */ +struct crypt_aead { + u_int32_t ses; + u_int16_t op; /* i.e. COP_ENCRYPT */ + u_int16_t flags; + u_int len; + u_int aadlen; + u_int ivlen; + caddr_t src, dst; /* become iov[] inside kernel */ + caddr_t aad; /* additional authenticated data */ + caddr_t tag; /* must fit for chosen TAG length */ + caddr_t iv; +}; + /* * Parameters for looking up a crypto driver/device by * device name or by id. The latter are returned for @@ -239,6 +271,7 @@ #define CIOCGSESSION2 _IOWR('c', 106, struct session2_op) #define CIOCKEY2 _IOWR('c', 107, struct crypt_kop) #define CIOCFINDDEV _IOWR('c', 108, struct crypt_find_op) +#define CIOCCRYPTAEAD _IOWR('c', 109, struct crypt_aead) struct cryptotstat { struct timespec acc; /* total accumulated time */ @@ -269,6 +302,14 @@ }; #ifdef _KERNEL + +#if 0 +#define CRYPTDEB(s) do { printf("%s:%d: %s\n", __FILE__, __LINE__, s); \ + } while (0) +#else +#define CRYPTDEB(s) do { } while (0) +#endif + /* Standard initialization structure beginning */ struct cryptoini { int cri_alg; /* Algorithm to use */ @@ -292,14 +333,15 @@ place, so don't copy. */ #define CRD_F_IV_EXPLICIT 0x04 /* IV explicitly provided */ #define CRD_F_DSA_SHA_NEEDED 0x08 /* Compute SHA-1 of buffer for DSA */ +#define CRD_F_COMP 0x0f /* Set when doing compression */ #define CRD_F_KEY_EXPLICIT 0x10 /* Key explicitly provided */ -#define CRD_F_COMP 0x0f /* Set when doing compression */ struct cryptoini CRD_INI; /* Initialization/context data */ -#define crd_iv CRD_INI.cri_iv -#define crd_key CRD_INI.cri_key -#define crd_alg CRD_INI.cri_alg -#define crd_klen CRD_INI.cri_klen +#define crd_esn CRD_INI.cri_esn +#define crd_iv CRD_INI.cri_iv +#define crd_key CRD_INI.cri_key +#define crd_alg CRD_INI.cri_alg +#define crd_klen CRD_INI.cri_klen struct cryptodesc *crd_next; }; @@ -324,9 +366,8 @@ */ int crp_flags; -#define CRYPTO_F_IMBUF 0x0001 /* Input/output are mbuf chains */ -#define CRYPTO_F_IOV 0x0002 /* Input/output are uio */ -#define CRYPTO_F_REL 0x0004 /* Must return data in same place */ +#define CRYPTO_F_IMBUF 0x0001 /* Input/output are mbuf chains */ +#define CRYPTO_F_IOV 0x0002 /* Input/output are uio */ #define CRYPTO_F_BATCH 0x0008 /* Batch op if possible */ #define CRYPTO_F_CBIMM 0x0010 /* Do callback immediately */ #define CRYPTO_F_DONE 0x0020 /* Operation completed */ @@ -341,12 +382,12 @@ struct bintime crp_tstamp; /* performance time stamp */ }; -#define CRYPTO_BUF_CONTIG 0x0 -#define CRYPTO_BUF_IOV 0x1 -#define CRYPTO_BUF_MBUF 0x2 +#define CRYPTO_BUF_CONTIG 0x0 +#define CRYPTO_BUF_IOV 0x1 +#define CRYPTO_BUF_MBUF 0x2 -#define CRYPTO_OP_DECRYPT 0x0 -#define CRYPTO_OP_ENCRYPT 0x1 +#define CRYPTO_OP_DECRYPT 0x0 +#define CRYPTO_OP_ENCRYPT 0x1 /* * Hints passed to process methods. @@ -381,9 +422,9 @@ extern int crypto_newsession(u_int64_t *sid, struct cryptoini *cri, int hard); extern int crypto_freesession(u_int64_t sid); -#define CRYPTOCAP_F_HARDWARE CRYPTO_FLAG_HARDWARE -#define CRYPTOCAP_F_SOFTWARE CRYPTO_FLAG_SOFTWARE -#define CRYPTOCAP_F_SYNC 0x04000000 /* operates synchronously */ +#define CRYPTOCAP_F_HARDWARE CRYPTO_FLAG_HARDWARE +#define CRYPTOCAP_F_SOFTWARE CRYPTO_FLAG_SOFTWARE +#define CRYPTOCAP_F_SYNC 0x04000000 /* operates synchronously */ extern int32_t crypto_get_driverid(device_t dev, int flags); extern int crypto_find_driver(const char *); extern device_t crypto_find_device_byhid(int hid); @@ -418,10 +459,15 @@ struct uio; extern void cuio_copydata(struct uio* uio, int off, int len, caddr_t cp); extern void cuio_copyback(struct uio* uio, int off, int len, caddr_t cp); -extern struct iovec *cuio_getptr(struct uio *uio, int loc, int *off); +extern int cuio_getptr(struct uio *uio, int loc, int *off); extern int cuio_apply(struct uio *uio, int off, int len, int (*f)(void *, void *, u_int), void *arg); +struct mbuf; +struct iovec; +extern void crypto_mbuftoiov(struct mbuf *mbuf, struct iovec **iovptr, + int *cnt, int *allocated); + extern void crypto_copyback(int flags, caddr_t buf, int off, int size, caddr_t in); extern void crypto_copydata(int flags, caddr_t buf, int off, int size, --- //depot/vendor/freebsd/src/sys/opencrypto/cryptosoft.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/cryptosoft.c 2014-09-02 16:11:00.000000000 -0700 @@ -9,6 +9,12 @@ * supported the development of this code. * * Copyright (c) 2000, 2001 Angelos D. Keromytis + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in @@ -37,6 +43,8 @@ #include #include #include +#include +#include #include #include @@ -64,6 +72,7 @@ static int swcr_encdec(struct cryptodesc *, struct swcr_data *, caddr_t, int); static int swcr_authcompute(struct cryptodesc *, struct swcr_data *, caddr_t, int); +static int swcr_authenc(struct cryptop *crp); static int swcr_compdec(struct cryptodesc *, struct swcr_data *, caddr_t, int); static int swcr_freesession(device_t dev, u_int64_t tid); static int swcr_freesession_locked(device_t dev, u_int64_t tid); @@ -76,36 +85,48 @@ int flags) { unsigned char iv[EALG_MAX_BLOCK_LEN], blk[EALG_MAX_BLOCK_LEN], *idat; - unsigned char *ivp, piv[EALG_MAX_BLOCK_LEN]; + unsigned char *ivp, *nivp, iv2[EALG_MAX_BLOCK_LEN]; struct enc_xform *exf; - int i, k, j, blks; + int i, j, k, blks, ind, count, ivlen; + struct uio *uio, uiolcl; + struct iovec iovlcl[4]; + struct iovec *iov; + int iovcnt, iovalloc; + int error; + + error = 0; exf = sw->sw_exf; blks = exf->blocksize; + ivlen = exf->ivsize; /* Check for non-padded data */ if (crd->crd_len % blks) return EINVAL; + if (crd->crd_alg == CRYPTO_AES_ICM && + (crd->crd_flags & CRD_F_IV_EXPLICIT) == 0) + return (EINVAL); + /* Initialize the IV */ if (crd->crd_flags & CRD_F_ENCRYPT) { /* IV explicitly provided ? */ if (crd->crd_flags & CRD_F_IV_EXPLICIT) - bcopy(crd->crd_iv, iv, blks); + bcopy(crd->crd_iv, iv, ivlen); else - arc4rand(iv, blks, 0); + arc4rand(iv, ivlen, 0); /* Do we need to write the IV */ if (!(crd->crd_flags & CRD_F_IV_PRESENT)) - crypto_copyback(flags, buf, crd->crd_inject, blks, iv); + crypto_copyback(flags, buf, crd->crd_inject, ivlen, iv); } else { /* Decryption */ - /* IV explicitly provided ? */ + /* IV explicitly provided ? */ if (crd->crd_flags & CRD_F_IV_EXPLICIT) - bcopy(crd->crd_iv, iv, blks); + bcopy(crd->crd_iv, iv, ivlen); else { /* Get IV off buf */ - crypto_copydata(flags, buf, crd->crd_inject, blks, iv); + crypto_copydata(flags, buf, crd->crd_inject, ivlen, iv); } } @@ -114,341 +135,184 @@ if (sw->sw_kschedule) exf->zerokey(&(sw->sw_kschedule)); + error = exf->setkey(&sw->sw_kschedule, crd->crd_key, crd->crd_klen / 8); if (error) return (error); } + iov = iovlcl; + iovcnt = nitems(iovlcl); + iovalloc = 0; + uio = &uiolcl; + if ((flags & CRYPTO_F_IMBUF) != 0) { + crypto_mbuftoiov((struct mbuf *)buf, &iov, &iovcnt, + &iovalloc); + uio->uio_iov = iov; + uio->uio_iovcnt = iovcnt; + } else if ((flags & CRYPTO_F_IOV) != 0) + uio = (struct uio *)buf; + else { + iov[0].iov_base = buf; + iov[0].iov_len = crd->crd_skip + crd->crd_len; + uio->uio_iov = iov; + uio->uio_iovcnt = 1; + } + ivp = iv; - /* - * xforms that provide a reinit method perform all IV - * handling themselves. - */ - if (exf->reinit) + if (exf->reinit) { + /* + * xforms that provide a reinit method perform all IV + * handling themselves. + */ exf->reinit(sw->sw_kschedule, iv); + } - if (flags & CRYPTO_F_IMBUF) { - struct mbuf *m = (struct mbuf *) buf; + count = crd->crd_skip; + ind = cuio_getptr(uio, count, &k); + if (ind == -1) { + error = EINVAL; + goto out; + } - /* Find beginning of data */ - m = m_getptr(m, crd->crd_skip, &k); - if (m == NULL) - return EINVAL; + i = crd->crd_len; - i = crd->crd_len; + while (i > 0) { + /* + * If there's insufficient data at the end of + * an iovec, we have to do some copying. + */ + if (uio->uio_iov[ind].iov_len < k + blks && + uio->uio_iov[ind].iov_len != k) { + cuio_copydata(uio, count, blks, blk); - while (i > 0) { - /* - * If there's insufficient data at the end of - * an mbuf, we have to do some copying. - */ - if (m->m_len < k + blks && m->m_len != k) { - m_copydata(m, k, blks, blk); - - /* Actual encryption/decryption */ - if (exf->reinit) { - if (crd->crd_flags & CRD_F_ENCRYPT) { - exf->encrypt(sw->sw_kschedule, - blk); - } else { - exf->decrypt(sw->sw_kschedule, - blk); - } - } else if (crd->crd_flags & CRD_F_ENCRYPT) { - /* XOR with previous block */ - for (j = 0; j < blks; j++) - blk[j] ^= ivp[j]; - - exf->encrypt(sw->sw_kschedule, blk); - - /* - * Keep encrypted block for XOR'ing - * with next block - */ - bcopy(blk, iv, blks); - ivp = iv; - } else { /* decrypt */ - /* - * Keep encrypted block for XOR'ing - * with next block - */ - if (ivp == iv) - bcopy(blk, piv, blks); - else - bcopy(blk, iv, blks); - - exf->decrypt(sw->sw_kschedule, blk); - - /* XOR with previous block */ - for (j = 0; j < blks; j++) - blk[j] ^= ivp[j]; - - if (ivp == iv) - bcopy(piv, iv, blks); - else - ivp = iv; + /* Actual encryption/decryption */ + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + blk); + } else { + exf->decrypt(sw->sw_kschedule, + blk); } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { + /* XOR with previous block */ + for (j = 0; j < blks; j++) + blk[j] ^= ivp[j]; - /* Copy back decrypted block */ - m_copyback(m, k, blks, blk); + exf->encrypt(sw->sw_kschedule, blk); - /* Advance pointer */ - m = m_getptr(m, k + blks, &k); - if (m == NULL) - return EINVAL; + /* + * Keep encrypted block for XOR'ing + * with next block + */ + bcopy(blk, iv, blks); + ivp = iv; + } else { /* decrypt */ + /* + * Keep encrypted block for XOR'ing + * with next block + */ + nivp = (ivp == iv) ? iv2 : iv; + bcopy(blk, nivp, blks); - i -= blks; + exf->decrypt(sw->sw_kschedule, blk); - /* Could be done... */ - if (i == 0) - break; - } + /* XOR with previous block */ + for (j = 0; j < blks; j++) + blk[j] ^= ivp[j]; - /* Skip possibly empty mbufs */ - if (k == m->m_len) { - for (m = m->m_next; m && m->m_len == 0; - m = m->m_next) - ; - k = 0; + ivp = nivp; } - /* Sanity check */ - if (m == NULL) - return EINVAL; + /* Copy back decrypted block */ + cuio_copyback(uio, count, blks, blk); - /* - * Warning: idat may point to garbage here, but - * we only use it in the while() loop, only if - * there are indeed enough data. - */ - idat = mtod(m, unsigned char *) + k; + count += blks; - while (m->m_len >= k + blks && i > 0) { - if (exf->reinit) { - if (crd->crd_flags & CRD_F_ENCRYPT) { - exf->encrypt(sw->sw_kschedule, - idat); - } else { - exf->decrypt(sw->sw_kschedule, - idat); - } - } else if (crd->crd_flags & CRD_F_ENCRYPT) { - /* XOR with previous block/IV */ - for (j = 0; j < blks; j++) - idat[j] ^= ivp[j]; + /* Advance pointer */ + ind = cuio_getptr(uio, count, &k); + if (ind == -1) { + error = EINVAL; + goto out; + } - exf->encrypt(sw->sw_kschedule, idat); - ivp = idat; - } else { /* decrypt */ - /* - * Keep encrypted block to be used - * in next block's processing. - */ - if (ivp == iv) - bcopy(idat, piv, blks); - else - bcopy(idat, iv, blks); + i -= blks; - exf->decrypt(sw->sw_kschedule, idat); - - /* XOR with previous block/IV */ - for (j = 0; j < blks; j++) - idat[j] ^= ivp[j]; - - if (ivp == iv) - bcopy(piv, iv, blks); - else - ivp = iv; - } - - idat += blks; - k += blks; - i -= blks; - } + /* Could be done... */ + if (i == 0) + break; } - return 0; /* Done with mbuf encryption/decryption */ - } else if (flags & CRYPTO_F_IOV) { - struct uio *uio = (struct uio *) buf; - struct iovec *iov; + /* + * Warning: idat may point to garbage here, but + * we only use it in the while() loop, only if + * there are indeed enough data. + */ + idat = (char *)uio->uio_iov[ind].iov_base + k; - /* Find beginning of data */ - iov = cuio_getptr(uio, crd->crd_skip, &k); - if (iov == NULL) - return EINVAL; - - i = crd->crd_len; - - while (i > 0) { - /* - * If there's insufficient data at the end of - * an iovec, we have to do some copying. - */ - if (iov->iov_len < k + blks && iov->iov_len != k) { - cuio_copydata(uio, k, blks, blk); - - /* Actual encryption/decryption */ - if (exf->reinit) { - if (crd->crd_flags & CRD_F_ENCRYPT) { - exf->encrypt(sw->sw_kschedule, - blk); - } else { - exf->decrypt(sw->sw_kschedule, - blk); - } - } else if (crd->crd_flags & CRD_F_ENCRYPT) { - /* XOR with previous block */ - for (j = 0; j < blks; j++) - blk[j] ^= ivp[j]; - - exf->encrypt(sw->sw_kschedule, blk); - - /* - * Keep encrypted block for XOR'ing - * with next block - */ - bcopy(blk, iv, blks); - ivp = iv; - } else { /* decrypt */ - /* - * Keep encrypted block for XOR'ing - * with next block - */ - if (ivp == iv) - bcopy(blk, piv, blks); - else - bcopy(blk, iv, blks); - - exf->decrypt(sw->sw_kschedule, blk); - - /* XOR with previous block */ - for (j = 0; j < blks; j++) - blk[j] ^= ivp[j]; - - if (ivp == iv) - bcopy(piv, iv, blks); - else - ivp = iv; + while (uio->uio_iov[ind].iov_len >= k + blks && i > 0) { + if (exf->reinit) { + if (crd->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(sw->sw_kschedule, + idat); + } else { + exf->decrypt(sw->sw_kschedule, + idat); } + } else if (crd->crd_flags & CRD_F_ENCRYPT) { + /* XOR with previous block/IV */ + for (j = 0; j < blks; j++) + idat[j] ^= ivp[j]; - /* Copy back decrypted block */ - cuio_copyback(uio, k, blks, blk); + exf->encrypt(sw->sw_kschedule, idat); + ivp = idat; + } else { /* decrypt */ + /* + * Keep encrypted block to be used + * in next block's processing. + */ + nivp = (ivp == iv) ? iv2 : iv; + bcopy(idat, nivp, blks); - /* Advance pointer */ - iov = cuio_getptr(uio, k + blks, &k); - if (iov == NULL) - return EINVAL; + exf->decrypt(sw->sw_kschedule, idat); - i -= blks; + /* XOR with previous block/IV */ + for (j = 0; j < blks; j++) + idat[j] ^= ivp[j]; - /* Could be done... */ - if (i == 0) - break; + ivp = nivp; } - /* - * Warning: idat may point to garbage here, but - * we only use it in the while() loop, only if - * there are indeed enough data. - */ - idat = (char *)iov->iov_base + k; - - while (iov->iov_len >= k + blks && i > 0) { - if (exf->reinit) { - if (crd->crd_flags & CRD_F_ENCRYPT) { - exf->encrypt(sw->sw_kschedule, - idat); - } else { - exf->decrypt(sw->sw_kschedule, - idat); - } - } else if (crd->crd_flags & CRD_F_ENCRYPT) { - /* XOR with previous block/IV */ - for (j = 0; j < blks; j++) - idat[j] ^= ivp[j]; - - exf->encrypt(sw->sw_kschedule, idat); - ivp = idat; - } else { /* decrypt */ - /* - * Keep encrypted block to be used - * in next block's processing. - */ - if (ivp == iv) - bcopy(idat, piv, blks); - else - bcopy(idat, iv, blks); - - exf->decrypt(sw->sw_kschedule, idat); - - /* XOR with previous block/IV */ - for (j = 0; j < blks; j++) - idat[j] ^= ivp[j]; - - if (ivp == iv) - bcopy(piv, iv, blks); - else - ivp = iv; - } - - idat += blks; - k += blks; - i -= blks; - } - if (k == iov->iov_len) { - iov++; - k = 0; - } + idat += blks; + count += blks; + k += blks; + i -= blks; } - return 0; /* Done with iovec encryption/decryption */ - } else { /* contiguous buffer */ - if (exf->reinit) { - for (i = crd->crd_skip; - i < crd->crd_skip + crd->crd_len; i += blks) { - if (crd->crd_flags & CRD_F_ENCRYPT) - exf->encrypt(sw->sw_kschedule, buf + i); - else - exf->decrypt(sw->sw_kschedule, buf + i); - } - } else if (crd->crd_flags & CRD_F_ENCRYPT) { - for (i = crd->crd_skip; - i < crd->crd_skip + crd->crd_len; i += blks) { - /* XOR with the IV/previous block, as appropriate. */ - if (i == crd->crd_skip) - for (k = 0; k < blks; k++) - buf[i + k] ^= ivp[k]; - else - for (k = 0; k < blks; k++) - buf[i + k] ^= buf[i + k - blks]; - exf->encrypt(sw->sw_kschedule, buf + i); - } - } else { /* Decrypt */ - /* - * Start at the end, so we don't need to keep the encrypted - * block as the IV for the next block. - */ - for (i = crd->crd_skip + crd->crd_len - blks; - i >= crd->crd_skip; i -= blks) { - exf->decrypt(sw->sw_kschedule, buf + i); - - /* XOR with the IV/previous block, as appropriate */ - if (i == crd->crd_skip) - for (k = 0; k < blks; k++) - buf[i + k] ^= ivp[k]; - else - for (k = 0; k < blks; k++) - buf[i + k] ^= buf[i + k - blks]; + /* + * Advance to the next iov if the end of the current iov + * is aligned with the end of a cipher block. + * Note that the code is equivalent to calling: + * ind = cuio_getptr(uio, count, &k); + */ + if (i > 0 && k == uio->uio_iov[ind].iov_len) { + k = 0; + ind++; + if (ind >= uio->uio_iovcnt) { + error = EINVAL; + goto out; } } + } - return 0; /* Done with contiguous buffer encryption/decryption */ - } +out: + if (iovalloc) + free(iov, M_CRYPTO_DATA); - /* Unreachable */ - return EINVAL; + return (error); } static void @@ -583,6 +447,181 @@ return 0; } +CTASSERT(INT_MAX <= (1ll<<39) - 256); /* GCM: plain text < 2^39-256 */ +CTASSERT(INT_MAX <= (uint64_t)-1); /* GCM: associated data <= 2^64-1 */ + +/* + * Apply a combined encryption-authentication transformation + */ +static int +swcr_authenc(struct cryptop *crp) +{ + uint32_t blkbuf[howmany(EALG_MAX_BLOCK_LEN, sizeof(uint32_t))]; + u_char *blk = (u_char *)blkbuf; + u_char aalg[AALG_MAX_RESULT_LEN]; + u_char uaalg[AALG_MAX_RESULT_LEN]; + u_char iv[EALG_MAX_BLOCK_LEN]; + union authctx ctx; + struct cryptodesc *crd, *crda = NULL, *crde = NULL; + struct swcr_data *sw, *swa, *swe = NULL; + struct auth_hash *axf = NULL; + struct enc_xform *exf = NULL; + caddr_t buf = (caddr_t)crp->crp_buf; + uint32_t *blkp; + int aadlen, blksz, i, ivlen, len, iskip, oskip, r; + + ivlen = blksz = iskip = oskip = 0; + + for (crd = crp->crp_desc; crd; crd = crd->crd_next) { + for (sw = swcr_sessions[crp->crp_sid & 0xffffffff]; + sw && sw->sw_alg != crd->crd_alg; + sw = sw->sw_next) + ; + if (sw == NULL) + return (EINVAL); + + switch (sw->sw_alg) { + case CRYPTO_AES_NIST_GCM_16: + case CRYPTO_AES_NIST_GMAC: + swe = sw; + crde = crd; + exf = swe->sw_exf; + ivlen = 12; + break; + case CRYPTO_AES_128_NIST_GMAC: + case CRYPTO_AES_192_NIST_GMAC: + case CRYPTO_AES_256_NIST_GMAC: + swa = sw; + crda = crd; + axf = swa->sw_axf; + if (swa->sw_ictx == 0) + return (EINVAL); + bcopy(swa->sw_ictx, &ctx, axf->ctxsize); + blksz = axf->blocksize; + break; + default: + return (EINVAL); + } + } + if (crde == NULL || crda == NULL) + return (EINVAL); + + if (crde->crd_alg == CRYPTO_AES_NIST_GCM_16 && + (crde->crd_flags & CRD_F_IV_EXPLICIT) == 0) + return (EINVAL); + + if (crde->crd_klen != crda->crd_klen) + return (EINVAL); + + /* Initialize the IV */ + if (crde->crd_flags & CRD_F_ENCRYPT) { + /* IV explicitly provided ? */ + if (crde->crd_flags & CRD_F_IV_EXPLICIT) + bcopy(crde->crd_iv, iv, ivlen); + else + arc4rand(iv, ivlen, 0); + + /* Do we need to write the IV */ + if (!(crde->crd_flags & CRD_F_IV_PRESENT)) + crypto_copyback(crp->crp_flags, buf, crde->crd_inject, + ivlen, iv); + + } else { /* Decryption */ + /* IV explicitly provided ? */ + if (crde->crd_flags & CRD_F_IV_EXPLICIT) + bcopy(crde->crd_iv, iv, ivlen); + else { + /* Get IV off buf */ + crypto_copydata(crp->crp_flags, buf, crde->crd_inject, + ivlen, iv); + } + } + + /* Supply MAC with IV */ + if (axf->Reinit) + axf->Reinit(&ctx, iv, ivlen); + + /* Supply MAC with AAD */ + aadlen = crda->crd_len; + + for (i = iskip; i < crda->crd_len; i += blksz) { + len = MIN(crda->crd_len - i, blksz - oskip); + crypto_copydata(crp->crp_flags, buf, crda->crd_skip + i, len, + blk + oskip); + bzero(blk + len + oskip, blksz - len - oskip); + axf->Update(&ctx, blk, blksz); + oskip = 0; /* reset initial output offset */ + } + + if (exf->reinit) + exf->reinit(swe->sw_kschedule, iv); + + /* Do encryption/decryption with MAC */ + for (i = 0; i < crde->crd_len; i += blksz) { + len = MIN(crde->crd_len - i, blksz); + if (len < blksz) + bzero(blk, blksz); + crypto_copydata(crp->crp_flags, buf, crde->crd_skip + i, len, + blk); + if (crde->crd_flags & CRD_F_ENCRYPT) { + exf->encrypt(swe->sw_kschedule, blk); + axf->Update(&ctx, blk, len); + crypto_copyback(crp->crp_flags, buf, + crde->crd_skip + i, len, blk); + } else { + axf->Update(&ctx, blk, len); + } + } + + /* Do any required special finalization */ + switch (crda->crd_alg) { + case CRYPTO_AES_128_NIST_GMAC: + case CRYPTO_AES_192_NIST_GMAC: + case CRYPTO_AES_256_NIST_GMAC: + /* length block */ + bzero(blk, blksz); + blkp = (uint32_t *)blk + 1; + *blkp = htobe32(aadlen * 8); + blkp = (uint32_t *)blk + 3; + *blkp = htobe32(crde->crd_len * 8); + axf->Update(&ctx, blk, blksz); + break; + } + + /* Finalize MAC */ + axf->Final(aalg, &ctx); + + /* Validate tag */ + if (!(crde->crd_flags & CRD_F_ENCRYPT)) { + crypto_copydata(crp->crp_flags, buf, crda->crd_inject, + axf->hashsize, uaalg); + + r = timingsafe_bcmp(aalg, uaalg, axf->hashsize); + if (r == 0) { + /* tag matches, decrypt data */ + for (i = 0; i < crde->crd_len; i += blksz) { + len = MIN(crde->crd_len - i, blksz); + if (len < blksz) + bzero(blk, blksz); + crypto_copydata(crp->crp_flags, buf, + crde->crd_skip + i, len, blk); + if (!(crde->crd_flags & CRD_F_ENCRYPT)) { + exf->decrypt(swe->sw_kschedule, blk); + } + crypto_copyback(crp->crp_flags, buf, + crde->crd_skip + i, len, blk); + } + } else + return (EBADMSG); + } else { + /* Inject the authentication data */ + crypto_copyback(crp->crp_flags, buf, crda->crd_inject, + axf->hashsize, aalg); + } + + return (0); +} + /* * Apply a compression/decompression algorithm */ @@ -747,6 +786,16 @@ case CRYPTO_AES_XTS: txf = &enc_xform_aes_xts; goto enccommon; + case CRYPTO_AES_ICM: + txf = &enc_xform_aes_icm; + goto enccommon; + case CRYPTO_AES_NIST_GCM_16: + txf = &enc_xform_aes_nist_gcm; + goto enccommon; + case CRYPTO_AES_NIST_GMAC: + txf = &enc_xform_aes_nist_gmac; + (*swd)->sw_exf = txf; + break; case CRYPTO_CAMELLIA_CBC: txf = &enc_xform_camellia; goto enccommon; @@ -865,6 +914,31 @@ (*swd)->sw_axf = axf; break; #endif + + case CRYPTO_AES_128_NIST_GMAC: + axf = &auth_hash_nist_gmac_aes_128; + goto auth4common; + + case CRYPTO_AES_192_NIST_GMAC: + axf = &auth_hash_nist_gmac_aes_192; + goto auth4common; + + case CRYPTO_AES_256_NIST_GMAC: + axf = &auth_hash_nist_gmac_aes_256; + auth4common: + (*swd)->sw_ictx = malloc(axf->ctxsize, M_CRYPTO_DATA, + M_NOWAIT); + if ((*swd)->sw_ictx == NULL) { + swcr_freesession_locked(dev, i); + rw_runlock(&swcr_sessions_lock); + return ENOBUFS; + } + axf->Init((*swd)->sw_ictx); + axf->Setkey((*swd)->sw_ictx, cri->cri_key, + cri->cri_klen / 8); + (*swd)->sw_axf = axf; + break; + case CRYPTO_DEFLATE_COMP: cxf = &comp_algo_deflate; (*swd)->sw_cxf = cxf; @@ -925,6 +999,9 @@ case CRYPTO_SKIPJACK_CBC: case CRYPTO_RIJNDAEL128_CBC: case CRYPTO_AES_XTS: + case CRYPTO_AES_ICM: + case CRYPTO_AES_NIST_GCM_16: + case CRYPTO_AES_NIST_GMAC: case CRYPTO_CAMELLIA_CBC: case CRYPTO_NULL_CBC: txf = swd->sw_exf; @@ -1050,6 +1127,7 @@ case CRYPTO_SKIPJACK_CBC: case CRYPTO_RIJNDAEL128_CBC: case CRYPTO_AES_XTS: + case CRYPTO_AES_ICM: case CRYPTO_CAMELLIA_CBC: if ((crp->crp_etype = swcr_encdec(crd, sw, crp->crp_buf, crp->crp_flags)) != 0) @@ -1074,6 +1152,14 @@ goto done; break; + case CRYPTO_AES_NIST_GCM_16: + case CRYPTO_AES_NIST_GMAC: + case CRYPTO_AES_128_NIST_GMAC: + case CRYPTO_AES_192_NIST_GMAC: + case CRYPTO_AES_256_NIST_GMAC: + crp->crp_etype = swcr_authenc(crp); + goto done; + case CRYPTO_DEFLATE_COMP: if ((crp->crp_etype = swcr_compdec(crd, sw, crp->crp_buf, crp->crp_flags)) != 0) @@ -1144,6 +1230,12 @@ REGISTER(CRYPTO_SHA1); REGISTER(CRYPTO_RIJNDAEL128_CBC); REGISTER(CRYPTO_AES_XTS); + REGISTER(CRYPTO_AES_ICM); + REGISTER(CRYPTO_AES_NIST_GCM_16); + REGISTER(CRYPTO_AES_NIST_GMAC); + REGISTER(CRYPTO_AES_128_NIST_GMAC); + REGISTER(CRYPTO_AES_192_NIST_GMAC); + REGISTER(CRYPTO_AES_256_NIST_GMAC); REGISTER(CRYPTO_CAMELLIA_CBC); REGISTER(CRYPTO_DEFLATE_COMP); #undef REGISTER --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/sys/opencrypto/gfmult.c 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,275 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by John-Mark Gurney under + * the sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#include "gfmult.h" + +#define REV_POLY_REDUCT 0xe1 /* 0x87 bit reversed */ + +/* reverse the bits of a nibble */ +static const uint8_t nib_rev[] = { + 0x0, 0x8, 0x4, 0xc, 0x2, 0xa, 0x6, 0xe, + 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf, +}; + +/* calulate v * 2 */ +static inline struct gf128 +gf128_mulalpha(struct gf128 v) +{ + uint64_t mask; + + mask = !!(v.v[1] & 1); + mask = ~(mask - 1); + v.v[1] = (v.v[1] >> 1) | ((v.v[0] & 1) << 63); + v.v[0] = (v.v[0] >> 1) ^ ((mask & REV_POLY_REDUCT) << 56); + + return v; +} + +/* + * Generate a table for 0-16 * h. Store the results in the table w/ indexes + * bit reversed, and the words striped across the values. + */ +void +gf128_genmultable(struct gf128 h, struct gf128table *t) +{ + struct gf128 tbl[16]; + int i; + + tbl[0] = MAKE_GF128(0, 0); + tbl[1] = h; + + for (i = 2; i < 16; i += 2) { + tbl[i] = gf128_mulalpha(tbl[i / 2]); + tbl[i + 1] = gf128_add(tbl[i], h); + } + + for (i = 0; i < 16; i++) { + t->a[nib_rev[i]] = tbl[i].v[0] >> 32; + t->b[nib_rev[i]] = tbl[i].v[0]; + t->c[nib_rev[i]] = tbl[i].v[1] >> 32; + t->d[nib_rev[i]] = tbl[i].v[1]; + } +} + +/* + * Generate tables containing h, h^2, h^3 and h^4, starting at 0. + */ +void +gf128_genmultable4(struct gf128 h, struct gf128table4 *t) +{ + struct gf128 h2, h3, h4; + + gf128_genmultable(h, &t->tbls[0]); + + h2 = gf128_mul(h, &t->tbls[0]); + + gf128_genmultable(h2, &t->tbls[1]); + + h3 = gf128_mul(h, &t->tbls[1]); + gf128_genmultable(h3, &t->tbls[2]); + + h4 = gf128_mul(h2, &t->tbls[1]); + gf128_genmultable(h4, &t->tbls[3]); +} + +/* + * Read a row from the table. + */ +static inline struct gf128 +readrow(struct gf128table *tbl, unsigned bits) +{ + struct gf128 r; + + bits = bits % 16; + + r.v[0] = ((uint64_t)tbl->a[bits] << 32) | tbl->b[bits]; + r.v[1] = ((uint64_t)tbl->c[bits] << 32) | tbl->d[bits]; + + return r; +} + +/* + * These are the reduction values. Since we are dealing with bit reversed + * version, the values need to be bit reversed, AND the indexes are also + * bit reversed to make lookups quicker. + */ +static uint16_t reduction[] = { + 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0, + 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0, +}; + +/* + * Calculate: + * (x*2^4 + word[3,0]*h) * + * 2^4 + word[7,4]*h) * + * ... + * 2^4 + word[63,60]*h + */ +static struct gf128 +gfmultword(uint64_t word, struct gf128 x, struct gf128table *tbl) +{ + struct gf128 row; + unsigned bits; + unsigned redbits; + int i; + + for (i = 0; i < 64; i += 4) { + bits = word % 16; + + /* fetch row */ + row = readrow(tbl, bits); + + /* x * 2^4 */ + redbits = x.v[1] % 16; + x.v[1] = (x.v[1] >> 4) | (x.v[0] % 16) << 60; + x.v[0] >>= 4; + x.v[0] ^= (uint64_t)reduction[redbits] << (64 - 16); + + word >>= 4; + + x = gf128_add(x, row); + } + + return x; +} + +/* + * Calculate + * (x*2^4 + worda[3,0]*h^4+wordb[3,0]*h^3+...+wordd[3,0]*h) * + * ... + * 2^4 + worda[63,60]*h^4+ ... + wordd[63,60]*h + * + * Passing/returning struct is .5% faster than passing in via pointer on + * amd64. + */ +static struct gf128 +gfmultword4(uint64_t worda, uint64_t wordb, uint64_t wordc, uint64_t wordd, + struct gf128 x, struct gf128table4 *tbl) +{ + struct gf128 rowa, rowb, rowc, rowd; + unsigned bitsa, bitsb, bitsc, bitsd; + unsigned redbits; + int i; + + /* + * XXX - nibble reverse words to save a shift? probably not as + * nibble reverse would take 20 ops (5 * 4) verse 16 + */ + + for (i = 0; i < 64; i += 4) { + bitsa = worda % 16; + bitsb = wordb % 16; + bitsc = wordc % 16; + bitsd = wordd % 16; + + /* fetch row */ + rowa = readrow(&tbl->tbls[3], bitsa); + rowb = readrow(&tbl->tbls[2], bitsb); + rowc = readrow(&tbl->tbls[1], bitsc); + rowd = readrow(&tbl->tbls[0], bitsd); + + /* x * 2^4 */ + redbits = x.v[1] % 16; + x.v[1] = (x.v[1] >> 4) | (x.v[0] % 16) << 60; + x.v[0] >>= 4; + x.v[0] ^= (uint64_t)reduction[redbits] << (64 - 16); + + worda >>= 4; + wordb >>= 4; + wordc >>= 4; + wordd >>= 4; + + x = gf128_add(x, gf128_add(rowa, gf128_add(rowb, + gf128_add(rowc, rowd)))); + } + + return x; +} + +struct gf128 +gf128_mul(struct gf128 v, struct gf128table *tbl) +{ + struct gf128 ret; + + ret = MAKE_GF128(0, 0); + + ret = gfmultword(v.v[1], ret, tbl); + ret = gfmultword(v.v[0], ret, tbl); + + return ret; +} + +/* + * Calculate a*h^4 + b*h^3 + c*h^2 + d*h, or: + * (((a*h+b)*h+c)*h+d)*h + */ +struct gf128 +gf128_mul4(struct gf128 a, struct gf128 b, struct gf128 c, struct gf128 d, + struct gf128table4 *tbl) +{ + struct gf128 tmp; + + tmp = MAKE_GF128(0, 0); + + tmp = gfmultword4(a.v[1], b.v[1], c.v[1], d.v[1], tmp, tbl); + tmp = gfmultword4(a.v[0], b.v[0], c.v[0], d.v[0], tmp, tbl); + + return tmp; +} + +/* + * a = data[0..15] + r + * b = data[16..31] + * c = data[32..47] + * d = data[48..63] + * + * Calculate a*h^4 + b*h^3 + c*h^2 + d*h, or: + * (((a*h+b)*h+c)*h+d)*h + */ +struct gf128 +gf128_mul4b(struct gf128 r, const uint8_t *v, struct gf128table4 *tbl) +{ + struct gf128 a, b, c, d; + struct gf128 tmp; + + tmp = MAKE_GF128(0, 0); + + a = gf128_add(r, gf128_read(&v[0*16])); + b = gf128_read(&v[1*16]); + c = gf128_read(&v[2*16]); + d = gf128_read(&v[3*16]); + + tmp = gfmultword4(a.v[1], b.v[1], c.v[1], d.v[1], tmp, tbl); + tmp = gfmultword4(a.v[0], b.v[0], c.v[0], d.v[0], tmp, tbl); + + return tmp; +} --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/sys/opencrypto/gfmult.h 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,128 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by John-Mark Gurney under + * the sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef _GFMULT_H_ +#define _GFMULT_H_ + +#ifdef __APPLE__ +#define __aligned(x) __attribute__((__aligned__(x))) +#define be64dec(buf) __builtin_bswap64(*(uint64_t *)buf) +#define be64enc(buf, x) (*(uint64_t *)buf = __builtin_bswap64(x)) +#else +#include +#endif + +#ifdef _KERNEL +#include +#else +#include +#include +#endif + +#define REQ_ALIGN (16 * 4) +/* + * The rows are striped across cache lines. Note that the indexes + * are bit reversed to make accesses quicker. + */ +struct gf128table { + uint32_t a[16] __aligned(REQ_ALIGN); /* bits 0 - 31 */ + uint32_t b[16] __aligned(REQ_ALIGN); /* bits 63 - 32 */ + uint32_t c[16] __aligned(REQ_ALIGN); /* bits 95 - 64 */ + uint32_t d[16] __aligned(REQ_ALIGN); /* bits 127 - 96 */ +} __aligned(REQ_ALIGN); + +/* + * A set of tables that contain h, h^2, h^3, h^4. To be used w/ gf128_mul4. + */ +struct gf128table4 { + struct gf128table tbls[4]; +}; + +/* + * GCM per spec is bit reversed in memory. So byte 0 is really bit reversed + * and contains bits 0-7. We can deal w/ this by using right shifts and + * related math instead of having to bit reverse everything. This means that + * the low bits are in v[0] (bits 0-63) and reverse order, while the high + * bits are in v[1] (bits 64-127) and reverse order. The high bit of v[0] is + * bit 0, and the low bit of v[1] is bit 127. + */ +struct gf128 { + uint64_t v[2]; +}; + +/* Note that we don't bit reverse in MAKE_GF128. */ +#define MAKE_GF128(a, b) ((struct gf128){.v = { (a), (b) } }) +#define GF128_EQ(a, b) ((((a).v[0] ^ (b).v[0]) | \ + ((a).v[1] ^ (b).v[1])) == 0) + +static inline struct gf128 +gf128_read(const uint8_t *buf) +{ + struct gf128 r; + + r.v[0] = be64dec(buf); + buf += sizeof(uint64_t); + + r.v[1] = be64dec(buf); + + return r; +} + +static inline void +gf128_write(struct gf128 v, uint8_t *buf) +{ + uint64_t tmp; + + be64enc(buf, v.v[0]); + buf += sizeof tmp; + + be64enc(buf, v.v[1]); +} + +static inline struct gf128 __pure /* XXX - __pure2 instead */ +gf128_add(struct gf128 a, struct gf128 b) +{ + a.v[0] ^= b.v[0]; + a.v[1] ^= b.v[1]; + + return a; +} + +void gf128_genmultable(struct gf128 h, struct gf128table *t); +void gf128_genmultable4(struct gf128 h, struct gf128table4 *t); +struct gf128 gf128_mul(struct gf128 v, struct gf128table *tbl); +struct gf128 gf128_mul4(struct gf128 a, struct gf128 b, struct gf128 c, + struct gf128 d, struct gf128table4 *tbl); +struct gf128 gf128_mul4b(struct gf128 r, const uint8_t *v, + struct gf128table4 *tbl); + +#endif /* _GFMULT_H_ */ --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/sys/opencrypto/gmac.c 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,119 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by John-Mark Gurney under + * the sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#include +#include +#include +#include + +void +AES_GMAC_Init(struct aes_gmac_ctx *agc) +{ + + bzero(agc, sizeof *agc); +} + +void +AES_GMAC_Setkey(struct aes_gmac_ctx *agc, const uint8_t *key, uint16_t klen) +{ + const uint8_t zeros[GMAC_BLOCK_LEN] = {}; + struct gf128 h; + uint8_t hbuf[GMAC_BLOCK_LEN]; + + agc->rounds = rijndaelKeySetupEnc(agc->keysched, key, klen * 8); + + rijndaelEncrypt(agc->keysched, agc->rounds, zeros, hbuf); + + h = gf128_read(hbuf); + gf128_genmultable4(h, &agc->ghashtbl); + + explicit_bzero(&h, sizeof h); + explicit_bzero(hbuf, sizeof hbuf); +} + +void +AES_GMAC_Reinit(struct aes_gmac_ctx *agc, const uint8_t *iv, uint16_t ivlen) +{ + + KASSERT(ivlen <= sizeof agc->counter, ("passed ivlen too large!")); + bcopy(iv, agc->counter, ivlen); +} + +int +AES_GMAC_Update(struct aes_gmac_ctx *agc, const uint8_t *data, uint16_t len) +{ + struct gf128 v; + uint8_t buf[GMAC_BLOCK_LEN] = {}; + int i; + + v = agc->hash; + + while (len > 0) { + if (len >= 4*GMAC_BLOCK_LEN) { + i = 4*GMAC_BLOCK_LEN; + v = gf128_mul4b(v, data, &agc->ghashtbl); + } else if (len >= GMAC_BLOCK_LEN) { + i = GMAC_BLOCK_LEN; + v = gf128_add(v, gf128_read(data)); + v = gf128_mul(v, &agc->ghashtbl.tbls[0]); + } else { + i = len; + bcopy(data, buf, i); + v = gf128_add(v, gf128_read(&buf[0])); + v = gf128_mul(v, &agc->ghashtbl.tbls[0]); + explicit_bzero(buf, sizeof buf); + } + len -= i; + data += i; + } + + agc->hash = v; + explicit_bzero(&v, sizeof v); + + return (0); +} + +void +AES_GMAC_Final(uint8_t digest[GMAC_DIGEST_LEN], struct aes_gmac_ctx *agc) +{ + uint8_t enccntr[GMAC_BLOCK_LEN]; + struct gf128 a; + + /* XXX - zero additional bytes? */ + agc->counter[GMAC_BLOCK_LEN - 1] = 1; + + rijndaelEncrypt(agc->keysched, agc->rounds, agc->counter, enccntr); + a = gf128_add(agc->hash, gf128_read(enccntr)); + gf128_write(a, digest); + + explicit_bzero(enccntr, sizeof enccntr); +} --- /dev/null 2014-11-15 22:00:00.000000000 -0800 +++ //depot/projects/opencrypto/sys/opencrypto/gmac.h 2014-10-31 23:14:22.988119000 -0700 @@ -0,0 +1,55 @@ +/*- + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by John-Mark Gurney under + * the sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ + +#ifndef _GMAC_H_ + +#include "gfmult.h" +#include + +#define GMAC_BLOCK_LEN 16 +#define GMAC_DIGEST_LEN 16 + +struct aes_gmac_ctx { + struct gf128table4 ghashtbl; + struct gf128 hash; + uint32_t keysched[4*(RIJNDAEL_MAXNR + 1)]; + uint8_t counter[GMAC_BLOCK_LEN]; + int rounds; +}; + +void AES_GMAC_Init(struct aes_gmac_ctx *); +void AES_GMAC_Setkey(struct aes_gmac_ctx *, const uint8_t *, uint16_t); +void AES_GMAC_Reinit(struct aes_gmac_ctx *, const uint8_t *, uint16_t); +int AES_GMAC_Update(struct aes_gmac_ctx *, const uint8_t *, uint16_t); +void AES_GMAC_Final(uint8_t [GMAC_DIGEST_LEN], struct aes_gmac_ctx *); + +#endif /* _GMAC_H_ */ --- //depot/vendor/freebsd/src/sys/opencrypto/xform.c.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/xform.c 2014-09-02 16:11:00.000000000 -0700 @@ -24,7 +24,13 @@ * Copyright (C) 2001, Angelos D. Keromytis. * * Copyright (C) 2008, Damien Miller + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). + * * Permission to use, copy, and modify this software with or without fee * is hereby granted, provided that this entire notice is included in * all copies of any software which is or includes a copy or @@ -76,6 +82,7 @@ static int cast5_setkey(u_int8_t **, u_int8_t *, int); static int skipjack_setkey(u_int8_t **, u_int8_t *, int); static int rijndael128_setkey(u_int8_t **, u_int8_t *, int); +static int aes_icm_setkey(u_int8_t **, u_int8_t *, int); static int aes_xts_setkey(u_int8_t **, u_int8_t *, int); static int cml_setkey(u_int8_t **, u_int8_t *, int); @@ -99,6 +106,8 @@ static void aes_xts_decrypt(caddr_t, u_int8_t *); static void cml_decrypt(caddr_t, u_int8_t *); +static void aes_icm_crypt(caddr_t, u_int8_t *); + static void null_zerokey(u_int8_t **); static void des1_zerokey(u_int8_t **); static void des3_zerokey(u_int8_t **); @@ -106,103 +115,145 @@ static void cast5_zerokey(u_int8_t **); static void skipjack_zerokey(u_int8_t **); static void rijndael128_zerokey(u_int8_t **); +static void aes_icm_zerokey(u_int8_t **); static void aes_xts_zerokey(u_int8_t **); static void cml_zerokey(u_int8_t **); +static void aes_icm_reinit(caddr_t, u_int8_t *); static void aes_xts_reinit(caddr_t, u_int8_t *); +static void aes_gcm_reinit(caddr_t, u_int8_t *); static void null_init(void *); -static int null_update(void *, u_int8_t *, u_int16_t); +static void null_reinit(void *ctx, const u_int8_t *buf, u_int16_t len); +static int null_update(void *, const u_int8_t *, u_int16_t); static void null_final(u_int8_t *, void *); -static int MD5Update_int(void *, u_int8_t *, u_int16_t); +static int MD5Update_int(void *, const u_int8_t *, u_int16_t); static void SHA1Init_int(void *); -static int SHA1Update_int(void *, u_int8_t *, u_int16_t); +static int SHA1Update_int(void *, const u_int8_t *, u_int16_t); static void SHA1Final_int(u_int8_t *, void *); -static int RMD160Update_int(void *, u_int8_t *, u_int16_t); -static int SHA256Update_int(void *, u_int8_t *, u_int16_t); -static int SHA384Update_int(void *, u_int8_t *, u_int16_t); -static int SHA512Update_int(void *, u_int8_t *, u_int16_t); +static int RMD160Update_int(void *, const u_int8_t *, u_int16_t); +static int SHA256Update_int(void *, const u_int8_t *, u_int16_t); +static int SHA384Update_int(void *, const u_int8_t *, u_int16_t); +static int SHA512Update_int(void *, const u_int8_t *, u_int16_t); static u_int32_t deflate_compress(u_int8_t *, u_int32_t, u_int8_t **); static u_int32_t deflate_decompress(u_int8_t *, u_int32_t, u_int8_t **); +#define AESICM_BLOCKSIZE 16 + +struct aes_icm_ctx { + u_int32_t ac_ek[4*(RIJNDAEL_MAXNR + 1)]; + /* ac_block is initalized to IV */ + u_int8_t ac_block[AESICM_BLOCKSIZE]; + int ac_nr; +}; + MALLOC_DEFINE(M_XDATA, "xform", "xform data buffers"); /* Encryption instances */ struct enc_xform enc_xform_null = { CRYPTO_NULL_CBC, "NULL", /* NB: blocksize of 4 is to generate a properly aligned ESP header */ - NULL_BLOCK_LEN, 0, 256, /* 2048 bits, max key */ + NULL_BLOCK_LEN, NULL_BLOCK_LEN, 0, 256, /* 2048 bits, max key */ null_encrypt, null_decrypt, null_setkey, null_zerokey, - NULL + NULL, }; struct enc_xform enc_xform_des = { CRYPTO_DES_CBC, "DES", - DES_BLOCK_LEN, 8, 8, + DES_BLOCK_LEN, DES_BLOCK_LEN, 8, 8, des1_encrypt, des1_decrypt, des1_setkey, des1_zerokey, - NULL + NULL, }; struct enc_xform enc_xform_3des = { CRYPTO_3DES_CBC, "3DES", - DES3_BLOCK_LEN, 24, 24, + DES3_BLOCK_LEN, DES3_BLOCK_LEN, 24, 24, des3_encrypt, des3_decrypt, des3_setkey, des3_zerokey, - NULL + NULL, }; struct enc_xform enc_xform_blf = { CRYPTO_BLF_CBC, "Blowfish", - BLOWFISH_BLOCK_LEN, 5, 56 /* 448 bits, max key */, + BLOWFISH_BLOCK_LEN, BLOWFISH_BLOCK_LEN, 5, 56 /* 448 bits, max key */, blf_encrypt, blf_decrypt, blf_setkey, blf_zerokey, - NULL + NULL, }; struct enc_xform enc_xform_cast5 = { CRYPTO_CAST_CBC, "CAST-128", - CAST128_BLOCK_LEN, 5, 16, + CAST128_BLOCK_LEN, CAST128_BLOCK_LEN, 5, 16, cast5_encrypt, cast5_decrypt, cast5_setkey, cast5_zerokey, - NULL + NULL, }; struct enc_xform enc_xform_skipjack = { CRYPTO_SKIPJACK_CBC, "Skipjack", - SKIPJACK_BLOCK_LEN, 10, 10, + SKIPJACK_BLOCK_LEN, SKIPJACK_BLOCK_LEN, 10, 10, skipjack_encrypt, - skipjack_decrypt, - skipjack_setkey, + skipjack_decrypt, skipjack_setkey, skipjack_zerokey, - NULL + NULL, }; struct enc_xform enc_xform_rijndael128 = { CRYPTO_RIJNDAEL128_CBC, "Rijndael-128/AES", - RIJNDAEL128_BLOCK_LEN, 8, 32, + RIJNDAEL128_BLOCK_LEN, RIJNDAEL128_BLOCK_LEN, 16, 32, rijndael128_encrypt, rijndael128_decrypt, rijndael128_setkey, rijndael128_zerokey, - NULL + NULL, +}; + +struct enc_xform enc_xform_aes_icm = { + CRYPTO_AES_ICM, "AES-ICM", + RIJNDAEL128_BLOCK_LEN, RIJNDAEL128_BLOCK_LEN, 16, 32, + aes_icm_crypt, + aes_icm_crypt, + aes_icm_setkey, + rijndael128_zerokey, + aes_icm_reinit, +}; + +struct enc_xform enc_xform_aes_nist_gcm = { + CRYPTO_AES_NIST_GCM_16, "AES-GCM", + 1, 12, 16, 32, + aes_icm_crypt, + aes_icm_crypt, + aes_icm_setkey, + aes_icm_zerokey, + aes_gcm_reinit, +}; + +struct enc_xform enc_xform_aes_nist_gmac = { + CRYPTO_AES_NIST_GMAC, "AES-GMAC", + 1, 12, 16, 32, + NULL, + NULL, + NULL, + NULL, + NULL, }; struct enc_xform enc_xform_aes_xts = { CRYPTO_AES_XTS, "AES-XTS", - RIJNDAEL128_BLOCK_LEN, 32, 64, + RIJNDAEL128_BLOCK_LEN, 8, 32, 64, aes_xts_encrypt, aes_xts_decrypt, aes_xts_setkey, @@ -212,85 +263,115 @@ struct enc_xform enc_xform_arc4 = { CRYPTO_ARC4, "ARC4", - 1, 1, 32, + 1, 1, 1, 32, + NULL, NULL, NULL, NULL, NULL, - NULL }; struct enc_xform enc_xform_camellia = { CRYPTO_CAMELLIA_CBC, "Camellia", - CAMELLIA_BLOCK_LEN, 8, 32, + CAMELLIA_BLOCK_LEN, CAMELLIA_BLOCK_LEN, 8, 32, cml_encrypt, cml_decrypt, cml_setkey, cml_zerokey, - NULL + NULL, }; /* Authentication instances */ -struct auth_hash auth_hash_null = { +struct auth_hash auth_hash_null = { /* NB: context isn't used */ CRYPTO_NULL_HMAC, "NULL-HMAC", - 0, NULL_HASH_LEN, NULL_HMAC_BLOCK_LEN, sizeof(int), /* NB: context isn't used */ - null_init, null_update, null_final + 0, NULL_HASH_LEN, sizeof(int), NULL_HMAC_BLOCK_LEN, + null_init, null_reinit, null_reinit, null_update, null_final }; struct auth_hash auth_hash_hmac_md5 = { CRYPTO_MD5_HMAC, "HMAC-MD5", - 16, MD5_HASH_LEN, MD5_HMAC_BLOCK_LEN, sizeof(MD5_CTX), - (void (*) (void *)) MD5Init, MD5Update_int, + 16, MD5_HASH_LEN, sizeof(MD5_CTX), MD5_HMAC_BLOCK_LEN, + (void (*) (void *)) MD5Init, NULL, NULL, MD5Update_int, (void (*) (u_int8_t *, void *)) MD5Final }; struct auth_hash auth_hash_hmac_sha1 = { CRYPTO_SHA1_HMAC, "HMAC-SHA1", - 20, SHA1_HASH_LEN, SHA1_HMAC_BLOCK_LEN, sizeof(SHA1_CTX), - SHA1Init_int, SHA1Update_int, SHA1Final_int + 20, SHA1_HASH_LEN, sizeof(SHA1_CTX), SHA1_HMAC_BLOCK_LEN, + SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int }; struct auth_hash auth_hash_hmac_ripemd_160 = { CRYPTO_RIPEMD160_HMAC, "HMAC-RIPEMD-160", - 20, RIPEMD160_HASH_LEN, RIPEMD160_HMAC_BLOCK_LEN, sizeof(RMD160_CTX), - (void (*)(void *)) RMD160Init, RMD160Update_int, + 20, RIPEMD160_HASH_LEN, sizeof(RMD160_CTX), RIPEMD160_HMAC_BLOCK_LEN, + (void (*)(void *)) RMD160Init, NULL, NULL, RMD160Update_int, (void (*)(u_int8_t *, void *)) RMD160Final }; struct auth_hash auth_hash_key_md5 = { CRYPTO_MD5_KPDK, "Keyed MD5", - 0, MD5_KPDK_HASH_LEN, 0, sizeof(MD5_CTX), - (void (*)(void *)) MD5Init, MD5Update_int, + 0, MD5_KPDK_HASH_LEN, sizeof(MD5_CTX), 0, + (void (*)(void *)) MD5Init, NULL, NULL, MD5Update_int, (void (*)(u_int8_t *, void *)) MD5Final }; struct auth_hash auth_hash_key_sha1 = { CRYPTO_SHA1_KPDK, "Keyed SHA1", - 0, SHA1_KPDK_HASH_LEN, 0, sizeof(SHA1_CTX), - SHA1Init_int, SHA1Update_int, SHA1Final_int + 0, SHA1_KPDK_HASH_LEN, sizeof(SHA1_CTX), 0, + SHA1Init_int, NULL, NULL, SHA1Update_int, SHA1Final_int }; struct auth_hash auth_hash_hmac_sha2_256 = { CRYPTO_SHA2_256_HMAC, "HMAC-SHA2-256", - 32, SHA2_256_HASH_LEN, SHA2_256_HMAC_BLOCK_LEN, sizeof(SHA256_CTX), - (void (*)(void *)) SHA256_Init, SHA256Update_int, + 32, SHA2_256_HASH_LEN, sizeof(SHA256_CTX), SHA2_256_HMAC_BLOCK_LEN, + (void (*)(void *)) SHA256_Init, NULL, NULL, SHA256Update_int, (void (*)(u_int8_t *, void *)) SHA256_Final }; struct auth_hash auth_hash_hmac_sha2_384 = { CRYPTO_SHA2_384_HMAC, "HMAC-SHA2-384", - 48, SHA2_384_HASH_LEN, SHA2_384_HMAC_BLOCK_LEN, sizeof(SHA384_CTX), - (void (*)(void *)) SHA384_Init, SHA384Update_int, + 48, SHA2_384_HASH_LEN, sizeof(SHA384_CTX), SHA2_384_HMAC_BLOCK_LEN, + (void (*)(void *)) SHA384_Init, NULL, NULL, SHA384Update_int, (void (*)(u_int8_t *, void *)) SHA384_Final }; struct auth_hash auth_hash_hmac_sha2_512 = { CRYPTO_SHA2_512_HMAC, "HMAC-SHA2-512", - 64, SHA2_512_HASH_LEN, SHA2_512_HMAC_BLOCK_LEN, sizeof(SHA512_CTX), - (void (*)(void *)) SHA512_Init, SHA512Update_int, + 64, SHA2_512_HASH_LEN, sizeof(SHA512_CTX), SHA2_512_HMAC_BLOCK_LEN, + (void (*)(void *)) SHA512_Init, NULL, NULL, SHA512Update_int, (void (*)(u_int8_t *, void *)) SHA512_Final }; +struct auth_hash auth_hash_nist_gmac_aes_128 = { + CRYPTO_AES_128_NIST_GMAC, "GMAC-AES-128", + 16, 16, sizeof(struct aes_gmac_ctx), GMAC_BLOCK_LEN, + (void (*)(void *)) AES_GMAC_Init, + (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey, + (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit, + (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update, + (void (*)(u_int8_t *, void *)) AES_GMAC_Final +}; + +struct auth_hash auth_hash_nist_gmac_aes_192 = { + CRYPTO_AES_192_NIST_GMAC, "GMAC-AES-192", + 24, 16, sizeof(struct aes_gmac_ctx), GMAC_BLOCK_LEN, + (void (*)(void *)) AES_GMAC_Init, + (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey, + (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit, + (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update, + (void (*)(u_int8_t *, void *)) AES_GMAC_Final +}; + +struct auth_hash auth_hash_nist_gmac_aes_256 = { + CRYPTO_AES_256_NIST_GMAC, "GMAC-AES-256", + 32, 16, sizeof(struct aes_gmac_ctx), GMAC_BLOCK_LEN, + (void (*)(void *)) AES_GMAC_Init, + (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Setkey, + (void (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Reinit, + (int (*)(void *, const u_int8_t *, u_int16_t)) AES_GMAC_Update, + (void (*)(u_int8_t *, void *)) AES_GMAC_Final +}; + /* Compression instance */ struct comp_algo comp_algo_deflate = { CRYPTO_DEFLATE_COMP, "Deflate", @@ -579,6 +660,74 @@ *sched = NULL; } +void +aes_icm_reinit(caddr_t key, u_int8_t *iv) +{ + struct aes_icm_ctx *ctx; + + ctx = (struct aes_icm_ctx *)key; + bcopy(iv, ctx->ac_block, AESICM_BLOCKSIZE); +} + +void +aes_gcm_reinit(caddr_t key, u_int8_t *iv) +{ + struct aes_icm_ctx *ctx; + + aes_icm_reinit(key, iv); + + ctx = (struct aes_icm_ctx *)key; + /* GCM starts with 2 as counter 1 is used for final xor of tag. */ + bzero(&ctx->ac_block[AESICM_BLOCKSIZE - 4], 4); + ctx->ac_block[AESICM_BLOCKSIZE - 1] = 2; +} + +void +aes_icm_crypt(caddr_t key, u_int8_t *data) +{ + struct aes_icm_ctx *ctx; + u_int8_t keystream[AESICM_BLOCKSIZE]; + int i; + + ctx = (struct aes_icm_ctx *)key; + rijndaelEncrypt(ctx->ac_ek, ctx->ac_nr, ctx->ac_block, keystream); + for (i = 0; i < AESICM_BLOCKSIZE; i++) + data[i] ^= keystream[i]; + explicit_bzero(keystream, sizeof(keystream)); + + /* increment counter */ + for (i = AESICM_BLOCKSIZE - 1; + i >= 0; i--) + if (++ctx->ac_block[i]) /* continue on overflow */ + break; +} + +int +aes_icm_setkey(u_int8_t **sched, u_int8_t *key, int len) +{ + struct aes_icm_ctx *ctx; + + *sched = malloc(sizeof(struct aes_icm_ctx), M_CRYPTO_DATA, + M_NOWAIT | M_ZERO); + if (*sched == NULL) + return ENOMEM; + + ctx = (struct aes_icm_ctx *)*sched; + ctx->ac_nr = rijndaelKeySetupEnc(ctx->ac_ek, (u_char *)key, len * 8); + if (ctx->ac_nr == 0) + return EINVAL; + return 0; +} + +void +aes_icm_zerokey(u_int8_t **sched) +{ + + bzero(*sched, sizeof(struct aes_icm_ctx)); + free(*sched, M_CRYPTO_DATA); + *sched = NULL; +} + #define AES_XTS_BLOCKSIZE 16 #define AES_XTS_IVSIZE 8 #define AES_XTS_ALPHA 0x87 /* GF(2^128) generator polynomial */ @@ -728,8 +877,13 @@ { } +static void +null_reinit(void *ctx, const u_int8_t *buf, u_int16_t len) +{ +} + static int -null_update(void *ctx, u_int8_t *buf, u_int16_t len) +null_update(void *ctx, const u_int8_t *buf, u_int16_t len) { return 0; } @@ -742,14 +896,14 @@ } static int -RMD160Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +RMD160Update_int(void *ctx, const u_int8_t *buf, u_int16_t len) { RMD160Update(ctx, buf, len); return 0; } static int -MD5Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +MD5Update_int(void *ctx, const u_int8_t *buf, u_int16_t len) { MD5Update(ctx, buf, len); return 0; @@ -762,7 +916,7 @@ } static int -SHA1Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +SHA1Update_int(void *ctx, const u_int8_t *buf, u_int16_t len) { SHA1Update(ctx, buf, len); return 0; @@ -775,21 +929,21 @@ } static int -SHA256Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +SHA256Update_int(void *ctx, const u_int8_t *buf, u_int16_t len) { SHA256_Update(ctx, buf, len); return 0; } static int -SHA384Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +SHA384Update_int(void *ctx, const u_int8_t *buf, u_int16_t len) { SHA384_Update(ctx, buf, len); return 0; } static int -SHA512Update_int(void *ctx, u_int8_t *buf, u_int16_t len) +SHA512Update_int(void *ctx, const u_int8_t *buf, u_int16_t len) { SHA512_Update(ctx, buf, len); return 0; --- //depot/vendor/freebsd/src/sys/opencrypto/xform.h.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/opencrypto/xform.h 2014-09-02 16:11:00.000000000 -0700 @@ -9,6 +9,12 @@ * supported the development of this code. * * Copyright (c) 2000 Angelos D. Keromytis + * Copyright (c) 2014 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by John-Mark Gurney + * under sponsorship of the FreeBSD Foundation and + * Rubicon Communications, LLC (Netgate). * * Permission to use, copy, and modify this software without fee * is hereby granted, provided that this entire notice is included in @@ -29,6 +35,7 @@ #include #include #include +#include /* Declarations */ struct auth_hash { @@ -36,10 +43,12 @@ char *name; u_int16_t keysize; u_int16_t hashsize; + u_int16_t ctxsize; u_int16_t blocksize; - u_int16_t ctxsize; void (*Init) (void *); - int (*Update) (void *, u_int8_t *, u_int16_t); + void (*Setkey) (void *, const u_int8_t *, u_int16_t); + void (*Reinit) (void *, const u_int8_t *, u_int16_t); + int (*Update) (void *, const u_int8_t *, u_int16_t); void (*Final) (u_int8_t *, void *); }; @@ -50,6 +59,7 @@ int type; char *name; u_int16_t blocksize; + u_int16_t ivsize; u_int16_t minkey, maxkey; void (*encrypt) (caddr_t, u_int8_t *); void (*decrypt) (caddr_t, u_int8_t *); @@ -73,6 +83,7 @@ SHA256_CTX sha256ctx; SHA384_CTX sha384ctx; SHA512_CTX sha512ctx; + struct aes_gmac_ctx aes_gmac_ctx; }; extern struct enc_xform enc_xform_null; @@ -82,6 +93,9 @@ extern struct enc_xform enc_xform_cast5; extern struct enc_xform enc_xform_skipjack; extern struct enc_xform enc_xform_rijndael128; +extern struct enc_xform enc_xform_aes_icm; +extern struct enc_xform enc_xform_aes_nist_gcm; +extern struct enc_xform enc_xform_aes_nist_gmac; extern struct enc_xform enc_xform_aes_xts; extern struct enc_xform enc_xform_arc4; extern struct enc_xform enc_xform_camellia; @@ -95,6 +109,9 @@ extern struct auth_hash auth_hash_hmac_sha2_256; extern struct auth_hash auth_hash_hmac_sha2_384; extern struct auth_hash auth_hash_hmac_sha2_512; +extern struct auth_hash auth_hash_nist_gmac_aes_128; +extern struct auth_hash auth_hash_nist_gmac_aes_192; +extern struct auth_hash auth_hash_nist_gmac_aes_256; extern struct comp_algo comp_algo_deflate; --- //depot/vendor/freebsd/src/sys/sys/libkern.h.orig 2014-09-02 16:11:00.000000000 -0700 +++ //depot/vendor/freebsd/src/sys/sys/libkern.h 2014-09-02 16:11:00.000000000 -0700 @@ -80,6 +80,7 @@ uint32_t arc4random(void); void arc4rand(void *ptr, u_int len, int reseed); int bcmp(const void *, const void *, size_t); +int timingsafe_bcmp(const void *, const void *, size_t); void *bsearch(const void *, const void *, size_t, size_t, int (*)(const void *, const void *)); #ifndef HAVE_INLINE_FFS