diff mbox

[5/7] esp6: Switch to new AEAD interface

Message ID E1YvNxL-00063M-DH@gondolin.me.apana.org.au
State Not Applicable, archived
Delegated to: David Miller
Headers show

Commit Message

Herbert Xu May 21, 2015, 10:44 a.m. UTC
This patch makes use of the new AEAD interface which uses a single
SG list instead of separate lists for the AD and plain text.  The
IV generation is also now carried out through normal AEAD methods.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
---

 net/ipv6/esp6.c |  197 ++++++++++++++++++++++++++++++++++----------------------
 1 file changed, 122 insertions(+), 75 deletions(-)

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Stephan Mueller May 22, 2015, 6:40 a.m. UTC | #1
Am Donnerstag, 21. Mai 2015, 18:44:03 schrieb Herbert Xu:

Hi Herbert,

>-	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
>-	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
>-	aead_givcrypt_set_assoc(req, asg, assoclen);
>-	aead_givcrypt_set_giv(req, esph->enc_data,
>-			      XFRM_SKB_CB(skb)->seq.output.low);
>+	aead_request_set_crypt(req, sg, sg, ivlen + clen, iv);
>+	aead_request_set_ad(req, assoclen, 0);

If I may ask, where in your initial patch set is now decided that the IV 
generator is used (i.e. so that the givcrypt API is not needed any more)?

Do I understand it correctly that you want to retire the givcrypt API 
entirely?

Thanks
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu May 22, 2015, 6:45 a.m. UTC | #2
On Fri, May 22, 2015 at 08:40:25AM +0200, Stephan Mueller wrote:
>
> If I may ask, where in your initial patch set is now decided that the IV 
> generator is used (i.e. so that the givcrypt API is not needed any more)?

Please see

https://www.mail-archive.com/linux-crypto@vger.kernel.org/msg14270.html

> Do I understand it correctly that you want to retire the givcrypt API 
> entirely?

Correct.  IV generation will be carried as normal AEAD algorithms.

Cheers,
Stephan Mueller May 22, 2015, 7:16 a.m. UTC | #3
Am Freitag, 22. Mai 2015, 14:45:54 schrieb Herbert Xu:

Hi Herbert,

>On Fri, May 22, 2015 at 08:40:25AM +0200, Stephan Mueller wrote:
>> If I may ask, where in your initial patch set is now decided that the IV
>> generator is used (i.e. so that the givcrypt API is not needed any more)?
>
>Please see
>
>https://www.mail-archive.com/linux-crypto@vger.kernel.org/msg14270.html

Thanks for the pointer, but there I do not really see the functionality I am 
looking for. I see patch 10/16 which seems to indicate that the geniv logic is 
now to be invoked as a normal AEAD cipher. I yet fail to see where the 
distinction is made in the code that an IV is to be generated versus the given 
IV is to be used.


Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu May 22, 2015, 7:19 a.m. UTC | #4
On Fri, May 22, 2015 at 09:16:08AM +0200, Stephan Mueller wrote:
>
> Thanks for the pointer, but there I do not really see the functionality I am 
> looking for. I see patch 10/16 which seems to indicate that the geniv logic is 
> now to be invoked as a normal AEAD cipher. I yet fail to see where the 
> distinction is made in the code that an IV is to be generated versus the given 
> IV is to be used.

Only IV generators algorithms will generate IV.  The generated IV
will be placed at the start of cipher text.  See patches 14-16 for
the actual implementation.

Cheers,
Stephan Mueller May 26, 2015, 6:39 a.m. UTC | #5
Am Freitag, 22. Mai 2015, 15:19:23 schrieb Herbert Xu:

Hi Herbert,

> On Fri, May 22, 2015 at 09:16:08AM +0200, Stephan Mueller wrote:
> > Thanks for the pointer, but there I do not really see the functionality I
> > am looking for. I see patch 10/16 which seems to indicate that the geniv
> > logic is now to be invoked as a normal AEAD cipher. I yet fail to see
> > where the distinction is made in the code that an IV is to be generated
> > versus the given IV is to be used.
> 
> Only IV generators algorithms will generate IV.  The generated IV
> will be placed at the start of cipher text.  See patches 14-16 for
> the actual implementation.

