X6 processor family.
aboutsummaryrefslogblamecommitdiffstats
path: root/crypto/testmgr.c
blob: 5823735cf381c0e531a3295419d0ea9d9759c837 (plain) (tree)
1
2
3
4
5
6
7
8







                                                              






                                                            












                                                                             
                       

                     
 
                                          








                                                                     


















































                                                          






                                           




                                  




                                   



                                                                         
                                                                        




                                                
                                              
                                            
                                              




                                                                                

















                                                                      


























                                                             












                                                                         
                                                                             
                                                          






                                                                             
                        




                                    






                                                                            




                                                                   
              
                                      



                                   












                                                                              
                                                                           





                                                                            




























                                                                             
                         




                                                                             
                                        













                                                                      
                                      
                                                              


                                                                            




























































                                                                               

                               


                   


                                                                          


                                                                            
                          


                                 



                                  


                                    
                     

                           
                             
                                





                                     
 














                                                                               








                                                  

                                                                          















                                                                           




                                                                   
















                                                                           

                                                                                                  






                                                                            

                                                                                                       





                                                                             








                                                                      

                                                                      
                                                                                









                                                                           

                                                                               

                                                                                                                          



                                                                             








                                                                           



                                                                               

                                                  

                                                                                            


                                         
                                   
                                                                              

                                                                                    























                                                                             

                                                                                                        







                                                                            

                                                                     

















                                                                            












                                                                              




                                                                     

                                                                                                             











                                                                         


                                                                        


                                                            
                                      
                                                                         


                                                                             








                                                                               
                                                                                










                                                                           

                                                                               

                                                                                                                                



                                                                             








                                                                           



                                                                               

                                                  

                                                                                                  




                                                                        





                                                                           





                                                                              

                                                                                                             





                                                                      

                                                                             









                                                                            

                                                                                                                                             












                                                           




                                          



                                


                   













                                                                        
                                                          

                                                                            

                                                                              


                      




                                    












                                      



                                                          







































                                                                              

                               


                   


                                                                                
 


                                                                       


                                       

                                    


                                    
                             
                                



                                    
 







                                                   








                                                        

                                                                              












                                                                        
                                                                     

                            



                                                                  










                                                                            


                                                                                                      




                                                                    



                                                                               
 

                                                                             

















                                                                           

                                                                                                




                                                                              

                                                                                        

























                                                                            

                                                                                                            







                                                                         

                                                                     















                                                                            











                                                                           



                                                           

                                                                


















                                                                           

                                                                                                      





                                                              





                                                                           


                                                                        

                                                                                                                 







                                                                               

                                                                                                                                                 











                                                           


                                          

                               


                   













                                                                              








                                                                              

                                                  












                                                                          







                                                                               









                                                                         

                                                  












                                                                          







                                                                               














                                                                           







                                                                             
                


                                        
                                          
 


                                                                     
                                                                              

                                                                          

                 

                                                
                                                                             

                                                                          








                                                        

                                                                  
                                                                               

                                                                          
                 

                                        



                                                             

                                                                  
                                                                               

                                                                          
                 

                                        



                                                                         

                                                       
                                                                              

                                                                          
                 
                                








                                                                               






                                                                               









                                                                               
                                          
 


                                                                       
                                                                           

                                                                               

                 

                                                  
                                                                               

                                                                          








                                                        

                                                                  
                                                                            

                                                                               
                 

                                        



                                                             

                                                                  
                                                                            

                                                                               
                 

                                        



                                                                         

                                                                  
                                                                           

                                                                               
                 

                                        








                                                                             






                                                                              










                                                                               




                                                                             
                                    























































                                                                               































                                                                              
                                  

                    
                                                      

















                                                                            




























                                                                              

























                                                                              





















                                                                               












                                                                              




                                                               




                               
















































                                                                                



















                                                                               





                                                                    


                                                      

                                         
            

                                         
            

                                           
            


                                            

                                            
            

                                           
            


                                            

                                                
                                  
            


                                                    

                                                     
            


                                                          

                                                
            

                                                
            

                                                  
            


                                                   

                                                   
            

                                                  
            


                                                   

                                                
                                  
            


                                                    

                                                     
            


                                                          

                                                
            

                                                
            

                                                  
            


                                                   

                                                   
            

                                                  
            


                                                   

                                             
                                  
            

                                       
                                  






                                                                    



































                                                                                     
                                  
                                          
                                  













                                                                         
                                          













                                                                            
                                          













                                                                        
                                          












                                                                              














                                                                           














                                                                           
                                  
                                          













                                                                         
                                          
                                  












                                                                              














                                                                             
                                      
                                          














                                                                        
                                  












                                                                         

















                                                                    


                                       
                                
                                        
                                  






                                                            


                                                        
            


                                                            

                                                             
            


                                                                  


                                                           

                                                        
                                  
            


                                                            

                                                             
            


                                                                  

                                                        
            

                                                        
            

                                                          
            


                                                           

                                                           
            

                                                          
            


                                                           


                                                        
            

                                                     
                                  
            

                                          
                                  












                                                                         














                                                                        














                                                                              














                                                                           













                                                                           














                                                                         














                                                                              
            














                                                                             














                                                                        
                                       
                                          














                                                                          
                                  












                                                                            


                                      

                                          
                                  
            
                                  
                                          
                                  













                                                                     
                                          













                                                                        
                                          













                                                                      
                                          













                                                                    
                                          













                                                                          
                                          













                                                                       
                                          












                                                                       


                                          
                                  
                                          
                                  













                                                                     
                                          
                                  












                                                                          














                                                                            
                                     
                                          













                                                                        
                                          













                                                                      
                                          













                                                                         
                                          













                                                                     
                                          













                                                                         
                                          













                                                                    
                                          













                                                                      
                                          














                                                                      
                                  












                                                                         

                                      
                                  






                                                           








                                                              




























                                                                 
                                  








                                                               
                                  








                                                                 
                                  








                                                                 
                                  








                                                                 
                                  







                                                                 
                                          












                                                                         














                                                                              














                                                                           














                                                                             














                                                                        

                                      
                                  







































                                                                        















                                                                         
                                      
                                          













                                                                            
                                          
                                  


                                        

                                                                                

                                        

                                                                                



                                 














                                                                                

                                           
                                  












                                                                                














                                                                                




































                                                            
                                          










                                                                                
                                  








                                                          
                                  








                                                            
                                  








                                                            
                                  








                                                            
                                  

































                                                            








                                                                




































                                                                
                                          
                                  











                                                                         
            














                                                                              














                                                                           














                                                                             














                                                                        

                                       
                                  











                                                                         


         
                                         

















                                                              








                                                                     
              
               











                                                                      


                                                                    

                                                                             

         
                               

                                  

                            

                                                                           

                                  







                                                                        
          


                                                                                  



                                                                        
                  

       

                                                                    

                       
 
 
                                                
 
                            
