xref: /openbmc/qemu/crypto/cipher.c (revision dd2bf9eb)
1 /*
2  * QEMU Crypto cipher 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 "crypto/cipher.h"
22 
23 
24 static size_t alg_key_len[QCRYPTO_CIPHER_ALG_LAST] = {
25     [QCRYPTO_CIPHER_ALG_AES_128] = 16,
26     [QCRYPTO_CIPHER_ALG_AES_192] = 24,
27     [QCRYPTO_CIPHER_ALG_AES_256] = 32,
28     [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
29 };
30 
31 static size_t alg_block_len[QCRYPTO_CIPHER_ALG_LAST] = {
32     [QCRYPTO_CIPHER_ALG_AES_128] = 16,
33     [QCRYPTO_CIPHER_ALG_AES_192] = 16,
34     [QCRYPTO_CIPHER_ALG_AES_256] = 16,
35     [QCRYPTO_CIPHER_ALG_DES_RFB] = 8,
36 };
37 
38 static bool mode_need_iv[QCRYPTO_CIPHER_MODE_LAST] = {
39     [QCRYPTO_CIPHER_MODE_ECB] = false,
40     [QCRYPTO_CIPHER_MODE_CBC] = true,
41 };
42 
43 
44 size_t qcrypto_cipher_get_block_len(QCryptoCipherAlgorithm alg)
45 {
46     if (alg >= G_N_ELEMENTS(alg_key_len)) {
47         return 0;
48     }
49     return alg_block_len[alg];
50 }
51 
52 
53 size_t qcrypto_cipher_get_key_len(QCryptoCipherAlgorithm alg)
54 {
55     if (alg >= G_N_ELEMENTS(alg_key_len)) {
56         return 0;
57     }
58     return alg_key_len[alg];
59 }
60 
61 
62 size_t qcrypto_cipher_get_iv_len(QCryptoCipherAlgorithm alg,
63                                  QCryptoCipherMode mode)
64 {
65     if (alg >= G_N_ELEMENTS(alg_block_len)) {
66         return 0;
67     }
68     if (mode >= G_N_ELEMENTS(mode_need_iv)) {
69         return 0;
70     }
71 
72     if (mode_need_iv[mode]) {
73         return alg_block_len[alg];
74     }
75     return 0;
76 }
77 
78 
79 static bool
80 qcrypto_cipher_validate_key_length(QCryptoCipherAlgorithm alg,
81                                    size_t nkey,
82                                    Error **errp)
83 {
84     if ((unsigned)alg >= QCRYPTO_CIPHER_ALG_LAST) {
85         error_setg(errp, "Cipher algorithm %d out of range",
86                    alg);
87         return false;
88     }
89 
90     if (alg_key_len[alg] != nkey) {
91         error_setg(errp, "Cipher key length %zu should be %zu",
92                    alg_key_len[alg], nkey);
93         return false;
94     }
95     return true;
96 }
97 
98 #if defined(CONFIG_GCRYPT) || defined(CONFIG_NETTLE)
99 static uint8_t *
100 qcrypto_cipher_munge_des_rfb_key(const uint8_t *key,
101                                  size_t nkey)
102 {
103     uint8_t *ret = g_new0(uint8_t, nkey);
104     size_t i;
105     for (i = 0; i < nkey; i++) {
106         uint8_t r = key[i];
107         r = (r & 0xf0) >> 4 | (r & 0x0f) << 4;
108         r = (r & 0xcc) >> 2 | (r & 0x33) << 2;
109         r = (r & 0xaa) >> 1 | (r & 0x55) << 1;
110         ret[i] = r;
111     }
112     return ret;
113 }
114 #endif /* CONFIG_GCRYPT || CONFIG_NETTLE */
115 
116 #ifdef CONFIG_GCRYPT
117 #include "crypto/cipher-gcrypt.c"
118 #elif defined CONFIG_NETTLE
119 #include "crypto/cipher-nettle.c"
120 #else
121 #include "crypto/cipher-builtin.c"
122 #endif
123