Thanks for the help.

May I also ask where I can find the generated IV when using rfc4106(gcm(aes))? 
The old invocation used aead_givcrypt_set_crypt(req, iv->data, 0) which 
delivered the 64 bit value generated by seqiv.

With the new invocation, I use the SGL with AD || IV space || PT

	ivlen = crypto_aead_ivsize(tfm);
	sg_init_table(sg, 3);
	sg_set_buf(&sg[0], aead_assoc->data, aead_assoc->len);
	/* iv->data should be filled by seqiv */
	sg_set_buf(&sg[1], iv->data, ivlen);
	sg_set_buf(&sg[2], data->data, data->len +
		   (enc ? authsize : 0));
	aead_request_set_ad(req, aead_assoc->len, 0);
	aead_request_set_crypt(req, sg, sg, data->len + ivlen, iv->data);

But in iv->data, there is nothing to be found after performing the encrypt 
operation.

Thanks a lot.
Stephan Mueller May 26, 2015, 7:02 a.m. UTC | #6
Am Dienstag, 26. Mai 2015, 08:39:56 schrieb Stephan Mueller:

Hi,

>Am Freitag, 22. Mai 2015, 15:19:23 schrieb Herbert Xu:
>
>Hi Herbert,
>
>> On Fri, May 22, 2015 at 09:16:08AM +0200, Stephan Mueller wrote:
>> > Thanks for the pointer, but there I do not really see the functionality I
>> > am looking for. I see patch 10/16 which seems to indicate that the geniv
>> > logic is now to be invoked as a normal AEAD cipher. I yet fail to see
>> > where the distinction is made in the code that an IV is to be generated
>> > versus the given IV is to be used.
>> 
>> Only IV generators algorithms will generate IV.  The generated IV
>> will be placed at the start of cipher text.  See patches 14-16 for
>> the actual implementation.
>
>Thanks for the help.
>
>May I also ask where I can find the generated IV when using
>rfc4106(gcm(aes))? The old invocation used aead_givcrypt_set_crypt(req,
>iv->data, 0) which delivered the 64 bit value generated by seqiv.
>
>With the new invocation, I use the SGL with AD || IV space || PT
>
>	ivlen = crypto_aead_ivsize(tfm);
>	sg_init_table(sg, 3);
>	sg_set_buf(&sg[0], aead_assoc->data, aead_assoc->len);
>	/* iv->data should be filled by seqiv */
>	sg_set_buf(&sg[1], iv->data, ivlen);
>	sg_set_buf(&sg[2], data->data, data->len +
>		   (enc ? authsize : 0));
>	aead_request_set_ad(req, aead_assoc->len, 0);
>	aead_request_set_crypt(req, sg, sg, data->len + ivlen, iv->data);
>
>But in iv->data, there is nothing to be found after performing the encrypt
>operation.