/*
 * Algorithm testing framework and tests.
 *
 * Copyright (c) 2002 James Morris <jmorris@intercode.com.au>
 * Copyright (c) 2002 Jean-Francois Dive <jef@linuxbe.org>
 * Copyright (c) 2007 Nokia Siemens Networks
 * Copyright (c) 2008 Herbert Xu <herbert@gondor.apana.org.au>
 *
 * Updated RFC4106 AES-GCM testing.
 *    Authors: Aidan O'Mahony (aidan.o.mahony@intel.com)
 *             Adrian Hoban <adrian.hoban@intel.com>
 *             Gabriele Paoloni <gabriele.paoloni@intel.com>
 *             Tadeusz Struk (tadeusz.struk@intel.com)
 *    Copyright (c) 2010, Intel Corporation.
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 */

#include <crypto/hash.h>
#include <linux/err.h>
#include <linux/module.h>
#include <linux/scatterlist.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <crypto/rng.h>

#include "internal.h"

#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS

/* a perfect nop */
int alg_test(const char *driver, const char *alg, u32 type, u32 mask)
{
	return 0;
}

#else

#include "testmgr.h"

/*
 * Need slab memory for testing (size in number of pages).
 */
#define XBUFSIZE	8

/*
 * Indexes into the xbuf to simulate cross-page access.
 */
#define IDX1		32
#define IDX2		32400
#define IDX3		1
#define IDX4		8193
#define IDX5		22222
#define IDX6		17101
#define IDX7		27333
#define IDX8		3000

/*
* Used by test_cipher()
*/
#define ENCRYPT 1
#define DECRYPT 0

struct tcrypt_result {
	struct completion completion;
	int err;
};

struct aead_test_suite {
	struct {
		struct aead_testvec *vecs;
		unsigned int count;
	} enc, dec;
};

struct cipher_test_suite {
	struct {
		struct cipher_testvec *vecs;
		unsigned int count;
	} enc, dec;
};

