pivot table procedure conceptually works
[pspp] / src / data / sys-file-encryption.c
1 /* PSPP - a program for statistical analysis.
2    Copyright (C) 2013 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation, either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>. */
16
17 #include <config.h>
18
19 #include "data/sys-file-encryption.h"
20
21 #include <errno.h>
22 #include <stdlib.h>
23
24 #include "data/file-name.h"
25 #include "libpspp/assertion.h"
26 #include "libpspp/cast.h"
27 #include "libpspp/cmac-aes256.h"
28 #include "libpspp/message.h"
29
30 #include "gl/minmax.h"
31 #include "gl/rijndael-alg-fst.h"
32 #include "gl/xalloc.h"
33
34 #include "gettext.h"
35 #define _(msgid) gettext (msgid)
36
37 struct encrypted_sys_file
38   {
39     FILE *file;
40     int error;
41
42     uint8_t ciphertext[16];
43     uint8_t plaintext[16];
44     unsigned int n;
45
46     uint32_t rk[4 * (RIJNDAEL_MAXNR + 1)];
47     int Nr;
48   };
49
50 static bool try_password(struct encrypted_sys_file *, const char *password);
51 static bool decode_password (const char *input, char output[11]);
52 static bool fill_buffer (struct encrypted_sys_file *);
53
54 /* If FILENAME names an encrypted system file, returns 1 and initializes *FP
55    for further use by the caller.
56
57    If FILENAME can be opened and read, but is not an encrypted system file,
58    returns 0.
59
60    If FILENAME cannot be open or read, returns a negative errno value. */
61 int
62 encrypted_sys_file_open (struct encrypted_sys_file **fp, const char *filename)
63 {
64   struct encrypted_sys_file *f;
65   char header[36 + 16];
66   int retval;
67   int n;
68
69   f = xmalloc (sizeof *f);
70   f->error = 0;
71   f->file = fn_open (filename, "rb");
72   if (f->file == NULL)
73     {
74       msg (ME, _("An error occurred while opening `%s': %s."),
75            filename, strerror (errno));
76       retval = -errno;
77       goto error;
78     }
79
80   n = fread (header, 1, sizeof header, f->file);
81   if (n != sizeof header)
82     {
83       int error = feof (f->file) ? 0 : errno;
84       if (error)
85         msg (ME, _("An error occurred while reading `%s': %s."),
86              filename, strerror (error));
87       retval = -error;
88       goto error;
89     }
90
91   if (memcmp (header + 8, "ENCRYPTEDSAV", 12))
92     {
93       retval = 0;
94       goto error;
95     }
96
97   memcpy (f->ciphertext, header + 36, 16);
98   f->n = 16;
99   *fp = f;
100   return 1;
101
102 error:
103   if (f->file)
104     fn_close (filename, f->file);
105   free (f);
106   *fp = NULL;
107
108   return retval;
109 }
110
111 /* Attempts to use PASSWORD, which may be a plaintext or "encrypted" password,
112    to unlock F.  Returns true if successful, otherwise false. */
113 bool
114 encrypted_sys_file_unlock (struct encrypted_sys_file *f, const char *password)
115 {
116   char decoded_password[11];
117
118   return (try_password (f, password)
119           || (decode_password (password, decoded_password)
120               && try_password (f, decoded_password)));
121 }
122
123 /* Attempts to read N bytes of plaintext from F into BUF.  Returns the number
124    of bytes successfully read.  A return value less than N may indicate end of
125    file or an error; use encrypted_sys_file_close() to distinguish.
126
127    This function can only be used after encrypted_sys_file_unlock() returns
128    true. */
129 size_t
130 encrypted_sys_file_read (struct encrypted_sys_file *f, void *buf_, size_t n)
131 {
132   uint8_t *buf = buf_;
133   size_t ofs = 0;
134
135   if (f->error)
136     return 0;
137
138   while (ofs < n)
139     {
140       unsigned int chunk = MIN (n - ofs, f->n);
141       if (chunk > 0)
142         {
143           memcpy (buf + ofs, &f->plaintext[16 - f->n], chunk);
144           ofs += chunk;
145           f->n -= chunk;
146         }
147       else
148         {
149           if (!fill_buffer (f))
150             return ofs;
151         }
152     }
153
154   return ofs;
155 }
156
157 /* Closes F.  Returns 0 if no read errors occurred, otherwise a positive errno
158    value. */
159 int
160 encrypted_sys_file_close (struct encrypted_sys_file *f)
161 {
162   int error = f->error;
163   if (fclose (f->file) == EOF && !error)
164     error = errno;
165   free (f);
166
167   return error;
168 }
169 \f
170 #define b(x) (1 << (x))
171
172 static const uint16_t m0[4][2] = {
173   { b(2),                         b(2) | b(3) | b(6) | b(7) },
174   { b(3),                         b(0) | b(1) | b(4) | b(5) },
175   { b(4) | b(7),                  b(8) | b(9) | b(12) | b(14) },
176   { b(5) | b(6),                  b(10) | b(11) | b(14) | b(15) },
177 };
178
179 static const uint16_t m1[4][2] = {
180   { b(0) | b(3) | b(12) | b(15),  b(0) | b(1) | b(4) | b(5) },
181   { b(1) | b(2) | b(13) | b(14),  b(2) | b(3) | b(6) | b(7) },
182   { b(4) | b(7) | b(8) | b(11),   b(8) | b(9) | b(12) | b(13) },
183   { b(5) | b(6) | b(9) | b(10),   b(10) | b(11) | b(14) | b(15) },
184 };
185
186 static const uint16_t m2[4][2] = {
187   { b(2),                         b(1) | b(3) | b(9) | b(11) },
188   { b(3),                         b(0) | b(2) | b(8) | b(10) },
189   { b(4) | b(7),                  b(4) | b(6) | b(12) | b(14) },
190   { b(5) | b(6),                  b(5) | b(7) | b(13) | b(15) },
191 };
192
193 static const uint16_t m3[4][2] = {
194   { b(0) | b(3) | b(12) | b(15),  b(0) | b(2) | b(8) | b(10) },
195   { b(1) | b(2) | b(13) | b(14),  b(1) | b(3) | b(9) | b(11) },
196   { b(4) | b(7) | b(8) | b(11),   b(4) | b(6) | b(12) | b(14) },
197   { b(5) | b(6) | b(9) | b(10),   b(5) | b(7) | b(13) | b(15) },
198 };
199
200 static int
201 decode_nibble (const uint16_t table[4][2], int nibble)
202 {
203   int i;
204
205   for (i = 0; i < 4; i++)
206     if (table[i][0] & (1 << nibble))
207       return table[i][1];
208
209   return 0;
210 }
211
212 /* Returns true if X has exactly one 1-bit, false otherwise. */
213 static bool
214 is_pow2 (int x)
215 {
216   return x && (x & (x - 1)) == 0;
217 }
218
219 /* If X has exactly one 1-bit, returns its index, where bit 0 is the LSB.
220    Otherwise, returns 0. */
221 static int
222 find_1bit (uint16_t x)
223 {
224   int i;
225
226   if (!is_pow2 (x))
227     return -1;
228
229   for (i = 0; i < 16; i++)
230     if (x & (1u << i))
231       return i;
232
233   abort ();
234 }
235
236 /* Attempts to decode a pair of encoded password characters A and B into a
237    single byte of the plaintext password.  Returns 0 if A and B are not a valid
238    encoded password pair, otherwise a byte of the plaintext password. */
239 static int
240 decode_password_2bytes (uint8_t a, uint8_t b)
241 {
242   int x = find_1bit (decode_nibble (m0, a >> 4) & decode_nibble (m2, b >> 4));
243   int y = find_1bit (decode_nibble (m1, a & 15) & decode_nibble (m3, b & 15));
244   return x < 0 || y < 0 ? 0 : (x << 4) | y;
245 }
246
247 /* Decodes an SPSS so-called "encrypted" password INPUT into OUTPUT.
248
249    An encoded password is always an even number of bytes long and no longer
250    than 20 bytes.  A decoded password is never longer than 10 bytes plus a null
251    terminator.
252
253    Returns true if successful, otherwise false. */
254 static bool
255 decode_password (const char *input, char output[11])
256 {
257   size_t len;
258
259   len = strlen (input);
260   if (len > 20 || len % 2)
261     return false;
262
263   for (; *input; input += 2)
264     {
265       int c = decode_password_2bytes (input[0], input[1]);
266       if (!c)
267         return false;
268       *output++ = c;
269     }
270   *output = '\0';
271
272   return true;
273 }
274
275 /* If CIPHERTEXT is the first ciphertext block in an encrypted .sav file for
276    PASSWORD, initializes rk[] and returns an nonzero Nr value.
277
278    Otherwise, returns zero. */
279 static bool
280 try_password(struct encrypted_sys_file *f, const char *password)
281 {
282   /* NIST SP 800-108 fixed data. */
283   static const uint8_t fixed[] = {
284     /* i */
285     0x00, 0x00, 0x00, 0x01,
286
287     /* label */
288     0x35, 0x27, 0x13, 0xcc, 0x53, 0xa7, 0x78, 0x89,
289     0x87, 0x53, 0x22, 0x11, 0xd6, 0x5b, 0x31, 0x58,
290     0xdc, 0xfe, 0x2e, 0x7e, 0x94, 0xda, 0x2f, 0x00,
291     0xcc, 0x15, 0x71, 0x80, 0x0a, 0x6c, 0x63, 0x53,
292
293     /* delimiter */
294     0x00,
295
296     /* context */
297     0x38, 0xc3, 0x38, 0xac, 0x22, 0xf3, 0x63, 0x62,
298     0x0e, 0xce, 0x85, 0x3f, 0xb8, 0x07, 0x4c, 0x4e,
299     0x2b, 0x77, 0xc7, 0x21, 0xf5, 0x1a, 0x80, 0x1d,
300     0x67, 0xfb, 0xe1, 0xe1, 0x83, 0x07, 0xd8, 0x0d,
301
302     /* L */
303     0x00, 0x00, 0x01, 0x00,
304   };
305
306   char padded_password[32];
307   size_t password_len;
308   uint8_t cmac[16];
309   uint8_t key[32];
310
311   /* Truncate password to at most 10 bytes. */
312   password_len = strlen (password);
313   if (password_len > 10)
314     password_len = 10;
315
316   /* padded_password = password padded with zeros to 32 bytes. */
317   memset (padded_password, 0, sizeof padded_password);
318   memcpy (padded_password, password, password_len);
319
320   /* cmac = CMAC(padded_password, fixed). */
321   cmac_aes256 (CHAR_CAST (const uint8_t *, padded_password),
322                fixed, sizeof fixed, cmac);
323
324   /* The key is the cmac repeated twice. */
325   memcpy(key, cmac, 16);
326   memcpy(key + 16, cmac, 16);
327
328   /* Use key to initialize AES. */
329   assert (sizeof key == 32);
330   f->Nr = rijndaelKeySetupDec (f->rk, CHAR_CAST (const char *, key), 256);
331
332   /* Check for magic number "$FL" always present in SPSS .sav file. */
333   rijndaelDecrypt (f->rk, f->Nr,
334                    CHAR_CAST (const char *, f->ciphertext),
335                    CHAR_CAST (char *, f->plaintext));
336   return !memcmp (f->plaintext, "$FL", 3);
337 }
338
339 static bool
340 fill_buffer (struct encrypted_sys_file *f)
341 {
342   f->n = fread (f->ciphertext, 1, sizeof f->ciphertext, f->file);
343   if (f->n == sizeof f->ciphertext)
344     {
345       rijndaelDecrypt (f->rk, f->Nr,
346                        CHAR_CAST (const char *, f->ciphertext),
347                        CHAR_CAST (char *, f->plaintext));
348       return true;
349     }
350   else
351     {
352       if (ferror (f->file))
353         f->error = errno;
354       return false;
355     }
356 }