crypto: add a nettle cipher implementation
[qemu.git] / crypto / cipher-nettle.c
1 /*
2 * QEMU Crypto cipher nettle algorithms
3 *
4 * Copyright (c) 2015 Red Hat, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 *
19 */
20
21 #include <nettle/nettle-types.h>
22 #include <nettle/aes.h>
23 #include <nettle/des.h>
24 #include <nettle/cbc.h>
25
26 typedef struct QCryptoCipherNettle QCryptoCipherNettle;
27 struct QCryptoCipherNettle {
28 void *ctx_encrypt;
29 void *ctx_decrypt;
30 nettle_crypt_func *alg_encrypt;
31 nettle_crypt_func *alg_decrypt;
32 uint8_t *iv;
33 size_t niv;
34 };
35
36 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
37 {
38 switch (alg) {
39 case QCRYPTO_CIPHER_ALG_DES_RFB:
40 case QCRYPTO_CIPHER_ALG_AES_128:
41 case QCRYPTO_CIPHER_ALG_AES_192:
42 case QCRYPTO_CIPHER_ALG_AES_256:
43 return true;
44 default:
45 return false;
46 }
47 }
48
49
50 QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
51 QCryptoCipherMode mode,
52 const uint8_t *key, size_t nkey,
53 Error **errp)
54 {
55 QCryptoCipher *cipher;
56 QCryptoCipherNettle *ctx;
57 uint8_t *rfbkey;
58
59 switch (mode) {
60 case QCRYPTO_CIPHER_MODE_ECB:
61 case QCRYPTO_CIPHER_MODE_CBC:
62 break;
63 default:
64 error_setg(errp, "Unsupported cipher mode %d", mode);
65 return NULL;
66 }
67
68 if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
69 return NULL;
70 }
71
72 cipher = g_new0(QCryptoCipher, 1);
73 cipher->alg = alg;
74 cipher->mode = mode;
75
76 ctx = g_new0(QCryptoCipherNettle, 1);
77
78 switch (alg) {
79 case QCRYPTO_CIPHER_ALG_DES_RFB:
80 ctx->ctx_encrypt = g_new0(struct des_ctx, 1);
81 ctx->ctx_decrypt = NULL; /* 1 ctx can do both */
82 rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
83 des_set_key(ctx->ctx_encrypt, rfbkey);
84 g_free(rfbkey);
85
86 ctx->alg_encrypt = (nettle_crypt_func *)des_encrypt;
87 ctx->alg_decrypt = (nettle_crypt_func *)des_decrypt;
88
89 ctx->niv = DES_BLOCK_SIZE;
90 break;
91
92 case QCRYPTO_CIPHER_ALG_AES_128:
93 case QCRYPTO_CIPHER_ALG_AES_192:
94 case QCRYPTO_CIPHER_ALG_AES_256:
95 ctx->ctx_encrypt = g_new0(struct aes_ctx, 1);
96 ctx->ctx_decrypt = g_new0(struct aes_ctx, 1);
97
98 aes_set_encrypt_key(ctx->ctx_encrypt, nkey, key);
99 aes_set_decrypt_key(ctx->ctx_decrypt, nkey, key);
100
101 ctx->alg_encrypt = (nettle_crypt_func *)aes_encrypt;
102 ctx->alg_decrypt = (nettle_crypt_func *)aes_decrypt;
103
104 ctx->niv = AES_BLOCK_SIZE;
105 break;
106 default:
107 error_setg(errp, "Unsupported cipher algorithm %d", alg);
108 goto error;
109 }
110
111 ctx->iv = g_new0(uint8_t, ctx->niv);
112 cipher->opaque = ctx;
113
114 return cipher;
115
116 error:
117 g_free(cipher);
118 g_free(ctx);
119 return NULL;
120 }
121
122
123 void qcrypto_cipher_free(QCryptoCipher *cipher)
124 {
125 QCryptoCipherNettle *ctx;
126
127 if (!cipher) {
128 return;
129 }
130
131 ctx = cipher->opaque;
132 g_free(ctx->iv);
133 g_free(ctx->ctx_encrypt);
134 g_free(ctx->ctx_decrypt);
135 g_free(ctx);
136 g_free(cipher);
137 }
138
139
140 int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
141 const void *in,
142 void *out,
143 size_t len,
144 Error **errp)
145 {
146 QCryptoCipherNettle *ctx = cipher->opaque;
147
148 switch (cipher->mode) {
149 case QCRYPTO_CIPHER_MODE_ECB:
150 ctx->alg_encrypt(ctx->ctx_encrypt, len, out, in);
151 break;
152
153 case QCRYPTO_CIPHER_MODE_CBC:
154 cbc_encrypt(ctx->ctx_encrypt, ctx->alg_encrypt,
155 ctx->niv, ctx->iv,
156 len, out, in);
157 break;
158 default:
159 error_setg(errp, "Unsupported cipher algorithm %d",
160 cipher->alg);
161 return -1;
162 }
163 return 0;
164 }
165
166
167 int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
168 const void *in,
169 void *out,
170 size_t len,
171 Error **errp)
172 {
173 QCryptoCipherNettle *ctx = cipher->opaque;
174
175 switch (cipher->mode) {
176 case QCRYPTO_CIPHER_MODE_ECB:
177 ctx->alg_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
178 len, out, in);
179 break;
180
181 case QCRYPTO_CIPHER_MODE_CBC:
182 cbc_decrypt(ctx->ctx_decrypt ? ctx->ctx_decrypt : ctx->ctx_encrypt,
183 ctx->alg_decrypt, ctx->niv, ctx->iv,
184 len, out, in);
185 break;
186 default:
187 error_setg(errp, "Unsupported cipher algorithm %d",
188 cipher->alg);
189 return -1;
190 }
191 return 0;
192 }
193
194 int qcrypto_cipher_setiv(QCryptoCipher *cipher,
195 const uint8_t *iv, size_t niv,
196 Error **errp)
197 {
198 QCryptoCipherNettle *ctx = cipher->opaque;
199 if (niv != ctx->niv) {
200 error_setg(errp, "Expected IV size %zu not %zu",
201 ctx->niv, niv);
202 return -1;
203 }
204 memcpy(ctx->iv, iv, niv);
205 return 0;
206 }