struct comp_test_suite {
	struct {
		struct comp_testvec *vecs;
		unsigned int count;
	} comp, decomp;
};

struct pcomp_test_suite {
	struct {
		struct pcomp_testvec *vecs;
		unsigned int count;
	} comp, decomp;
};

struct hash_test_suite {
	struct hash_testvec *vecs;
	unsigned int count;
};

struct cprng_test_suite {
	struct cprng_testvec *vecs;
	unsigned int count;
};

struct alg_test_desc {
	const char *alg;
	int (*test)(const struct alg_test_desc *desc, const char *driver,
		    u32 type, u32 mask);
	int fips_allowed;	/* set if alg is allowed in fips mode */

	union {
		struct aead_test_suite aead;
		struct cipher_test_suite cipher;
		struct comp_test_suite comp;
		struct pcomp_test_suite pcomp;
		struct hash_test_suite hash;
		struct cprng_test_suite cprng;
	} suite;
};

static unsigned int IDX[8] = { IDX1, IDX2, IDX3, IDX4, IDX5, IDX6, IDX7, IDX8 };

static void hexdump(unsigned char *buf, unsigned int len)
{
	print_hex_dump(KERN_CONT, "", DUMP_PREFIX_OFFSET,
			16, 1,
			buf, len, false);
}

static void tcrypt_complete(struct crypto_async_request *req, int err)
{
	struct tcrypt_result *res = req->data;

	if (err == -EINPROGRESS)
		return;

	res->err = err;
	complete(&res->completion);
}

static int testmgr_alloc_buf(char *buf[XBUFSIZE])
{
	int i;

	for (i = 0; i < XBUFSIZE; i++) {
		buf[i] = (void *)__get_free_page(GFP_KERNEL);
		if (!buf[i])
			goto err_free_buf;
	}

	return 0;

err_free_buf:
	while (i-- > 0)
		free_page((unsigned long)buf[i]);

	return -ENOMEM;
}

static void testmgr_free_buf(char *buf[XBUFSIZE])
{
	int i;

	for (i = 0; i < XBUFSIZE; i++)
		free_page((unsigned long)buf[i]);
}

static int do_one_async_hash_op(struct ahash_request *req,
				struct tcrypt_result *tr,
				int ret)
{
	if (ret == -EINPROGRESS || ret == -EBUSY) {
		ret = wait_for_completion_interruptible(&tr->completion);
		if (!ret)
			ret = tr->err;
		INIT_COMPLETION(tr->completion);
	}
	return ret;
}

