1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2013 Free Software Foundation, Inc.
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.
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.
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/>. */
19 #include "data/sys-file-encryption.h"
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"
30 #include "gl/minmax.h"
31 #include "gl/rijndael-alg-fst.h"
32 #include "gl/xalloc.h"
35 #define _(msgid) gettext (msgid)
37 struct encrypted_sys_file
42 uint8_t ciphertext[16];
43 uint8_t plaintext[16];
46 uint32_t rk[4 * (RIJNDAEL_MAXNR + 1)];
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 *);
54 /* If FILENAME names an encrypted system file, returns 1 and initializes *FP
55 for further use by the caller.
57 If FILENAME can be opened and read, but is not an encrypted system file,
60 If FILENAME cannot be open or read, returns a negative errno value. */
62 encrypted_sys_file_open (struct encrypted_sys_file **fp, const char *filename)
64 struct encrypted_sys_file *f;
69 f = xmalloc (sizeof *f);
71 f->file = fn_open (filename, "rb");
74 msg (ME, _("An error occurred while opening `%s': %s."),
75 filename, strerror (errno));
80 n = fread (header, 1, sizeof header, f->file);
81 if (n != sizeof header)
83 int error = feof (f->file) ? 0 : errno;
85 msg (ME, _("An error occurred while reading `%s': %s."),
86 filename, strerror (error));
91 if (memcmp (header + 8, "ENCRYPTEDSAV", 12))
97 memcpy (f->ciphertext, header + 36, 16);
104 fn_close (filename, f->file);
111 /* Attempts to use PASSWORD, which may be a plaintext or "encrypted" password,
112 to unlock F. Returns true if successful, otherwise false. */
114 encrypted_sys_file_unlock (struct encrypted_sys_file *f, const char *password)
116 char decoded_password[11];
118 return (try_password (f, password)
119 || (decode_password (password, decoded_password)
120 && try_password (f, decoded_password)));
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.
127 This function can only be used after encrypted_sys_file_unlock() returns
130 encrypted_sys_file_read (struct encrypted_sys_file *f, void *buf_, size_t n)
140 unsigned int chunk = MIN (n - ofs, f->n);
143 memcpy (buf + ofs, &f->plaintext[16 - f->n], chunk);
149 if (!fill_buffer (f))
157 /* Closes F. Returns 0 if no read errors occurred, otherwise a positive errno
160 encrypted_sys_file_close (struct encrypted_sys_file *f)
162 int error = f->error;
163 if (fclose (f->file) == EOF && !error)
170 #define b(x) (1 << (x))
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) },
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) },
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) },
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) },
201 decode_nibble (const uint16_t table[4][2], int nibble)
205 for (i = 0; i < 4; i++)
206 if (table[i][0] & (1 << nibble))
212 /* Returns true if X has exactly one 1-bit, false otherwise. */
216 return x && (x & (x - 1)) == 0;
219 /* If X has exactly one 1-bit, returns its index, where bit 0 is the LSB.
220 Otherwise, returns 0. */
222 find_1bit (uint16_t x)
229 for (i = 0; i < 16; i++)
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. */
240 decode_password_2bytes (uint8_t a, uint8_t b)
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;
247 /* Decodes an SPSS so-called "encrypted" password INPUT into OUTPUT.
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
253 Returns true if successful, otherwise false. */
255 decode_password (const char *input, char output[11])
259 len = strlen (input);
260 if (len > 20 || len % 2)
263 for (; *input; input += 2)
265 int c = decode_password_2bytes (input[0], input[1]);
275 /* If CIPHERTEXT is the first ciphertext block in an encrypted .sav file for
276 PASSWORD, initializes rk[] and returns an nonzero Nr value.
278 Otherwise, returns zero. */
280 try_password(struct encrypted_sys_file *f, const char *password)
282 /* NIST SP 800-108 fixed data. */
283 static const uint8_t fixed[] = {
285 0x00, 0x00, 0x00, 0x01,
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,
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,
303 0x00, 0x00, 0x01, 0x00,
306 char padded_password[32];
311 /* Truncate password to at most 10 bytes. */
312 password_len = strlen (password);
313 if (password_len > 10)
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);
320 /* cmac = CMAC(padded_password, fixed). */
321 cmac_aes256 (CHAR_CAST (const uint8_t *, padded_password),
322 fixed, sizeof fixed, cmac);
324 /* The key is the cmac repeated twice. */
325 memcpy(key, cmac, 16);
326 memcpy(key + 16, cmac, 16);
328 /* Use key to initialize AES. */
329 assert (sizeof key == 32);
330 f->Nr = rijndaelKeySetupDec (f->rk, CHAR_CAST (const char *, key), 256);
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);
340 fill_buffer (struct encrypted_sys_file *f)
342 f->n = fread (f->ciphertext, 1, sizeof f->ciphertext, f->file);
343 if (f->n == sizeof f->ciphertext)
345 rijndaelDecrypt (f->rk, f->Nr,
346 CHAR_CAST (const char *, f->ciphertext),
347 CHAR_CAST (char *, f->plaintext));
352 if (ferror (f->file))