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 try_password(struct encrypted_file *, const char *password);
53 static bool decode_password (const char *input, char output[11]);
54 static bool fill_buffer (struct encrypted_file *);
56 /* If FILENAME names an encrypted SPSS file, returns 1 and initializes *FP
57 for further use by the caller.
59 If FILENAME can be opened and read, but is not an encrypted SPSS file,
62 If FILENAME cannot be open or read, returns a negative errno value. */
64 encrypted_file_open (struct encrypted_file **fp, const struct file_handle *fh)
66 struct encrypted_file *f;
71 f = xmalloc (sizeof *f);
73 f->file = fn_open (fh, "rb");
76 msg (ME, _("An error occurred while opening `%s': %s."),
77 fh_get_file_name (fh), strerror (errno));
82 n = fread (header, 1, sizeof header, f->file);
83 if (n != sizeof header)
85 int error = feof (f->file) ? 0 : errno;
87 msg (ME, _("An error occurred while reading `%s': %s."),
88 fh_get_file_name (fh), strerror (error));
93 if (!memcmp (header + 8, "ENCRYPTEDSAV", 12))
95 else if (!memcmp (header + 8, "ENCRYPTEDSPS", 12))
103 memcpy (f->ciphertext, header + 36, 16);
111 fn_close (fh, f->file);
118 /* Attempts to use PASSWORD, which may be a plaintext or "encrypted" password,
119 to unlock F. Returns true if successful, otherwise false. */
121 encrypted_file_unlock (struct encrypted_file *f, const char *password)
123 char decoded_password[11];
125 return (try_password (f, password)
126 || (decode_password (password, decoded_password)
127 && try_password (f, decoded_password)));
130 /* Attempts to read N bytes of plaintext from F into BUF. Returns the number
131 of bytes successfully read. A return value less than N may indicate end of
132 file or an error; use encrypted_file_close() to distinguish.
134 This function can only be used after encrypted_file_unlock() returns
137 encrypted_file_read (struct encrypted_file *f, void *buf_, size_t n)
147 unsigned int chunk = MIN (n - ofs, f->n - f->ofs);
150 memcpy (buf + ofs, &f->plaintext[f->ofs], chunk);
156 if (!fill_buffer (f))
164 /* Closes F. Returns 0 if no read errors occurred, otherwise a positive errno
167 encrypted_file_close (struct encrypted_file *f)
169 int error = f->error;
170 if (fclose (f->file) == EOF && !error)
177 /* Returns true if F is an encrypted system file,
178 false if it is an encrypted syntax file. */
180 encrypted_file_is_sav (const struct encrypted_file *f)
182 return f->type == SYSTEM;
185 #define b(x) (1 << (x))
187 static const uint16_t m0[4][2] = {
188 { b(2), b(2) | b(3) | b(6) | b(7) },
189 { b(3), b(0) | b(1) | b(4) | b(5) },
190 { b(4) | b(7), b(8) | b(9) | b(12) | b(14) },
191 { b(5) | b(6), b(10) | b(11) | b(14) | b(15) },
194 static const uint16_t m1[4][2] = {
195 { b(0) | b(3) | b(12) | b(15), b(0) | b(1) | b(4) | b(5) },
196 { b(1) | b(2) | b(13) | b(14), b(2) | b(3) | b(6) | b(7) },
197 { b(4) | b(7) | b(8) | b(11), b(8) | b(9) | b(12) | b(13) },
198 { b(5) | b(6) | b(9) | b(10), b(10) | b(11) | b(14) | b(15) },
201 static const uint16_t m2[4][2] = {
202 { b(2), b(1) | b(3) | b(9) | b(11) },
203 { b(3), b(0) | b(2) | b(8) | b(10) },
204 { b(4) | b(7), b(4) | b(6) | b(12) | b(14) },
205 { b(5) | b(6), b(5) | b(7) | b(13) | b(15) },
208 static const uint16_t m3[4][2] = {
209 { b(0) | b(3) | b(12) | b(15), b(0) | b(2) | b(8) | b(10) },
210 { b(1) | b(2) | b(13) | b(14), b(1) | b(3) | b(9) | b(11) },
211 { b(4) | b(7) | b(8) | b(11), b(4) | b(6) | b(12) | b(14) },
212 { b(5) | b(6) | b(9) | b(10), b(5) | b(7) | b(13) | b(15) },
216 decode_nibble (const uint16_t table[4][2], int nibble)
220 for (i = 0; i < 4; i++)
221 if (table[i][0] & (1 << nibble))
227 /* Returns true if X has exactly one 1-bit, false otherwise. */
231 return x && (x & (x - 1)) == 0;
234 /* If X has exactly one 1-bit, returns its index, where bit 0 is the LSB.
235 Otherwise, returns 0. */
237 find_1bit (uint16_t x)
244 for (i = 0; i < 16; i++)
251 /* Attempts to decode a pair of encoded password characters A and B into a
252 single byte of the plaintext password. Returns 0 if A and B are not a valid
253 encoded password pair, otherwise a byte of the plaintext password. */
255 decode_password_2bytes (uint8_t a, uint8_t b)
257 int x = find_1bit (decode_nibble (m0, a >> 4) & decode_nibble (m2, b >> 4));
258 int y = find_1bit (decode_nibble (m1, a & 15) & decode_nibble (m3, b & 15));
259 return x < 0 || y < 0 ? 0 : (x << 4) | y;
262 /* Decodes an SPSS so-called "encrypted" password INPUT into OUTPUT.
264 An encoded password is always an even number of bytes long and no longer
265 than 20 bytes. A decoded password is never longer than 10 bytes plus a null
268 Returns true if successful, otherwise false. */
270 decode_password (const char *input, char output[11])
274 len = strlen (input);
275 if (len > 20 || len % 2)
278 for (; *input; input += 2)
280 int c = decode_password_2bytes (input[0], input[1]);
290 /* If CIPHERTEXT is the first ciphertext block in an encrypted .sav file for
291 PASSWORD, initializes rk[] and returns an nonzero Nr value.
293 Otherwise, returns zero. */
295 try_password(struct encrypted_file *f, const char *password)
297 /* NIST SP 800-108 fixed data. */
298 static const uint8_t fixed[] = {
300 0x00, 0x00, 0x00, 0x01,
303 0x35, 0x27, 0x13, 0xcc, 0x53, 0xa7, 0x78, 0x89,
304 0x87, 0x53, 0x22, 0x11, 0xd6, 0x5b, 0x31, 0x58,
305 0xdc, 0xfe, 0x2e, 0x7e, 0x94, 0xda, 0x2f, 0x00,
306 0xcc, 0x15, 0x71, 0x80, 0x0a, 0x6c, 0x63, 0x53,
312 0x38, 0xc3, 0x38, 0xac, 0x22, 0xf3, 0x63, 0x62,
313 0x0e, 0xce, 0x85, 0x3f, 0xb8, 0x07, 0x4c, 0x4e,
314 0x2b, 0x77, 0xc7, 0x21, 0xf5, 0x1a, 0x80, 0x1d,
315 0x67, 0xfb, 0xe1, 0xe1, 0x83, 0x07, 0xd8, 0x0d,
318 0x00, 0x00, 0x01, 0x00,
321 char padded_password[32];
326 /* Truncate password to at most 10 bytes. */
327 password_len = strlen (password);
328 if (password_len > 10)
331 /* padded_password = password padded with zeros to 32 bytes. */
332 memset (padded_password, 0, sizeof padded_password);
333 memcpy (padded_password, password, password_len);
335 /* cmac = CMAC(padded_password, fixed). */
336 cmac_aes256 (CHAR_CAST (const uint8_t *, padded_password),
337 fixed, sizeof fixed, cmac);
339 /* The key is the cmac repeated twice. */
340 memcpy(key, cmac, 16);
341 memcpy(key + 16, cmac, 16);
343 /* Use key to initialize AES. */
344 assert (sizeof key == 32);
345 f->Nr = rijndaelKeySetupDec (f->rk, CHAR_CAST (const char *, key), 256);
347 /* Check for magic number at beginning of plaintext. */
348 rijndaelDecrypt (f->rk, f->Nr,
349 CHAR_CAST (const char *, f->ciphertext),
350 CHAR_CAST (char *, f->plaintext));
351 return !memcmp (f->plaintext, f->type == SYSTEM ? "$FL" : "* E", 3);
355 fill_buffer (struct encrypted_file *f)
357 f->n = fread (f->ciphertext, 1, sizeof f->ciphertext, f->file);
359 if (f->n == sizeof f->ciphertext)
361 rijndaelDecrypt (f->rk, f->Nr,
362 CHAR_CAST (const char *, f->ciphertext),
363 CHAR_CAST (char *, f->plaintext));
364 if (f->type == SYNTAX)
366 const char *eof = memchr (f->plaintext, '\04', sizeof f->plaintext);
368 f->n = CHAR_CAST (const uint8_t *, eof) - f->plaintext;
374 if (ferror (f->file))