static int test_hash(struct crypto_ahash *tfm, struct hash_testvec *template,
		     unsigned int tcount, bool use_digest)
{
	const char *algo = crypto_tfm_alg_driver_name(crypto_ahash_tfm(tfm));
	unsigned int i, j, k, temp;
	struct scatterlist sg[8];
	char result[64];
	struct ahash_request *req;
	struct tcrypt_result tresult;
	void *hash_buff;
	char *xbuf[XBUFSIZE];
	int ret = -ENOMEM;

	if (testmgr_alloc_buf(xbuf))
		goto out_nobuf;

	init_completion(&tresult.completion);

	req = ahash_request_alloc(tfm, GFP_KERNEL);
	if (!req) {
		printk(KERN_ERR "alg: hash: Failed to allocate request for "
		       "%s\n", algo);
		goto out_noreq;
	}
	ahash_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
				   tcrypt_complete, &tresult);

	j = 0;
	for (i = 0; i < tcount; i++) {
		if (template[i].np)
			continue;

		j++;
		memset(result, 0, 64);

		hash_buff = xbuf[0];

		memcpy(hash_buff, template[i].plaintext, template[i].psize);
		sg_init_one(&sg[0], hash_buff, template[i].psize);

		if (template[i].ksize) {
			crypto_ahash_clear_flags(tfm, ~0);
			ret = crypto_ahash_setkey(tfm, template[i].key,
						  template[i].ksize);
			if (ret) {
				printk(KERN_ERR "alg: hash: setkey failed on "
				       "test %d for %s: ret=%d\n", j, algo,
				       -ret);
				goto out;
			}
		}

		ahash_request_set_crypt(req, sg, result, template[i].psize);
		if (use_digest) {
			ret = do_one_async_hash_op(req, &tresult,
						   crypto_ahash_digest(req));
			if (ret) {
				pr_err("alg: hash: digest failed on test %d "
				       "for %s: ret=%d\n", j, algo, -ret);
				goto out;
			}
		} else {
			ret = do_one_async_hash_op(req, &tresult,
						   crypto_ahash_init(req));
			if (ret) {
				pr_err("alt: hash: init failed on test %d "
				       "for %s: ret=%d\n", j, algo, -ret);
				goto out;
			}
			ret = do_one_async_hash_op(req, &tresult,
						   crypto_ahash_update(req));
			if (ret) {
				pr_err("alt: hash: update failed on test %d "
				       "for %s: ret=%d\n", j, algo, -ret);
				goto out;
			}
			ret = do_one_async_hash_op(req, &tresult,
						   crypto_ahash_final(req));
			if (ret) {
				pr_err("alt: hash: final failed on test %d "
				       "for %s: ret=%d\n", j, algo, -ret);
				goto out;
			}
		}

		if (memcmp(result, template[i].digest,
			   crypto_ahash_digestsize(tfm))) {
			printk(KERN_ERR "alg: hash: Test %d failed for %s\n",
			       j, algo);
			hexdump(result, crypto_ahash_digestsize(tfm));
			ret = -EINVAL;
			goto out;
		}
	}

	j = 0;
	for (i = 0; i < tcount; i++) {
		if (template[i].np) {
			j++;
			memset(result, 0, 64);

			temp = 0;
			sg_init_table(sg, template[i].np);
			ret = -EINVAL;
			for (k = 0; k < template[i].np; k++) {
				if (WARN_ON(offset_in_page(IDX[k]) +
					    template[i].tap[k] > PAGE_SIZE))
					goto out;
				sg_set_buf(&sg[k],
					   memcpy(xbuf[IDX[k] >> PAGE_SHIFT] +
						  offset_in_page(IDX[k]),
						  template[i].plaintext + temp,
						  template[i].tap[k]),
					   template[i].tap[k]);
				temp += template[i].tap[k];
			}

			if (template[i].ksize) {
				crypto_ahash_clear_flags(tfm, ~0);
				ret = crypto_ahash_setkey(tfm, template[i].key,
							  template[i].ksize);

				if (ret) {
					printk(KERN_ERR "alg: hash: setkey "
					       "failed on chunking test %d "
					       "for %s: ret=%d\n", j, algo,
					       -ret);
					goto out;
				}
			}

			ahash_request_set_crypt(req, sg, result,
						template[i].psize);
			ret = crypto_ahash_digest(req);
			switch (ret) {
			case 0:
				break;
			case -EINPROGRESS:
			case -EBUSY:
				ret = wait_for_completion_interruptible(
					&tresult.completion);
				if (!ret && !(ret = tresult.err)) {
					INIT_COMPLETION(tresult.completion);
					break;
				}
				/* fall through */
			default:
				printk(KERN_ERR "alg: hash: digest failed "
				       "on chunking test %d for %s: "
				       "ret=%d\n", j, algo, -ret);
				goto out;
			}

			if (memcmp(result, template[i].digest,
				   crypto_ahash_digestsize(tfm))) {
				printk(KERN_ERR "alg: hash: Chunking test %d "
				       "failed for %s\n", j, algo);
				hexdump(result, crypto_ahash_digestsize(tfm));
				ret = -EINVAL;
				goto out;
			}
		}
	}

	ret = 0;

out:
	ahash_request_free(req);
out_noreq:
	testmgr_free_buf(xbuf);
out_nobuf:
	return ret;
}

