]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - sys/geom/eli/g_eli_key.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / sys / geom / eli / g_eli_key.c
1 /*-
2  * Copyright (c) 2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/param.h>
31 #ifdef _KERNEL
32 #include <sys/malloc.h>
33 #include <sys/systm.h>
34 #include <geom/geom.h>
35 #else
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <strings.h>
41 #include <errno.h>
42 #endif
43
44 #include <geom/eli/g_eli.h>
45
46
47 /*
48  * Verify if the given 'key' is correct.
49  * Return 1 if it is correct and 0 otherwise.
50  */
51 static int
52 g_eli_mkey_verify(const unsigned char *mkey, const unsigned char *key)
53 {
54         const unsigned char *odhmac;    /* On-disk HMAC. */
55         unsigned char chmac[SHA512_MDLEN];      /* Calculated HMAC. */
56         unsigned char hmkey[SHA512_MDLEN];      /* Key for HMAC. */
57
58         /*
59          * The key for HMAC calculations is: hmkey = HMAC_SHA512(Derived-Key, 0)
60          */
61         g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x00", 1, hmkey, 0);
62
63         odhmac = mkey + G_ELI_DATAIVKEYLEN;
64
65         /* Calculate HMAC from Data-Key and IV-Key. */
66         g_eli_crypto_hmac(hmkey, sizeof(hmkey), mkey, G_ELI_DATAIVKEYLEN,
67             chmac, 0);
68
69         bzero(hmkey, sizeof(hmkey));
70
71         /*
72          * Compare calculated HMAC with HMAC from metadata.
73          * If two HMACs are equal, 'key' is correct.
74          */
75         return (!bcmp(odhmac, chmac, SHA512_MDLEN));
76 }
77
78 /*
79  * Calculate HMAC from Data-Key and IV-Key.
80  */
81 void
82 g_eli_mkey_hmac(unsigned char *mkey, const unsigned char *key)
83 {
84         unsigned char hmkey[SHA512_MDLEN];      /* Key for HMAC. */
85         unsigned char *odhmac;  /* On-disk HMAC. */
86
87         /*
88          * The key for HMAC calculations is: hmkey = HMAC_SHA512(Derived-Key, 0)
89          */
90         g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x00", 1, hmkey, 0);
91
92         odhmac = mkey + G_ELI_DATAIVKEYLEN;
93         /* Calculate HMAC from Data-Key and IV-Key. */
94         g_eli_crypto_hmac(hmkey, sizeof(hmkey), mkey, G_ELI_DATAIVKEYLEN,
95             odhmac, 0);
96
97         bzero(hmkey, sizeof(hmkey));
98 }
99
100 /*
101  * Find and decrypt Master Key encrypted with 'key'.
102  * Return decrypted Master Key number in 'nkeyp' if not NULL.
103  * Return 0 on success, > 0 on failure, -1 on bad key.
104  */
105 int
106 g_eli_mkey_decrypt(const struct g_eli_metadata *md, const unsigned char *key,
107     unsigned char *mkey, unsigned *nkeyp)
108 {
109         unsigned char tmpmkey[G_ELI_MKEYLEN];
110         unsigned char enckey[SHA512_MDLEN];     /* Key for encryption. */
111         const unsigned char *mmkey;
112         int bit, error, nkey;
113
114         if (nkeyp != NULL)
115                 *nkeyp = -1;
116
117         /*
118          * The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1)
119          */
120         g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0);
121
122         mmkey = md->md_mkeys;
123         nkey = 0;
124         for (nkey = 0; nkey < G_ELI_MAXMKEYS; nkey++, mmkey += G_ELI_MKEYLEN) {
125                 bit = (1 << nkey);
126                 if (!(md->md_keys & bit))
127                         continue;
128                 bcopy(mmkey, tmpmkey, G_ELI_MKEYLEN);
129                 error = g_eli_crypto_decrypt(md->md_ealgo, tmpmkey,
130                     G_ELI_MKEYLEN, enckey, md->md_keylen);
131                 if (error != 0) {
132                         bzero(tmpmkey, sizeof(tmpmkey));
133                         bzero(enckey, sizeof(enckey));
134                         return (error);
135                 }
136                 if (g_eli_mkey_verify(tmpmkey, key)) {
137                         bcopy(tmpmkey, mkey, G_ELI_DATAIVKEYLEN);
138                         bzero(tmpmkey, sizeof(tmpmkey));
139                         bzero(enckey, sizeof(enckey));
140                         if (nkeyp != NULL)
141                                 *nkeyp = nkey;
142                         return (0);
143                 }
144         }
145         bzero(enckey, sizeof(enckey));
146         bzero(tmpmkey, sizeof(tmpmkey));
147         return (-1);
148 }
149
150 /*
151  * Encrypt the Master-Key and calculate HMAC to be able to verify it in the
152  * future.
153  */
154 int
155 g_eli_mkey_encrypt(unsigned algo, const unsigned char *key, unsigned keylen,
156     unsigned char *mkey)
157 {
158         unsigned char enckey[SHA512_MDLEN];     /* Key for encryption. */
159         int error;
160
161         /*
162          * To calculate HMAC, the whole key (G_ELI_USERKEYLEN bytes long) will
163          * be used.
164          */
165         g_eli_mkey_hmac(mkey, key);
166         /*
167          * The key for encryption is: enckey = HMAC_SHA512(Derived-Key, 1)
168          */
169         g_eli_crypto_hmac(key, G_ELI_USERKEYLEN, "\x01", 1, enckey, 0);
170         /*
171          * Encrypt the Master-Key and HMAC() result with the given key (this
172          * time only 'keylen' bits from the key are used).
173          */
174         error = g_eli_crypto_encrypt(algo, mkey, G_ELI_MKEYLEN, enckey, keylen);
175
176         bzero(enckey, sizeof(enckey));
177
178         return (error);
179 }
180
181 #ifdef _KERNEL
182 /*
183  * When doing encryption only, copy IV key and encryption key.
184  * When doing encryption and authentication, copy IV key, generate encryption
185  * key and generate authentication key.
186  */
187 void
188 g_eli_mkey_propagate(struct g_eli_softc *sc, const unsigned char *mkey)
189 {
190
191         /* Remember the Master Key. */
192         bcopy(mkey, sc->sc_mkey, sizeof(sc->sc_mkey));
193
194         bcopy(mkey, sc->sc_ivkey, sizeof(sc->sc_ivkey));
195         mkey += sizeof(sc->sc_ivkey);
196
197         if (!(sc->sc_flags & G_ELI_FLAG_AUTH)) {
198                 bcopy(mkey, sc->sc_ekey, sizeof(sc->sc_ekey));
199         } else {
200                 /*
201                  * The encryption key is: ekey = HMAC_SHA512(Master-Key, 0x10)
202                  * The authentication key is: akey = HMAC_SHA512(Master-Key, 0x11)
203                  */
204                 g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x10", 1, sc->sc_ekey, 0);
205                 g_eli_crypto_hmac(mkey, G_ELI_MAXKEYLEN, "\x11", 1, sc->sc_akey, 0);
206         }
207
208 }
209 #endif