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"
20 #include "data/file-handle-def.h"
25 #include "data/file-name.h"
26 #include "libpspp/assertion.h"
27 #include "libpspp/cast.h"
28 #include "libpspp/cmac-aes256.h"
29 #include "libpspp/message.h"
31 #include "gl/minmax.h"
32 #include "gl/rijndael-alg-fst.h"
33 #include "gl/xalloc.h"
36 #define _(msgid) gettext (msgid)
41 enum { SYSTEM, SYNTAX } type;
44 uint8_t ciphertext[16];
45 uint8_t plaintext[16];
48 uint32_t rk[4 * (RIJNDAEL_MAXNR + 1)];
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 struct file_handle *fh)
65 struct encrypted_file *f;
70 f = xmalloc (sizeof *f);
72 f->file = fn_open (fh, "rb");
75 msg (ME, _("An error occurred while opening `%s': %s."),
76 fh_get_file_name (fh), 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 fh_get_file_name (fh), 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 (fh, 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 (encrypted_file_unlock__ (f, password)
125 || (decode_password (password, decoded_password)
126 && encrypted_file_unlock__ (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 /* Attempts to use plaintext password PASSWORD to unlock F. Returns true if
290 successful, otherwise false. */
292 encrypted_file_unlock__ (struct encrypted_file *f, const char *password)
294 /* NIST SP 800-108 fixed data. */
295 static const uint8_t fixed[] = {
297 0x00, 0x00, 0x00, 0x01,
300 0x35, 0x27, 0x13, 0xcc, 0x53, 0xa7, 0x78, 0x89,
301 0x87, 0x53, 0x22, 0x11, 0xd6, 0x5b, 0x31, 0x58,
302 0xdc, 0xfe, 0x2e, 0x7e, 0x94, 0xda, 0x2f, 0x00,
303 0xcc, 0x15, 0x71, 0x80, 0x0a, 0x6c, 0x63, 0x53,
309 0x38, 0xc3, 0x38, 0xac, 0x22, 0xf3, 0x63, 0x62,
310 0x0e, 0xce, 0x85, 0x3f, 0xb8, 0x07, 0x4c, 0x4e,
311 0x2b, 0x77, 0xc7, 0x21, 0xf5, 0x1a, 0x80, 0x1d,
312 0x67, 0xfb, 0xe1, 0xe1, 0x83, 0x07, 0xd8, 0x0d,
315 0x00, 0x00, 0x01, 0x00,
318 char padded_password[32];
323 /* Truncate password to at most 10 bytes. */
324 password_len = strlen (password);
325 if (password_len > 10)
328 /* padded_password = password padded with zeros to 32 bytes. */
329 memset (padded_password, 0, sizeof padded_password);
330 memcpy (padded_password, password, password_len);
332 /* cmac = CMAC(padded_password, fixed). */
333 cmac_aes256 (CHAR_CAST (const uint8_t *, padded_password),
334 fixed, sizeof fixed, cmac);
336 /* The key is the cmac repeated twice. */
337 memcpy(key, cmac, 16);
338 memcpy(key + 16, cmac, 16);
340 /* Use key to initialize AES. */
341 assert (sizeof key == 32);
342 f->Nr = rijndaelKeySetupDec (f->rk, CHAR_CAST (const char *, key), 256);
344 /* Check for magic number at beginning of plaintext. */
345 rijndaelDecrypt (f->rk, f->Nr,
346 CHAR_CAST (const char *, f->ciphertext),
347 CHAR_CAST (char *, f->plaintext));
349 const char *magic = f->type == SYSTEM ? "$FL?@(#)" : "* Encoding";
350 for (int i = 0; magic[i]; i++)
351 if (magic[i] != '?' && f->plaintext[i] != magic[i])
357 fill_buffer (struct encrypted_file *f)
359 f->n = fread (f->ciphertext, 1, sizeof f->ciphertext, f->file);
361 if (f->n == sizeof f->ciphertext)
363 rijndaelDecrypt (f->rk, f->Nr,
364 CHAR_CAST (const char *, f->ciphertext),
365 CHAR_CAST (char *, f->plaintext));
366 if (f->type == SYNTAX)
368 const char *eof = memchr (f->plaintext, '\04', sizeof f->plaintext);
370 f->n = CHAR_CAST (const uint8_t *, eof) - f->plaintext;
376 if (ferror (f->file))