To be more precise, in iv->data, there is some data. But it is always static 
(seqiv's uses a random number) and does not seem to be the IV used for GCM 
when checking with a reference implementation.
>
>Thanks a lot.


Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu May 26, 2015, 7:21 a.m. UTC | #7
On Tue, May 26, 2015 at 08:39:56AM +0200, Stephan Mueller wrote:
> 
> May I also ask where I can find the generated IV when using rfc4106(gcm(aes))? 

You need to use the IV generator, seqniv(rfc4106(gcm(aes)))

Cheers,
Stephan Mueller May 26, 2015, 7:37 a.m. UTC | #8
Am Dienstag, 26. Mai 2015, 15:21:52 schrieb Herbert Xu:

Hi Herbert,

>On Tue, May 26, 2015 at 08:39:56AM +0200, Stephan Mueller wrote:
>> May I also ask where I can find the generated IV when using
>> rfc4106(gcm(aes))?
>You need to use the IV generator, seqniv(rfc4106(gcm(aes)))

Thank you, that simple change does the trick.

However, now, may I ask you how the following shall be handled:

- the current IKE implementations use rfc4106(gcm(aes)). They would need to 
use seqniv(rfc4106(gcm(aes))) depending on the kernel version. So, we have a 
clear change in the user space API where the old configuration even works 
(i.e. no error), but does not produce the correct encryption that is required.

- For outbound encryption of IPSEC, we need seqniv() as the IV needs to be 
generated. But for inbound, we do not need seqniv() as the IV is already given 
(before the patch, only esp_output used the givcrypt API whereas esp_input 
used the "normal" AEAD API). I would be interested on how that difference is 
to be handled.

Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu May 26, 2015, 7:38 a.m. UTC | #9
On Tue, May 26, 2015 at 09:37:09AM +0200, Stephan Mueller wrote:
>
> - the current IKE implementations use rfc4106(gcm(aes)). They would need to 
> use seqniv(rfc4106(gcm(aes))) depending on the kernel version. So, we have a 
> clear change in the user space API where the old configuration even works 
> (i.e. no error), but does not produce the correct encryption that is required.

You mean through the user-space AEAD interface? That's not a problem
because I'm going to disable it for 4.1 :)

Cheers,
Herbert Xu May 26, 2015, 7:40 a.m. UTC | #10
On Tue, May 26, 2015 at 03:38:58PM +0800, Herbert Xu wrote:
> On Tue, May 26, 2015 at 09:37:09AM +0200, Stephan Mueller wrote:
> >
> > - the current IKE implementations use rfc4106(gcm(aes)). They would need to 
> > use seqniv(rfc4106(gcm(aes))) depending on the kernel version. So, we have a 
> > clear change in the user space API where the old configuration even works 
> > (i.e. no error), but does not produce the correct encryption that is required.
> 
> You mean through the user-space AEAD interface? That's not a problem
> because I'm going to disable it for 4.1 :)

In fact it isn't a problem anyway because we never exported
givencrypt to user-space so this interface never existed.
Stephan Mueller May 26, 2015, 7:56 a.m. UTC | #11
Am Dienstag, 26. Mai 2015, 15:38:59 schrieb Herbert Xu:

Hi Herbert,

>On Tue, May 26, 2015 at 09:37:09AM +0200, Stephan Mueller wrote:
>> - the current IKE implementations use rfc4106(gcm(aes)). They would need to
>> use seqniv(rfc4106(gcm(aes))) depending on the kernel version. So, we have
>> a
>> clear change in the user space API where the old configuration even works
>> (i.e. no error), but does not produce the correct encryption that is
>> required.
>You mean through the user-space AEAD interface? That's not a problem
>because I'm going to disable it for 4.1 :)

Actually, I mean the real in-kernel crypto API: the IKE daemon would set up 
the SA via XFRM where the rfc4106(gcm(aes)) cipher is set, is it not? So, user 
space is responsible to set the right IPSEC cipher.

As that user space cipher name is now changed, user space would need to be 
aware of that modification, would it not?

PS: I just tried seqniv(rfc4106(gcm(aes))) via AF_ALG and it works without 
crashing the kernel. I have not yet checked whether the data returned by 
recvmsg is cryptographically sound.

Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu May 26, 2015, 7:57 a.m. UTC | #12
On Tue, May 26, 2015 at 09:56:17AM +0200, Stephan Mueller wrote:
>
> Actually, I mean the real in-kernel crypto API: the IKE daemon would set up 
> the SA via XFRM where the rfc4106(gcm(aes)) cipher is set, is it not? So, user 
> space is responsible to set the right IPSEC cipher.
> 
> As that user space cipher name is now changed, user space would need to be 
> aware of that modification, would it not?

No the change was done in a backwards compatible way.  So if you
allocate rfc4106(gcm(aes)) and use the givencrypt interface (not
encrypt) then you still get the old behaviour.

Cheers,
Stephan Mueller May 26, 2015, 8:15 a.m. UTC | #13
Am Dienstag, 26. Mai 2015, 15:57:59 schrieb Herbert Xu:

Hi Herbert,

>On Tue, May 26, 2015 at 09:56:17AM +0200, Stephan Mueller wrote:
>> Actually, I mean the real in-kernel crypto API: the IKE daemon would set up
>> the SA via XFRM where the rfc4106(gcm(aes)) cipher is set, is it not? So,
>> user space is responsible to set the right IPSEC cipher.
>> 
>> As that user space cipher name is now changed, user space would need to be
>> aware of that modification, would it not?
>
>No the change was done in a backwards compatible way.  So if you
>allocate rfc4106(gcm(aes)) and use the givencrypt interface (not
>encrypt) then you still get the old behaviour.

I fully understand that. But the current patch set that we discuss modifies 
the IPSEC implementation of esp_ouput to use the new interface. Therefore, to 
use rfc4106(gcm(aes)) *with* the IV generator (i.e. to get the old removed 
givcrypt logic), the AEAD cipher handle must be allocated with 
seqniv(rfc4106(gcm(aes))), would it not?

Therfore, I would assume that user space has to use the new cipher name when 
setting up IPSEC that uses the new interface.

Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Herbert Xu May 26, 2015, 8:18 a.m. UTC | #14
On Tue, May 26, 2015 at 10:15:37AM +0200, Stephan Mueller wrote:
>
> I fully understand that. But the current patch set that we discuss modifies 
> the IPSEC implementation of esp_ouput to use the new interface. Therefore, to 
> use rfc4106(gcm(aes)) *with* the IV generator (i.e. to get the old removed 
> givcrypt logic), the AEAD cipher handle must be allocated with 
> seqniv(rfc4106(gcm(aes))), would it not?
> 
> Therfore, I would assume that user space has to use the new cipher name when 
> setting up IPSEC that uses the new interface.

No I have not exposed IV generation to user-space.  If and when we
do that we can easily set a default IV generator.

This is all in the patch series that you're responding.  So please
actually read it rather than making assumptions :)

