1 /* PSPP - a program for statistical analysis.
2 Copyright (C) 2013, 2015 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/encrypted-file.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)
40 enum { SYSTEM, SYNTAX } type;
43 uint8_t ciphertext[16];
44 uint8_t plaintext[16];
47 uint32_t rk[4 * (RIJNDAEL_MAXNR + 1)];
51 static bool try_password(struct encrypted_file *, const char *password);
52 static bool decode_password (const char *input, char output[11]);
53 static bool fill_buffer (struct encrypted_file *);
55 /* If FILENAME names an encrypted SPSS file, returns 1 and initializes *FP
56 for further use by the caller.
58 If FILENAME can be opened and read, but is not an encrypted SPSS file,
61 If FILENAME cannot be open or read, returns a negative errno value. */
63 encrypted_file_open (struct encrypted_file **fp, const char *filename)
65 struct encrypted_file *f;
70 f = xmalloc (sizeof *f);
72 f->file = fn_open (filename, "rb");
75 msg (ME, _("An error occurred while opening `%s': %s."),
76 filename, strerror (errno));
81 n = fread (header, 1, sizeof header, f->file);
82 if (n != sizeof header)
84 int error = feof (f->file) ? 0 : errno;
86 msg (ME, _("An error occurred while reading `%s': %s."),
87 filename, strerror (error));
92 if (!memcmp (header + 8, "ENCRYPTEDSAV", 12))
94 else if (!memcmp (header + 8, "ENCRYPTEDSPS", 12))
102 memcpy (f->ciphertext, header + 36, 16);
110 fn_close (filename, f->file);
117 /* Attempts to use PASSWORD, which may be a plaintext or "encrypted" password,
118 to unlock F. Returns true if successful, otherwise false. */
120 encrypted_file_unlock (struct encrypted_file *f, const char *password)
122 char decoded_password[11];
124 return (try_password (f, password)
125 || (decode_password (password, decoded_password)
126 && try_password (f, decoded_password)));
129 /* Attempts to read N bytes of plaintext from F into BUF. Returns the number
130 of bytes successfully read. A return value less than N may indicate end of
131 file or an error; use encrypted_file_close() to distinguish.
133 This function can only be used after encrypted_file_unlock() returns
136 encrypted_file_read (struct encrypted_file *f, void *buf_, size_t n)
146 unsigned int chunk = MIN (n - ofs, f->n - f->ofs);
149 memcpy (buf + ofs, &f->plaintext[f->ofs], chunk);
155 if (!fill_buffer (f))
163 /* Closes F. Returns 0 if no read errors occurred, otherwise a positive errno
166 encrypted_file_close (struct encrypted_file *f)
168 int error = f->error;
169 if (fclose (f->file) == EOF && !error)
176 /* Returns true if F is an encrypted system file,
177 false if it is an encrypted syntax file. */
179 encrypted_file_is_sav (const struct encrypted_file *f)
181 return f->type == SYSTEM;
184 #define b(x) (1 << (x))
186 static const uint16_t m0[4][2] = {
187 { b(2), b(2) | b(3) | b(6) | b(7) },
188 { b(3), b(0) | b(1) | b(4) | b(5) },
189 { b(4) | b(7), b(8) | b(9) | b(12) | b(14) },
190 { b(5) | b(6), b(10) | b(11) | b(14) | b(15) },
193 static const uint16_t m1[4][2] = {
194 { b(0) | b(3) | b(12) | b(15), b(0) | b(1) | b(4) | b(5) },
195 { b(1) | b(2) | b(13) | b(14), b(2) | b(3) | b(6) | b(7) },
196 { b(4) | b(7) | b(8) | b(11), b(8) | b(9) | b(12) | b(13) },
197 { b(5) | b(6) | b(9) | b(10), b(10) | b(11) | b(14) | b(15) },
200 static const uint16_t m2[4][2] = {
201 { b(2), b(1) | b(3) | b(9) | b(11) },
202 { b(3), b(0) | b(2) | b(8) | b(10) },
203 { b(4) | b(7), b(4) | b(6) | b(12) | b(14) },
204 { b(5) | b(6), b(5) | b(7) | b(13) | b(15) },
207 static const uint16_t m3[4][2] = {
208 { b(0) | b(3) | b(12) | b(15), b(0) | b(2) | b(8) | b(10) },
209 { b(1) | b(2) | b(13) | b(14), b(1) | b(3) | b(9) | b(11) },
210 { b(4) | b(7) | b(8) | b(11), b(4) | b(6) | b(12) | b(14) },
211 { b(5) | b(6) | b(9) | b(10), b(5) | b(7) | b(13) | b(15) },
215 decode_nibble (const uint16_t table[4][2], int nibble)
219 for (i = 0; i < 4; i++)
220 if (table[i][0] & (1 << nibble))
226 /* Returns true if X has exactly one 1-bit, false otherwise. */
230 return x && (x & (x - 1)) == 0;
233 /* If X has exactly one 1-bit, returns its index, where bit 0 is the LSB.
234 Otherwise, returns 0. */
236 find_1bit (uint16_t x)
243 for (i = 0; i < 16; i++)
250 /* Attempts to decode a pair of encoded password characters A and B into a
251 single byte of the plaintext password. Returns 0 if A and B are not a valid
252 encoded password pair, otherwise a byte of the plaintext password. */
254 decode_password_2bytes (uint8_t a, uint8_t b)
256 int x = find_1bit (decode_nibble (m0, a >> 4) & decode_nibble (m2, b >> 4));
257 int y = find_1bit (decode_nibble (m1, a & 15) & decode_nibble (m3, b & 15));
258 return x < 0 || y < 0 ? 0 : (x << 4) | y;
261 /* Decodes an SPSS so-called "encrypted" password INPUT into OUTPUT.
263 An encoded password is always an even number of bytes long and no longer
264 than 20 bytes. A decoded password is never longer than 10 bytes plus a null
267 Returns true if successful, otherwise false. */
269 decode_password (const char *input, char output[11])
273 len = strlen (input);
274 if (len > 20 || len % 2)
277 for (; *input; input += 2)
279 int c = decode_password_2bytes (input[0], input[1]);
289 /* If CIPHERTEXT is the first ciphertext block in an encrypted .sav file for
290 PASSWORD, initializes rk[] and returns an nonzero Nr value.
292 Otherwise, returns zero. */
294 try_password(struct encrypted_file *f, const char *password)
296 /* NIST SP 800-108 fixed data. */
297 static const uint8_t fixed[] = {
299 0x00, 0x00, 0x00, 0x01,
302 0x35, 0x27, 0x13, 0xcc, 0x53, 0xa7, 0x78, 0x89,
303 0x87, 0x53, 0x22, 0x11, 0xd6, 0x5b, 0x31, 0x58,
304 0xdc, 0xfe, 0x2e, 0x7e, 0x94, 0xda, 0x2f, 0x00,
305 0xcc, 0x15, 0x71, 0x80, 0x0a, 0x6c, 0x63, 0x53,
311 0x38, 0xc3, 0x38, 0xac, 0x22, 0xf3, 0x63, 0x62,
312 0x0e, 0xce, 0x85, 0x3f, 0xb8, 0x07, 0x4c, 0x4e,
313 0x2b, 0x77, 0xc7, 0x21, 0xf5, 0x1a, 0x80, 0x1d,
314 0x67, 0xfb, 0xe1, 0xe1, 0x83, 0x07, 0xd8, 0x0d,
317 0x00, 0x00, 0x01, 0x00,
320 char padded_password[32];
325 /* Truncate password to at most 10 bytes. */
326 password_len = strlen (password);
327 if (password_len > 10)
330 /* padded_password = password padded with zeros to 32 bytes. */
331 memset (padded_password, 0, sizeof padded_password);
332 memcpy (padded_password, password, password_len);
334 /* cmac = CMAC(padded_password, fixed). */
335 cmac_aes256 (CHAR_CAST (const uint8_t *, padded_password),
336 fixed, sizeof fixed, cmac);
338 /* The key is the cmac repeated twice. */
339 memcpy(key, cmac, 16);
340 memcpy(key + 16, cmac, 16);
342 /* Use key to initialize AES. */
343 assert (sizeof key == 32);
344 f->Nr = rijndaelKeySetupDec (f->rk, CHAR_CAST (const char *, key), 256);
346 /* Check for magic number at beginning of plaintext. */
347 rijndaelDecrypt (f->rk, f->Nr,
348 CHAR_CAST (const char *, f->ciphertext),
349 CHAR_CAST (char *, f->plaintext));
350 return !memcmp (f->plaintext, f->type == SYSTEM ? "$FL" : "* E", 3);
354 fill_buffer (struct encrypted_file *f)
356 f->n = fread (f->ciphertext, 1, sizeof f->ciphertext, f->file);
358 if (f->n == sizeof f->ciphertext)
360 rijndaelDecrypt (f->rk, f->Nr,
361 CHAR_CAST (const char *, f->ciphertext),
362 CHAR_CAST (char *, f->plaintext));
363 if (f->type == SYNTAX)
365 const char *eof = memchr (f->plaintext, '\04', sizeof f->plaintext);
367 f->n = CHAR_CAST (const uint8_t *, eof) - f->plaintext;
373 if (ferror (f->file))