Add qemu 2.4.0
[kvmfornfv.git] / qemu / crypto / cipher-gcrypt.c
1 /*
2  * QEMU Crypto cipher libgcrypt 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 <gcrypt.h>
22
23
24 bool qcrypto_cipher_supports(QCryptoCipherAlgorithm alg)
25 {
26     switch (alg) {
27     case QCRYPTO_CIPHER_ALG_DES_RFB:
28     case QCRYPTO_CIPHER_ALG_AES_128:
29     case QCRYPTO_CIPHER_ALG_AES_192:
30     case QCRYPTO_CIPHER_ALG_AES_256:
31         return true;
32     default:
33         return false;
34     }
35 }
36
37
38 QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgorithm alg,
39                                   QCryptoCipherMode mode,
40                                   const uint8_t *key, size_t nkey,
41                                   Error **errp)
42 {
43     QCryptoCipher *cipher;
44     gcry_cipher_hd_t handle;
45     gcry_error_t err;
46     int gcryalg, gcrymode;
47
48     switch (mode) {
49     case QCRYPTO_CIPHER_MODE_ECB:
50         gcrymode = GCRY_CIPHER_MODE_ECB;
51         break;
52     case QCRYPTO_CIPHER_MODE_CBC:
53         gcrymode = GCRY_CIPHER_MODE_CBC;
54         break;
55     default:
56         error_setg(errp, "Unsupported cipher mode %d", mode);
57         return NULL;
58     }
59
60     if (!qcrypto_cipher_validate_key_length(alg, nkey, errp)) {
61         return NULL;
62     }
63
64     switch (alg) {
65     case QCRYPTO_CIPHER_ALG_DES_RFB:
66         gcryalg = GCRY_CIPHER_DES;
67         break;
68
69     case QCRYPTO_CIPHER_ALG_AES_128:
70         gcryalg = GCRY_CIPHER_AES128;
71         break;
72
73     case QCRYPTO_CIPHER_ALG_AES_192:
74         gcryalg = GCRY_CIPHER_AES192;
75         break;
76
77     case QCRYPTO_CIPHER_ALG_AES_256:
78         gcryalg = GCRY_CIPHER_AES256;
79         break;
80
81     default:
82         error_setg(errp, "Unsupported cipher algorithm %d", alg);
83         return NULL;
84     }
85
86     cipher = g_new0(QCryptoCipher, 1);
87     cipher->alg = alg;
88     cipher->mode = mode;
89
90     err = gcry_cipher_open(&handle, gcryalg, gcrymode, 0);
91     if (err != 0) {
92         error_setg(errp, "Cannot initialize cipher: %s",
93                    gcry_strerror(err));
94         goto error;
95     }
96
97     if (cipher->alg == QCRYPTO_CIPHER_ALG_DES_RFB) {
98         /* We're using standard DES cipher from gcrypt, so we need
99          * to munge the key so that the results are the same as the
100          * bizarre RFB variant of DES :-)
101          */
102         uint8_t *rfbkey = qcrypto_cipher_munge_des_rfb_key(key, nkey);
103         err = gcry_cipher_setkey(handle, rfbkey, nkey);
104         g_free(rfbkey);
105     } else {
106         err = gcry_cipher_setkey(handle, key, nkey);
107     }
108     if (err != 0) {
109         error_setg(errp, "Cannot set key: %s",
110                    gcry_strerror(err));
111         goto error;
112     }
113
114     cipher->opaque = handle;
115     return cipher;
116
117  error:
118     gcry_cipher_close(handle);
119     g_free(cipher);
120     return NULL;
121 }
122
123
124 void qcrypto_cipher_free(QCryptoCipher *cipher)
125 {
126     gcry_cipher_hd_t handle;
127     if (!cipher) {
128         return;
129     }
130     handle = cipher->opaque;
131     gcry_cipher_close(handle);
132     g_free(cipher);
133 }
134
135
136 int qcrypto_cipher_encrypt(QCryptoCipher *cipher,
137                            const void *in,
138                            void *out,
139                            size_t len,
140                            Error **errp)
141 {
142     gcry_cipher_hd_t handle = cipher->opaque;
143     gcry_error_t err;
144
145     err = gcry_cipher_encrypt(handle,
146                               out, len,
147                               in, len);
148     if (err != 0) {
149         error_setg(errp, "Cannot encrypt data: %s",
150                    gcry_strerror(err));
151         return -1;
152     }
153
154     return 0;
155 }
156
157
158 int qcrypto_cipher_decrypt(QCryptoCipher *cipher,
159                            const void *in,
160                            void *out,
161                            size_t len,
162                            Error **errp)
163 {
164     gcry_cipher_hd_t handle = cipher->opaque;
165     gcry_error_t err;
166
167     err = gcry_cipher_decrypt(handle,
168                               out, len,
169                               in, len);
170     if (err != 0) {
171         error_setg(errp, "Cannot decrypt data: %s",
172                    gcry_strerror(err));
173         return -1;
174     }
175
176     return 0;
177 }
178
179 int qcrypto_cipher_setiv(QCryptoCipher *cipher,
180                          const uint8_t *iv, size_t niv,
181                          Error **errp)
182 {
183     gcry_cipher_hd_t handle = cipher->opaque;
184     gcry_error_t err;
185
186     gcry_cipher_reset(handle);
187     err = gcry_cipher_setiv(handle, iv, niv);
188     if (err != 0) {
189         error_setg(errp, "Cannot set IV: %s",
190                    gcry_strerror(err));
191         return -1;
192     }
193
194     return 0;
195 }