static int __test_aead(struct crypto_aead *tfm, int enc,
		       struct aead_testvec *template, unsigned int tcount,
		       const bool diff_dst)
{
	const char *algo = crypto_tfm_alg_driver_name(crypto_aead_tfm(tfm));
	unsigned int i, j, k, n, temp;
	int ret = -ENOMEM;
	char *q;
	char *key;
	struct aead_request *req;
	struct scatterlist *sg;
	struct scatterlist *asg;
	struct scatterlist *sgout;
	const char *e, *d;
	struct tcrypt_result result;
	unsigned int authsize;
	void *input;
	void *output;
	void *assoc;
	char iv[MAX_IVLEN];
	char *xbuf[XBUFSIZE];
	char *xoutbuf[XBUFSIZE];
	char *axbuf[XBUFSIZE];

	if (testmgr_alloc_buf(xbuf))
		goto out_noxbuf;
	if (testmgr_alloc_buf(axbuf))
		goto out_noaxbuf;

	if (diff_dst && testmgr_alloc_buf(xoutbuf))
		goto out_nooutbuf;

	/* avoid "the frame size is larger than 1024 bytes" compiler warning */
	sg = kmalloc(sizeof(*sg) * 8 * (diff_dst ? 3 : 2), GFP_KERNEL);
	if (!sg)
		goto out_nosg;
	asg = &sg[8];
	sgout = &asg[8];

	if (diff_dst)
		d = "-ddst";
	else
		d = "";

	if (enc == ENCRYPT)
		e = "encryption";
	else
		e = "decryption";

	init_completion(&result.completion);

	req = aead_request_alloc(tfm, GFP_KERNEL);
	if (!req) {
		pr_err("alg: aead%s: Failed to allocate request for %s\n",
		       d, algo);
		goto out;
	}

	aead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
				  tcrypt_complete, &result);

	for (i = 0, j = 0; i < tcount; i++) {
		if (!template[i].np) {
			j++;

			/* some tepmplates have no input data but they will
			 * touch input
			 */
			input = xbuf[0];
			assoc = axbuf[0];

			ret = -EINVAL;
			if (WARN_ON(template[i].ilen > PAGE_SIZE ||
				    template[i].alen > PAGE_SIZE))
				goto out;

			memcpy(input, template[i].input, template[i].ilen);
			memcpy(assoc, template[i].assoc, template[i].alen);
			if (template[i].iv)
				memcpy(iv, template[i].iv, MAX_IVLEN);
			else
				memset(iv, 0, MAX_IVLEN);

			crypto_aead_clear_flags(tfm, ~0);
			if (template[i].wk)
				crypto_aead_set_flags(
					tfm, CRYPTO_TFM_REQ_WEAK_KEY);

			key = template[i].key;

			ret = crypto_aead_setkey(tfm, key,
						 template[i].klen);
			if (!ret == template[i].fail) {
				pr_err("alg: aead%s: setkey failed on test %d for %s: flags=%x\n",
				       d, j, algo, crypto_aead_get_flags(tfm));
				goto out;
			} else if (ret)
				continue;

			authsize = abs(template[i].rlen - template[i].ilen);
			ret = crypto_aead_setauthsize(tfm, authsize);
			if (ret) {
				pr_err("alg: aead%s: Failed to set authsize to %u on test %d for %s\n",
				       d, authsize, j, algo);
				goto out;
			}

			sg_init_one(&sg[0], input,
				    template[i].ilen + (enc ? authsize : 0));

			if (diff_dst) {
				output = xoutbuf[0];
				sg_init_one(&sgout[0], output,
					    template[i].ilen +
						(enc ? authsize : 0));
			} else {
				output = input;
			}

			sg_init_one(&asg[0], assoc, template[i].alen);

			aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
					       template[i].ilen, iv);

			aead_request_set_assoc(req, asg, template[i].alen);

			ret = enc ?
				crypto_aead_encrypt(req) :
				crypto_aead_decrypt(req);

			switch (ret) {
			case 0:
				if (template[i].novrfy) {
					/* verification was supposed to fail */
					pr_err("alg: aead%s: %s failed on test %d for %s: ret was 0, expected -EBADMSG\n",
					       d, e, j, algo);
					/* so really, we got a bad message */
					ret = -EBADMSG;
					goto out;
				}
				break;
			case -EINPROGRESS:
			case -EBUSY:
				ret = wait_for_completion_interruptible(
					&result.completion);
				if (!ret && !(ret = result.err)) {
					INIT_COMPLETION(result.completion);
					break;
				}
			case -EBADMSG:
				if (template[i].novrfy)
					/* verification failure was expected */
					continue;
				/* fall through */
			default:
				pr_err("alg: aead%s: %s failed on test %d for %s: ret=%d\n",
				       d, e, j, algo, -ret);
				goto out;
			}

			q = output;
			if (memcmp(q, template[i].result, template[i].rlen)) {
				pr_err("alg: aead%s: Test %d failed on %s for %s\n",
				       d, j, e, algo);
				hexdump(q, template[i].rlen);
				ret = -EINVAL;
				goto out;
			}
		}
	}

	for (i = 0, j = 0; i < tcount; i++) {
		if (template[i].np) {
			j++;

			if (template[i].iv)
				memcpy(iv, template[i].iv, MAX_IVLEN);
			else
				memset(iv, 0, MAX_IVLEN);

			crypto_aead_clear_flags(tfm, ~0);
			if (template[i].wk)
				crypto_aead_set_flags(
					tfm, CRYPTO_TFM_REQ_WEAK_KEY);
			key = template[i].key;

			ret = crypto_aead_setkey(tfm, key, template[i].klen);
			if (!ret == template[i].fail) {
				pr_err("alg: aead%s: setkey failed on chunk test %d for %s: flags=%x\n",
				       d, j, algo, crypto_aead_get_flags(tfm));
				goto out;
			} else if (ret)
				continue;

			authsize = abs(template[i].rlen - template[i].ilen);

			ret = -EINVAL;
			sg_init_table(sg, template[i].np);
			if (diff_dst)
				sg_init_table(sgout, template[i].np);
			for (k = 0, temp = 0; k < template[i].np; k++) {
				if (WARN_ON(offset_in_page(IDX[k]) +
					    template[i].tap[k] > PAGE_SIZE))
					goto out;

				q = xbuf[IDX[k] >> PAGE_SHIFT] +
				    offset_in_page(IDX[k]);

				memcpy(q, template[i].input + temp,
				       template[i].tap[k]);

				n = template[i].tap[k];
				if (k == template[i].np - 1 && enc)
					n += authsize;
				if (offset_in_page(q) + n < PAGE_SIZE)
					q[n] = 0;

				sg_set_buf(&sg[k], q, template[i].tap[k]);

				if (diff_dst) {
					q = xoutbuf[IDX[k] >> PAGE_SHIFT] +
					    offset_in_page(IDX[k]);

					memset(q, 0, template[i].tap[k]);
					if (offset_in_page(q) + n < PAGE_SIZE)
						q[n] = 0;

					sg_set_buf(&sgout[k], q,
						   template[i].tap[k]);
				}

				temp += template[i].tap[k];
			}

			ret = crypto_aead_setauthsize(tfm, authsize);
			if (ret) {
				pr_err("alg: aead%s: Failed to set authsize to %u on chunk test %d for %s\n",
				       d, authsize, j, algo);
				goto out;
			}

			if (enc) {
				if (WARN_ON(sg[k - 1].offset +
					    sg[k - 1].length + authsize >
					    PAGE_SIZE)) {
					ret = -EINVAL;
					goto out;
				}

				sg[k - 1].length += authsize;

				if (diff_dst)
					sgout[k - 1].length += authsize;
			}

			sg_init_table(asg, template[i].anp);
			ret = -EINVAL;
			for (k = 0, temp = 0; k < template[i].anp; k++) {
				if (WARN_ON(offset_in_page(IDX[k]) +
					    template[i].atap[k] > PAGE_SIZE))
					goto out;
				sg_set_buf(&asg[k],
					   memcpy(axbuf[IDX[k] >> PAGE_SHIFT] +
						  offset_in_page(IDX[k]),
						  template[i].assoc + temp,
						  template[i].atap[k]),
					   template[i].atap[k]);
				temp += template[i].atap[k];
			}

			aead_request_set_crypt(req, sg, (diff_dst) ? sgout : sg,
					       template[i].ilen,
					       iv);

			aead_request_set_assoc(req, asg, template[i].alen);

			ret = enc ?
				crypto_aead_encrypt(req) :
				crypto_aead_decrypt(req);

			switch (ret) {
			case 0:
				if (template[i].novrfy) {
					/* verification was supposed to fail */
					pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret was 0, expected -EBADMSG\n",
					       d, e, j, algo);
					/* so really, we got a bad message */
					ret = -EBADMSG;
					goto out;
				}
				break;
			case -EINPROGRESS:
			case -EBUSY:
				ret = wait_for_completion_interruptible(
					&result.completion);
				if (!ret && !(ret = result.err)) {
					INIT_COMPLETION(result.completion);
					break;
				}
			case -EBADMSG:
				if (template[i].novrfy)
					/* verification failure was expected */
					continue;
				/* fall through */
			default:
				pr_err("alg: aead%s: %s failed on chunk test %d for %s: ret=%d\n",
				       d, e, j, algo, -ret);
				goto out;
			}

			ret = -EINVAL;
			for (k = 0, temp = 0; k < template[i].np; k++) {
				if (diff_dst)
					q = xoutbuf[IDX[k] >> PAGE_SHIFT] +
					    offset_in_page(IDX[k]);
				else
					q = xbuf[IDX[k] >> PAGE_SHIFT] +
					    offset_in_page(IDX[k]);

				n = template[i].tap[k];
				if (k == template[i].np - 1)
					n += enc ? authsize : -authsize;

				if (memcmp(q, template[i].result + temp, n)) {
					pr_err("alg: aead%s: Chunk test %d failed on %s at page %u for %s\n",
					       d, j, e, k, algo);
					hexdump(q, n);
					goto out;
				}

				q += n;
				if (k == template[i].np - 1 && !enc) {
					if (!diff_dst &&
						memcmp(q, template[i].input +
						      temp + n, authsize))
						n = authsize;
					else
						n = 0;
				} else {
					for (n = 0; offset_in_page(q + n) &&
						    q[n]; n++)
						;
				}
				if (n) {
					pr_err("alg: aead%s: Result buffer corruption in chunk test %d on %s at page %u for %s: %u bytes:\n",
					       d, j, e, k, algo, n);
					hexdump(q, n);
					goto out;
				}

				temp += template[i].tap[k];
			}
		}
	}

	ret = 0;