Cheers,
Stephan Mueller May 26, 2015, 8:27 a.m. UTC | #15
Am Dienstag, 26. Mai 2015, 16:18:01 schrieb Herbert Xu:

Hi Herbert,

>
>This is all in the patch series that you're responding.  So please
>actually read it rather than making assumptions :)

Sorry, you are right -- I overlooked the xfrm_algo_desc change. Thanks for 
helping.

Ciao
Stephan
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/net/ipv6/esp6.c b/net/ipv6/esp6.c
index 31f1b5d..ff21a5d 100644
--- a/net/ipv6/esp6.c
+++ b/net/ipv6/esp6.c
@@ -76,7 +76,7 @@  static void *esp_alloc_tmp(struct crypto_aead *aead, int nfrags, int seqihlen)
 		len = ALIGN(len, crypto_tfm_ctx_alignment());
 	}
 
-	len += sizeof(struct aead_givcrypt_request) + crypto_aead_reqsize(aead);
+	len += sizeof(struct aead_request) + crypto_aead_reqsize(aead);
 	len = ALIGN(len, __alignof__(struct scatterlist));
 
 	len += sizeof(struct scatterlist) * nfrags;
@@ -96,17 +96,6 @@  static inline u8 *esp_tmp_iv(struct crypto_aead *aead, void *tmp, int seqhilen)
 			 crypto_aead_alignmask(aead) + 1) : tmp + seqhilen;
 }
 
-static inline struct aead_givcrypt_request *esp_tmp_givreq(
-	struct crypto_aead *aead, u8 *iv)
-{
-	struct aead_givcrypt_request *req;
-
-	req = (void *)PTR_ALIGN(iv + crypto_aead_ivsize(aead),
-				crypto_tfm_ctx_alignment());
-	aead_givcrypt_set_tfm(req, aead);
-	return req;
-}
-
 static inline struct aead_request *esp_tmp_req(struct crypto_aead *aead, u8 *iv)
 {
 	struct aead_request *req;
@@ -125,14 +114,6 @@  static inline struct scatterlist *esp_req_sg(struct crypto_aead *aead,
 			     __alignof__(struct scatterlist));
 }
 
-static inline struct scatterlist *esp_givreq_sg(
-	struct crypto_aead *aead, struct aead_givcrypt_request *req)
-{
-	return (void *)ALIGN((unsigned long)(req + 1) +
-			     crypto_aead_reqsize(aead),
-			     __alignof__(struct scatterlist));
-}
-
 static void esp_output_done(struct crypto_async_request *base, int err)
 {
 	struct sk_buff *skb = base->data;
@@ -141,32 +122,57 @@  static void esp_output_done(struct crypto_async_request *base, int err)
 	xfrm_output_resume(skb, err);
 }
 
