summaryrefslogtreecommitdiffstats
path: root/crypto/ecb.c
blob: de839129d151c0dcf20048cc13aea731281d9960 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
/*
 * ECB: Electronic CodeBook mode
 *
 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
 *
 * 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/algapi.h>
#include <crypto/internal/skcipher.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>

static int crypto_ecb_crypt(struct skcipher_request *req,
			    struct crypto_cipher *cipher,
			    void (*fn)(struct crypto_tfm *, u8 *, const u8 *))
{
	const unsigned int bsize = crypto_cipher_blocksize(cipher);
	struct skcipher_walk walk;
	unsigned int nbytes;
	int err;

	err = skcipher_walk_virt(&walk, req, false);

	while ((nbytes = walk.nbytes) != 0) {
		const u8 *src = walk.src.virt.addr;
		u8 *dst = walk.dst.virt.addr;

		do {
			fn(crypto_cipher_tfm(cipher), dst, src);

			src += bsize;
			dst += bsize;
		} while ((nbytes -= bsize) >= bsize);

		err = skcipher_walk_done(&walk, nbytes);
	}

	return err;
}

static int crypto_ecb_encrypt(struct skcipher_request *req)
{
	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
	struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);

	return crypto_ecb_crypt(req, cipher,
				crypto_cipher_alg(cipher)->cia_encrypt);
}

static int crypto_ecb_decrypt(struct skcipher_request *req)
{
	struct crypto_skcipher *tfm = crypto_skcipher_reqtfm(req);
	struct crypto_cipher *cipher = skcipher_cipher_simple(tfm);

	return crypto_ecb_crypt(req, cipher,
				crypto_cipher_alg(cipher)->cia_decrypt);
}

static int crypto_ecb_create(struct crypto_template *tmpl, struct rtattr **tb)
{
	struct skcipher_instance *inst;
	struct crypto_alg *alg;
	int err;

	inst = skcipher_alloc_instance_simple(tmpl, tb, &alg);
	if (IS_ERR(inst))
		return PTR_ERR(inst);

	inst->alg.ivsize = 0; /* ECB mode doesn't take an IV */

	inst->alg.encrypt = crypto_ecb_encrypt;
	inst->alg.decrypt = crypto_ecb_decrypt;

	err = skcipher_register_instance(tmpl, inst);
	if (err)
		inst->free(inst);
	crypto_mod_put(alg);
	return err;
}

static struct crypto_template crypto_ecb_tmpl = {
	.name = "ecb",
	.create = crypto_ecb_create,
	.module = THIS_MODULE,
};

static int __init crypto_ecb_module_init(void)
{
	return crypto_register_template(&crypto_ecb_tmpl);
}

static void __exit crypto_ecb_module_exit(void)
{
	crypto_unregister_template(&crypto_ecb_tmpl);
}

subsys_initcall(crypto_ecb_module_init);
module_exit(crypto_ecb_module_exit);

MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("ECB block cipher mode of operation");
MODULE_ALIAS_CRYPTO("ecb");
ts = (ts & ~7) + 8; else ts++; } last_ts = ts; if (first_ts) { if (ts < first_ts) { zconf_endhelp(); return T_HELPTEXT; } ts -= first_ts; while (ts > 8) { append_string(" ", 8); ts -= 8; } append_string(" ", ts); } } [ \t]*\n/[^ \t\n] { zconf_endhelp(); return T_HELPTEXT; } [ \t]*\n { append_string("\n", 1); } [^ \t\n].* { while (yyleng) { if ((yytext[yyleng-1] != ' ') && (yytext[yyleng-1] != '\t')) break; yyleng--; } append_string(yytext, yyleng); if (!first_ts) first_ts = last_ts; } <<EOF>> { zconf_endhelp(); return T_HELPTEXT; } } <<EOF>> { BEGIN(INITIAL); if (prev_token != T_EOL && prev_token != T_HELPTEXT) fprintf(stderr, "%s:%d:warning: no new line at end of file\n", current_file->name, yylineno); if (current_file) { zconf_endfile(); return T_EOL; } fclose(yyin); yyterminate(); } %% /* second stage lexer */ int yylex(void) { int token; repeat: token = yylex1(); if (prev_token == T_EOL || prev_token == T_HELPTEXT) { if (token == T_EOL) { /* Do not pass unneeded T_EOL to the parser. */ goto repeat; } else { /* * For the parser, update file/lineno at the first token * of each statement. Generally, \n is a statement * terminator in Kconfig, but it is not always true * because \n could be escaped by a backslash. */ current_pos.file = current_file; current_pos.lineno = yylineno; } } if (prev_prev_token == T_EOL && prev_token == T_WORD && (token == T_EQUAL || token == T_COLON_EQUAL || token == T_PLUS_EQUAL)) BEGIN(ASSIGN_VAL); prev_prev_token = prev_token; prev_token = token; return token; } static char *expand_token(const char *in, size_t n) { char *out; int c; char c2; const char *rest, *end; new_string(); append_string(in, n); /* get the whole line because we do not know the end of token. */ while ((c = input()) != EOF) { if (c == '\n') { unput(c); break; } c2 = c; append_string(&c2, 1); } rest = text; out = expand_one_token(&rest); /* push back unused characters to the input stream */ end = rest + strlen(rest); while (end > rest) unput(*--end); free(text); return out; } static void append_expanded_string(const char *str) { const char *end; char *res; str++; res = expand_dollar(&str); /* push back unused characters to the input stream */ end = str + strlen(str); while (end > str) unput(*--end); append_string(res, strlen(res)); free(res); } void zconf_starthelp(void) { new_string(); last_ts = first_ts = 0; BEGIN(HELP); } static void zconf_endhelp(void) { yylval.string = text; BEGIN(INITIAL); } /* * Try to open specified file with following names: * ./name * $(srctree)/name * The latter is used when srctree is separate from objtree * when compiling the kernel. * Return NULL if file is not found. */ FILE *zconf_fopen(const char *name) { char *env, fullname[PATH_MAX+1]; FILE *f; f = fopen(name, "r"); if (!f && name != NULL && name[0] != '/') { env = getenv(SRCTREE); if (env) { snprintf(fullname, sizeof(fullname), "%s/%s", env, name); f = fopen(fullname, "r"); } } return f; } void zconf_initscan(const char *name) { yyin = zconf_fopen(name); if (!yyin) { fprintf(stderr, "can't find file %s\n", name); exit(1); } current_buf = xmalloc(sizeof(*current_buf)); memset(current_buf, 0, sizeof(*current_buf)); current_file = file_lookup(name); yylineno = 1; } void zconf_nextfile(const char *name) { struct file *iter; struct file *file = file_lookup(name); struct buffer *buf = xmalloc(sizeof(*buf)); memset(buf, 0, sizeof(*buf)); current_buf->state = YY_CURRENT_BUFFER; yyin = zconf_fopen(file->name); if (!yyin) { fprintf(stderr, "%s:%d: can't open file \"%s\"\n", zconf_curname(), zconf_lineno(), file->name); exit(1); } yy_switch_to_buffer(yy_create_buffer(yyin, YY_BUF_SIZE)); buf->parent = current_buf; current_buf = buf; current_file->lineno = yylineno; file->parent = current_file; for (iter = current_file; iter; iter = iter->parent) { if (!strcmp(iter->name, file->name)) { fprintf(stderr, "Recursive inclusion detected.\n" "Inclusion path:\n" " current file : %s\n", file->name); iter = file; do { iter = iter->parent; fprintf(stderr, " included from: %s:%d\n", iter->name, iter->lineno - 1); } while (strcmp(iter->name, file->name)); exit(1); } } yylineno = 1; current_file = file; } static void zconf_endfile(void) { struct buffer *parent; current_file = current_file->parent; if (current_file) yylineno = current_file->lineno; parent = current_buf->parent; if (parent) { fclose(yyin); yy_delete_buffer(YY_CURRENT_BUFFER); yy_switch_to_buffer(parent->state); } free(current_buf); current_buf = parent; } int zconf_lineno(void) { return current_pos.lineno; } const char *zconf_curname(void) { return current_pos.file ? current_pos.file->name : "<none>"; }