out:
	aead_request_free(req);
	kfree(sg);
out_nosg:
	if (diff_dst)
		testmgr_free_buf(xoutbuf);
out_nooutbuf:
	testmgr_free_buf(axbuf);
out_noaxbuf:
	testmgr_free_buf(xbuf);
out_noxbuf:
	return ret;
}

static int test_aead(struct crypto_aead *tfm, int enc,
		     struct aead_testvec *template, unsigned int tcount)
{
	int ret;

	/* test 'dst == src' case */
	ret = __test_aead(tfm, enc, template, tcount, false);
	if (ret)
		return ret;

	/* test 'dst != src' case */
	return __test_aead(tfm, enc, template, tcount, true);
}

static int test_cipher(struct crypto_cipher *tfm, int enc,
		       struct cipher_testvec *template, unsigned int tcount)
{
	const char *algo = crypto_tfm_alg_driver_name(crypto_cipher_tfm(tfm));
	unsigned int i, j, k;
	char *q;
	const char *e;
	void *data;
	char *xbuf[XBUFSIZE];
	int ret = -ENOMEM;

	if (testmgr_alloc_buf(xbuf))
		goto out_nobuf;

	if (enc == ENCRYPT)
	        e = "encryption";
	else
		e = "decryption";

	j = 0;
	for (i = 0; i < tcount; i++) {
		if (template[i].np)
			continue;

		j++;

		ret = -EINVAL;
		if (WARN_ON(template[i].ilen > PAGE_SIZE))
			goto out;

		data = xbuf[0];
		memcpy(data, template[i].input, template[i].ilen);

		crypto_cipher_clear_flags(tfm, ~0);
		if (template[i].wk)
			crypto_cipher_set_flags(tfm, CRYPTO_TFM_REQ_WEAK_KEY);

		ret = crypto_cipher_setkey(tfm, template[i].key,
					   template[i].klen);
		if (!ret == template[i].fail) {
			printk(KERN_ERR "alg: cipher: setkey failed "
			       "on test %d for %s: flags=%x\n", j,
			       algo, crypto_cipher_get_flags(tfm));
			goto out;
		} else if (ret)
			continue;

		for (k = 0; k < template[i].ilen;
		     k += crypto_cipher_blocksize(tfm)) {
			if (enc)
				crypto_cipher_encrypt_one(tfm, data + k,
							  data + k);
			else
				crypto_cipher_decrypt_one(tfm, data + k,
							  data + k);
		}

		q = data;
		if (memcmp(q, template[i].result, template[i].rlen)) {
			printk(KERN_ERR "alg: cipher: Test %d failed "
			       "on %s for %s\n", j, e, algo);
			hexdump(q, template[i].rlen);
			ret = -EINVAL;
			goto out;
		}
	}