+/* Move ESP header back into place. */
+static void esp_restore_header(struct sk_buff *skb, unsigned int offset)
+{
+	struct ip_esp_hdr *esph = (void *)(skb->data + offset);
+	void *tmp = ESP_SKB_CB(skb)->tmp;
+	__be32 *seqhi = esp_tmp_seqhi(tmp);
+
+	esph->seq_no = esph->spi;
+	esph->spi = *seqhi;
+}
+
+static void esp_output_restore_header(struct sk_buff *skb)
+{
+	esp_restore_header(skb, skb_transport_offset(skb) - sizeof(__be32));
+}
+
+static void esp_output_done_esn(struct crypto_async_request *base, int err)
+{
+	struct sk_buff *skb = base->data;
+
+	esp_output_restore_header(skb);
+	esp_output_done(base, err);
+}
+
 static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 {
 	int err;
 	struct ip_esp_hdr *esph;
 	struct crypto_aead *aead;
-	struct aead_givcrypt_request *req;
+	struct aead_request *req;
 	struct scatterlist *sg;
-	struct scatterlist *asg;
 	struct sk_buff *trailer;
 	void *tmp;
 	int blksize;
 	int clen;
 	int alen;
 	int plen;
+	int ivlen;
 	int tfclen;
 	int nfrags;
 	int assoclen;
-	int sglists;
 	int seqhilen;
 	u8 *iv;
 	u8 *tail;
 	__be32 *seqhi;
+	__be64 seqno;
 
 	/* skb is pure payload to encrypt */
 	aead = x->data;
 	alen = crypto_aead_authsize(aead);
+	ivlen = crypto_aead_ivsize(aead);
 
 	tfclen = 0;
 	if (x->tfcpad) {
@@ -187,16 +193,14 @@  static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 	nfrags = err;
 
 	assoclen = sizeof(*esph);
-	sglists = 1;
 	seqhilen = 0;
 
 	if (x->props.flags & XFRM_STATE_ESN) {
-		sglists += 2;
 		seqhilen += sizeof(__be32);
 		assoclen += seqhilen;
 	}
 
-	tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
+	tmp = esp_alloc_tmp(aead, nfrags, seqhilen);
 	if (!tmp) {
 		err = -ENOMEM;
 		goto error;
@@ -204,9 +208,8 @@  static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 
 	seqhi = esp_tmp_seqhi(tmp);
 	iv = esp_tmp_iv(aead, tmp, seqhilen);
-	req = esp_tmp_givreq(aead, iv);
-	asg = esp_givreq_sg(aead, req);
-	sg = asg + sglists;
+	req = esp_tmp_req(aead, iv);
+	sg = esp_req_sg(aead, req);
 
 	/* Fill padding... */
 	tail = skb_tail_pointer(trailer);
@@ -227,36 +230,53 @@  static int esp6_output(struct xfrm_state *x, struct sk_buff *skb)
 	esph = ip_esp_hdr(skb);
 	*skb_mac_header(skb) = IPPROTO_ESP;
 
-	esph->spi = x->id.spi;
 	esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
 
+	aead_request_set_callback(req, 0, esp_output_done, skb);
+
+	/* For ESN we move the header forward by 4 bytes to
+	 * accomodate the high bits.  We will move it back after
+	 * encryption.
+	 */
+	if ((x->props.flags & XFRM_STATE_ESN)) {
+		esph = (void *)(skb_transport_header(skb) - sizeof(__be32));
+		*seqhi = esph->spi;
+		esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
+		aead_request_set_callback(req, 0, esp_output_done_esn, skb);
+	}
+
+	esph->spi = x->id.spi;
+
 	sg_init_table(sg, nfrags);
 	skb_to_sgvec(skb, sg,
-		     esph->enc_data + crypto_aead_ivsize(aead) - skb->data,
-		     clen + alen);
+		     (unsigned char *)esph - skb->data,
+		     assoclen + ivlen + clen + alen);
 
-	if ((x->props.flags & XFRM_STATE_ESN)) {
-		sg_init_table(asg, 3);
-		sg_set_buf(asg, &esph->spi, sizeof(__be32));
-		*seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
-		sg_set_buf(asg + 1, seqhi, seqhilen);
-		sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32));
-	} else
-		sg_init_one(asg, esph, sizeof(*esph));
-
-	aead_givcrypt_set_callback(req, 0, esp_output_done, skb);
-	aead_givcrypt_set_crypt(req, sg, sg, clen, iv);
-	aead_givcrypt_set_assoc(req, asg, assoclen);
-	aead_givcrypt_set_giv(req, esph->enc_data,
-			      XFRM_SKB_CB(skb)->seq.output.low);
+	aead_request_set_crypt(req, sg, sg, ivlen + clen, iv);
+	aead_request_set_ad(req, assoclen, 0);
+
+	seqno = cpu_to_be64(XFRM_SKB_CB(skb)->seq.output.low +
+			    ((u64)XFRM_SKB_CB(skb)->seq.output.hi << 32));
+
+	memset(iv, 0, ivlen);
+	memcpy(iv + ivlen - min(ivlen, 8), (u8 *)&seqno + 8 - min(ivlen, 8),
+	       min(ivlen, 8));
 
 	ESP_SKB_CB(skb)->tmp = tmp;
