Variable key length crypters use default key length if zero given
[strongswan.git] / src / libstrongswan / plugins / padlock / padlock_aes_crypter.c
1 /*
2 * Copyright (C) 2008 Thomas Kallenberg
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #include "padlock_aes_crypter.h"
18 #include <stdio.h>
19
20 #define AES_BLOCK_SIZE 16
21 #define PADLOCK_ALIGN __attribute__ ((__aligned__(16)))
22
23 typedef struct private_padlock_aes_crypter_t private_padlock_aes_crypter_t;
24
25 /**
26 * Private data of padlock_aes_crypter_t
27 */
28 struct private_padlock_aes_crypter_t {
29
30 /**
31 * Public part of this class.
32 */
33 padlock_aes_crypter_t public;
34
35 /*
36 * the key
37 */
38 chunk_t key;
39 };
40
41 /**
42 * Control word structure to pass to crypt operations
43 */
44 typedef struct {
45 u_int __attribute__ ((__packed__))
46 rounds:4,
47 algo:3,
48 keygen:1,
49 interm:1,
50 encdec:1,
51 ksize:2;
52 /* microcode needs additional bytes for calculation */
53 u_char buf[124];
54 } cword;
55
56 /**
57 * Invoke the actual de/encryption
58 */
59 static void padlock_crypt(void *key, void *ctrl, void *src, void *dst,
60 int count, void *iv)
61 {
62 asm volatile(
63 "pushl %%eax\n pushl %%ebx\n pushl %%ecx\n"
64 "pushl %%edx\n pushl %%esi\n pushl %%edi\n"
65 "pushfl\n popfl\n"
66 "movl %0, %%eax\n"
67 "movl %1, %%ebx\n"
68 "movl %2, %%ecx\n"
69 "movl %3, %%edx\n"
70 "movl %4, %%esi\n"
71 "movl %5, %%edi\n"
72 "rep\n"
73 ".byte 0x0f, 0xa7, 0xd0\n"
74 "popl %%edi\n popl %%esi\n popl %%edx\n"
75 "popl %%ecx\n popl %%ebx\n popl %%eax\n"
76 :
77 : "m"(iv),"m"(key), "m"(count), "m"(ctrl), "m"(src), "m"(dst)
78 : "eax", "ecx", "edx", "esi", "edi");
79 }
80
81 /**
82 * Do encryption/decryption operation using Padlock control word
83 */
84 static void crypt(private_padlock_aes_crypter_t *this, char *iv,
85 chunk_t src, chunk_t *dst, bool enc)
86 {
87 cword cword PADLOCK_ALIGN;
88 u_char key_aligned[256] PADLOCK_ALIGN;
89 u_char iv_aligned[16] PADLOCK_ALIGN;
90
91 memset(&cword, 0, sizeof(cword));
92
93 /* set encryption/decryption flag */
94 cword.encdec = enc;
95 /* calculate rounds and key size */
96 cword.rounds = 10 + (this->key.len - 16) / 4;
97 cword.ksize = (this->key.len - 16) / 8;
98 /* enable autoalign */
99 cword.algo |= 2;
100
101 /* move data to aligned buffers */
102 memcpy(iv_aligned, iv, sizeof(iv_aligned));
103 memcpy(key_aligned, this->key.ptr, this->key.len);
104
105 *dst = chunk_alloc(src.len);
106 padlock_crypt(key_aligned, &cword, src.ptr, dst->ptr,
107 src.len / AES_BLOCK_SIZE, iv_aligned);
108 }
109
110 METHOD(crypter_t, decrypt, void,
111 private_padlock_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
112 {
113 crypt(this, iv.ptr, data, dst, TRUE);
114 }
115
116 METHOD(crypter_t, encrypt, void,
117 private_padlock_aes_crypter_t *this, chunk_t data, chunk_t iv, chunk_t *dst)
118 {
119 crypt(this, iv.ptr, data, dst, FALSE);
120 }
121
122 METHOD(crypter_t, get_block_size, size_t,
123 private_padlock_aes_crypter_t *this)
124 {
125 return AES_BLOCK_SIZE;
126 }
127
128 METHOD(crypter_t, get_iv_size, size_t,
129 private_padlock_aes_crypter_t *this)
130 {
131 return AES_BLOCK_SIZE;
132 }
133
134 METHOD(crypter_t, get_key_size, size_t,
135 private_padlock_aes_crypter_t *this)
136 {
137 return this->key.len;
138 }
139
140 METHOD(crypter_t, set_key, void,
141 private_padlock_aes_crypter_t *this, chunk_t key)
142 {
143 memcpy(this->key.ptr, key.ptr, min(key.len, this->key.len));
144 }
145
146 METHOD(crypter_t, destroy, void,
147 private_padlock_aes_crypter_t *this)
148 {
149 free(this->key.ptr);
150 free(this);
151 }
152
153 /*
154 * Described in header
155 */
156 padlock_aes_crypter_t *padlock_aes_crypter_create(encryption_algorithm_t algo,
157 size_t key_size)
158 {
159 private_padlock_aes_crypter_t *this;
160
161 if (algo != ENCR_AES_CBC)
162 {
163 return NULL;
164 }
165 switch (key_size)
166 {
167 case 0:
168 key_size = 16;
169 /* FALL */
170 case 16: /* AES 128 */
171 break;
172 case 24: /* AES-192 */
173 case 32: /* AES-256 */
174 /* These need an expanded key, currently not supported, FALL */
175 default:
176 return NULL;
177 }
178
179 INIT(this,
180 .public.crypter = {
181 .encrypt = _encrypt,
182 .decrypt = _decrypt,
183 .get_block_size = _get_block_size,
184 .get_iv_size = _get_iv_size,
185 .get_key_size = _get_key_size,
186 .set_key = _set_key,
187 .destroy = _destroy,
188 },
189 .key = chunk_alloc(key_size),
190 );
191 return &this->public;
192 }