	ret = 0;

out:
	testmgr_free_buf(xbuf);
out_nobuf:
	return ret;
}

static int __test_skcipher(struct crypto_ablkcipher *tfm, int enc,
			   struct cipher_testvec *template, unsigned int tcount,
			   const bool diff_dst)
{
	const char *algo =
		crypto_tfm_alg_driver_name(crypto_ablkcipher_tfm(tfm));
	unsigned int i, j, k, n, temp;
	char *q;
	struct ablkcipher_request *req;
	struct scatterlist sg[8];
	struct scatterlist sgout[8];
	const char *e, *d;
	struct tcrypt_result result;
	void *data;
	char iv[MAX_IVLEN];
	char *xbuf[XBUFSIZE];
	char *xoutbuf[XBUFSIZE];
	int ret = -ENOMEM;

	if (testmgr_alloc_buf(xbuf))
		goto out_nobuf;

	if (diff_dst && testmgr_alloc_buf(xoutbuf))
		goto out_nooutbuf;

	if (diff_dst)
		d = "-ddst";
	else
		d = "";

	if (enc == ENCRYPT)
	        e = "encryption";
	else
		e = "decryption";

	init_completion(&result.completion);

	req = ablkcipher_request_alloc(tfm, GFP_KERNEL);
	if (!req) {
		pr_err("alg: skcipher%s: Failed to allocate request for %s\n",
		       d, algo);
		goto out;
	}

	ablkcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,
					tcrypt_complete, &result);

	j = 0;
	for (i = 0; i < tcount; i++) {
		if (template[i].iv)
			memcpy(iv, template[i].iv, MAX_IVLEN);
		else
			memset(iv, 0, MAX_IVLEN);

		if (!(template[i].np) || (template[i].also_non_np)) {
			j++;

			ret = -EINVAL;
			if (WARN_ON(template[i].ilen > PAGE_SIZE))
				goto out;

			data = xbuf[0];
			memcpy(data, template[i].input, template[i].ilen);

			crypto_ablkcipher_clear_flags(tfm, ~0);
			if (template[i].wk)
				crypto_ablkcipher_set_flags(
					tfm, CRYPTO_TFM_REQ_WEAK_KEY);

			ret = crypto_ablkcipher_setkey(tfm, template[i].key,
						       template[i].klen);
			if (!ret == template[i].fail) {
				pr_err("alg: skcipher%s: setkey failed on test %d for %s: flags=%x\n",
				       d, j, algo,
				       crypto_ablkcipher_get_flags(tfm));
				goto out;
			} else if (ret)
				continue;

			sg_init_one(&sg[0], data, template[i].ilen);
			if (diff_dst) {
				data = xoutbuf[0];
				sg_init_one(&sgout[0], data, template[i].ilen);
			}

			ablkcipher_request_set_crypt(req, sg,
						     (diff_dst) ? sgout : sg,
						     template[i].ilen, iv);
			ret = enc ?
				crypto_ablkcipher_encrypt(req) :
				crypto_ablkcipher_decrypt(req);

			switch (ret) {
			case 0:
				break;
			case -EINPROGRESS:
			case -EBUSY:
				ret = wait_for_completion_interruptible(
					&result.completion);
				if (!ret && !((ret = result.err))) {
					INIT_COMPLETION(result.completion);
					break;
				}
				/* fall through */
			default:
				pr_err("alg: skcipher%s: %s failed on test %d for %s: ret=%d\n",
				       d, e, j, algo, -ret);
				goto out;
			}

			q = data;
			if (memcmp(q, template[i].result, template[i].rlen)) {
				pr_err("alg: skcipher%s: Test %d failed on %s for %s\n",
				       d, j, e, algo);
				hexdump(q, template[i].rlen);
				ret = -EINVAL;
				goto out;
			}
		}
	}

	j = 0;
	for (i = 0; i < tcount; i++) {

		if (template[i].iv)
			memcpy(iv, template[i].iv, MAX_IVLEN);
		else
			memset(iv, 0, MAX_IVLEN);

		if (template[i].np) {
			j++;

			crypto_ablkcipher_clear_flags(tfm, ~0);
			if (template[i].wk)
				crypto_ablkcipher_set_flags(
					tfm, CRYPTO_TFM_REQ_WEAK_KEY);

			ret = crypto_ablkcipher_setkey(tfm, template[i].key,
						       template[i].klen);
			if (!ret == template[i].fail) {
				pr_err("alg: skcipher%s: setkey failed on chunk test %d for %s: flags=%x\n",
				       d, j, algo,
				       crypto_ablkcipher_get_flags(tfm));
				goto out;
			} else if (ret)
				continue;

			temp = 0;
			ret = -EINVAL;
			sg_init_table(sg, template[i].np);
			if (diff_dst)
				sg_init_table(sgout, template[i].np);
			for (k = 0; k < template[i].np; k++) {
				if (WARN_ON(offset_in_page(IDX[k]) +
					    template[i].tap[k] > PAGE_SIZE))
					goto out;

				q = xbuf[IDX[k] >> PAGE_SHIFT] +
				    offset_in_page(IDX[k]);