-	err = crypto_aead_givencrypt(req);
-	if (err == -EINPROGRESS)
+	err = crypto_aead_encrypt(req);
+
+	switch (err) {
+	case -EINPROGRESS:
 		goto error;
 
-	if (err == -EBUSY)
+	case -EBUSY:
 		err = NET_XMIT_DROP;
+		break;
+
+	case 0:
+		if ((x->props.flags & XFRM_STATE_ESN))
+			esp_output_restore_header(skb);
+	}
 
 	kfree(tmp);
 
@@ -317,25 +337,38 @@  static void esp_input_done(struct crypto_async_request *base, int err)
 	xfrm_input_resume(skb, esp_input_done2(skb, err));
 }
 
+static void esp_input_restore_header(struct sk_buff *skb)
+{
+	esp_restore_header(skb, 0);
+	__skb_pull(skb, 4);
+}
+
+static void esp_input_done_esn(struct crypto_async_request *base, int err)
+{
+	struct sk_buff *skb = base->data;
+
+	esp_input_restore_header(skb);
+	esp_input_done(base, err);
+}
+
 static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 {
 	struct ip_esp_hdr *esph;
 	struct crypto_aead *aead = x->data;
 	struct aead_request *req;
 	struct sk_buff *trailer;
-	int elen = skb->len - sizeof(*esph) - crypto_aead_ivsize(aead);
+	int ivlen = crypto_aead_ivsize(aead);
+	int elen = skb->len - sizeof(*esph) - ivlen;
 	int nfrags;
 	int assoclen;
-	int sglists;
 	int seqhilen;
 	int ret = 0;
 	void *tmp;
 	__be32 *seqhi;
 	u8 *iv;
 	struct scatterlist *sg;
-	struct scatterlist *asg;
 
-	if (!pskb_may_pull(skb, sizeof(*esph) + crypto_aead_ivsize(aead))) {
+	if (!pskb_may_pull(skb, sizeof(*esph) + ivlen)) {
 		ret = -EINVAL;
 		goto out;
 	}
@@ -354,16 +387,14 @@  static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 	ret = -ENOMEM;
 
 	assoclen = sizeof(*esph);
-	sglists = 1;
 	seqhilen = 0;
 
 	if (x->props.flags & XFRM_STATE_ESN) {
-		sglists += 2;
 		seqhilen += sizeof(__be32);
 		assoclen += seqhilen;
 	}
 
-	tmp = esp_alloc_tmp(aead, nfrags + sglists, seqhilen);
+	tmp = esp_alloc_tmp(aead, nfrags, seqhilen);
 	if (!tmp)
 		goto out;
 
@@ -371,8 +402,7 @@  static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 	seqhi = esp_tmp_seqhi(tmp);
 	iv = esp_tmp_iv(aead, tmp, seqhilen);
 	req = esp_tmp_req(aead, iv);
-	asg = esp_req_sg(aead, req);
-	sg = asg + sglists;
+	sg = esp_req_sg(aead, req);
 
 	skb->ip_summed = CHECKSUM_NONE;
 
@@ -381,26 +411,33 @@  static int esp6_input(struct xfrm_state *x, struct sk_buff *skb)
 	/* Get ivec. This can be wrong, check against another impls. */
 	iv = esph->enc_data;
 
-	sg_init_table(sg, nfrags);
-	skb_to_sgvec(skb, sg, sizeof(*esph) + crypto_aead_ivsize(aead), elen);
+	aead_request_set_callback(req, 0, esp_input_done, skb);
 
+	/* For ESN we move the header forward by 4 bytes to
+	 * accomodate the high bits.  We will move it back after
+	 * decryption.
+	 */
 	if ((x->props.flags & XFRM_STATE_ESN)) {
-		sg_init_table(asg, 3);
-		sg_set_buf(asg, &esph->spi, sizeof(__be32));
-		*seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
-		sg_set_buf(asg + 1, seqhi, seqhilen);
-		sg_set_buf(asg + 2, &esph->seq_no, sizeof(__be32));
-	} else
-		sg_init_one(asg, esph, sizeof(*esph));
+		esph = (void *)skb_push(skb, 4);
+		*seqhi = esph->spi;
+		esph->spi = esph->seq_no;
+		esph->seq_no = htonl(XFRM_SKB_CB(skb)->seq.input.hi);
+		aead_request_set_callback(req, 0, esp_input_done_esn, skb);
+	}
 
-	aead_request_set_callback(req, 0, esp_input_done, skb);
-	aead_request_set_crypt(req, sg, sg, elen, iv);
-	aead_request_set_assoc(req, asg, assoclen);
+	sg_init_table(sg, nfrags);
+	skb_to_sgvec(skb, sg, 0, skb->len);
+
+	aead_request_set_crypt(req, sg, sg, elen + ivlen, iv);
+	aead_request_set_ad(req, assoclen, 0);
 
 	ret = crypto_aead_decrypt(req);
 	if (ret == -EINPROGRESS)
 		goto out;
 
+	if ((x->props.flags & XFRM_STATE_ESN))
+		esp_input_restore_header(skb);
+
 	ret = esp_input_done2(skb, ret);
 
 out:
@@ -460,10 +497,16 @@  static void esp6_destroy(struct xfrm_state *x)
 
 static int esp_init_aead(struct xfrm_state *x)
 {
+	char aead_name[CRYPTO_MAX_ALG_NAME];
 	struct crypto_aead *aead;
 	int err;
 
-	aead = crypto_alloc_aead(x->aead->alg_name, 0, 0);
+	err = -ENAMETOOLONG;
+	if (snprintf(aead_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
+		     x->geniv, x->aead->alg_name) >= CRYPTO_MAX_ALG_NAME)
+		goto error;
+
+	aead = crypto_alloc_aead(aead_name, 0, 0);
 	err = PTR_ERR(aead);
 	if (IS_ERR(aead))
 		goto error;
@@ -502,15 +545,19 @@  static int esp_init_authenc(struct xfrm_state *x)
 
 	if ((x->props.flags & XFRM_STATE_ESN)) {
 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
-			     "authencesn(%s,%s)",
+			     "%s%sauthencesn(%s,%s)%s",
+			     x->geniv ?: "", x->geniv ? "(" : "",
 			     x->aalg ? x->aalg->alg_name : "digest_null",
-			     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
+			     x->ealg->alg_name,
+			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
 			goto error;
 	} else {
 		if (snprintf(authenc_name, CRYPTO_MAX_ALG_NAME,
-			     "authenc(%s,%s)",
+			     "%s%sauthenc(%s,%s)%s",
+			     x->geniv ?: "", x->geniv ? "(" : "",
 			     x->aalg ? x->aalg->alg_name : "digest_null",
-			     x->ealg->alg_name) >= CRYPTO_MAX_ALG_NAME)
+			     x->ealg->alg_name,
+			     x->geniv ? ")" : "") >= CRYPTO_MAX_ALG_NAME)
 			goto error;
 	}