4 * Date: Fri Aug 26 19:50:51 2011
6 * GNU recutils - Encryption routines
10 /* Copyright (C) 2011-2019 Jose E. Marchesi */
12 /* This program is free software: you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation, either version 3 of the License, or
15 * (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program. If not, see <http://www.gnu.org/licenses/>.
34 #include <rec-utils.h>
36 /* Size of a block in AES128 */
37 #define AESV2_BLKSIZE 16
38 #define AESV2_KEYSIZE 16
43 rec_field_encrypted_p (rec_field_t field
)
45 return ((strlen (rec_field_value (field
)) > strlen (REC_ENCRYPTED_PREFIX
))
46 && (strncmp (rec_field_value (field
), REC_ENCRYPTED_PREFIX
,
47 strlen (REC_ENCRYPTED_PREFIX
)) == 0));
51 rec_encrypt (char *in
,
57 gcry_cipher_hd_t handler
;
60 char key
[AESV2_KEYSIZE
];
61 char iv
[AESV2_BLKSIZE
];
67 /* Append four bytes to the input buffer, containing the CRC of its
68 contents. This will be used as a control token to determine
69 whether the correct key is used in decryption.
71 We store the integer always in little-endian. */
73 crc
= crc32 (in
, in_size
);
75 #if defined WORDS_BIGENDIAN
76 crc
= rec_endian_swap (crc
);
79 real_in_size
= in_size
+ 4;
80 real_in
= malloc (real_in_size
+ 4);
81 memcpy (real_in
, in
, real_in_size
);
82 memcpy (real_in
+ real_in_size
- 4, &crc
, 4);
84 /* The size of the input buffer must be bigger than AESV2_BLKSIZE,
85 and must contain an entire number of blocks. We assure that by
86 padding the buffer with \0 characters. */
88 if ((real_in_size
% AESV2_BLKSIZE
) != 0)
89 padding
= AESV2_BLKSIZE
- (real_in_size
% AESV2_BLKSIZE
);
95 real_in_size
= real_in_size
+ padding
;
96 real_in
= realloc (real_in
, real_in_size
);
98 for (i
= 0; i
< padding
; i
++)
99 real_in
[real_in_size
- i
- 1] = '\0';
102 /* Create the handler. */
103 if (gcry_cipher_open (&handler
,
105 GCRY_CIPHER_MODE_CBC
,
106 0) != GPG_ERR_NO_ERROR
)
109 /* Set the key of the cypher. */
110 password_size
= strlen (password
);
111 for (i
= 0; i
< AESV2_KEYSIZE
; i
++)
112 key
[i
] = password
[i
% password_size
];
114 /* Set both the key and the IV vector. */
115 if (gcry_cipher_setkey (handler
, key
, AESV2_KEYSIZE
)
118 gcry_cipher_close (handler
);
122 gcry_create_nonce (iv
, SALT_SIZE
);
124 for (i
= SALT_SIZE
; i
< AESV2_BLKSIZE
; i
++)
127 if (gcry_cipher_setiv (handler
, iv
, AESV2_BLKSIZE
)
130 gcry_cipher_close (handler
);
134 *out_size
= real_in_size
+ SALT_SIZE
;
135 *out
= malloc (*out_size
);
137 /* Append salt at the end of the output. */
138 memcpy (*out
+ real_in_size
, iv
, SALT_SIZE
);
140 /* Encrypt the data. */
141 if (gcry_cipher_encrypt (handler
,
148 gcry_cipher_close (handler
);
152 /* Close the handler. */
153 gcry_cipher_close (handler
);
159 rec_decrypt (char *in
,
161 const char *password
,
165 gcry_cipher_hd_t handler
;
167 size_t password_size
;
168 char key
[AESV2_KEYSIZE
];
169 char iv
[AESV2_BLKSIZE
];
170 size_t salt_size
= 0;
172 if (((in_size
- SALT_SIZE
) % AESV2_BLKSIZE
) == 0)
173 salt_size
= SALT_SIZE
;
174 else if ((in_size
% AESV2_BLKSIZE
) != 0)
177 /* Create the handler. */
178 if (gcry_cipher_open (&handler
,
180 GCRY_CIPHER_MODE_CBC
,
181 0) != GPG_ERR_NO_ERROR
)
184 /* Set the key of the cypher. */
185 password_size
= strlen (password
);
186 for (i
= 0; i
< AESV2_KEYSIZE
; i
++)
187 key
[i
] = password
[i
% password_size
];
189 /* Set both the key and the IV vector. */
190 if (gcry_cipher_setkey (handler
, key
, AESV2_KEYSIZE
)
193 printf ("error setting key\n");
194 gcry_cipher_close (handler
);
198 /* Extract salt at the end of the output. */
199 memcpy (iv
, in
+ in_size
- salt_size
, salt_size
);
201 for (i
= salt_size
; i
< AESV2_BLKSIZE
; i
++)
204 if (gcry_cipher_setiv (handler
, iv
, AESV2_BLKSIZE
)
207 gcry_cipher_close (handler
);
211 /* Decrypt the data. */
212 *out_size
= in_size
- salt_size
;
213 *out
= malloc (*out_size
);
214 if (gcry_cipher_decrypt (handler
,
218 in_size
- salt_size
) != 0)
221 gcry_cipher_close (handler
);
225 /* Make sure the decrypted data is ok by checking the CRC at the end
228 if (strlen(*out
) > 4)
232 memcpy (&crc
, *out
+ strlen(*out
) - 4, 4);
233 #if defined WORDS_BIGENDIAN
234 crc
= rec_endian_swap (crc
);
237 if (crc32 (*out
, strlen(*out
) - 4) != crc
)
239 gcry_cipher_close (handler
);
243 (*out
)[strlen(*out
) - 4] = '\0';
247 gcry_cipher_close (handler
);
251 /* Close the handler. */
252 gcry_cipher_close (handler
);
258 rec_encrypt_record (rec_rset_t rset
,
260 const char *password
)
264 const char *field_name
;
265 rec_fex_t confidential_fields
;
266 size_t i
, k
, num_fields
;
272 confidential_fields
= rec_rset_confidential (rset
);
273 for (i
= 0; i
< rec_fex_size (confidential_fields
); i
++)
275 field_name
= rec_fex_elem_field_name (rec_fex_get (confidential_fields
, i
));
277 num_fields
= rec_record_get_num_fields_by_name (record
, field_name
);
278 for (k
= 0; k
< num_fields
; k
++)
280 field
= rec_record_get_field_by_name (record
, field_name
, k
);
283 res
= rec_encrypt_field (field
, password
);
295 rec_encrypt_field (rec_field_t field
,
296 const char *password
)
299 char *field_value_encrypted
;
300 char *field_value_base64
;
301 size_t out_size
, base64_size
;
304 field_value
= strdup (rec_field_value (field
));
308 /* Make sure the field is not already encrypted. */
309 if ((strlen (rec_field_value (field
)) >= strlen (REC_ENCRYPTED_PREFIX
))
310 && (strncmp (rec_field_value (field
), REC_ENCRYPTED_PREFIX
,
311 strlen (REC_ENCRYPTED_PREFIX
)) == 0))
314 if (!rec_encrypt (field_value
,
315 strlen (field_value
),
317 &field_value_encrypted
,
321 /* Encode the encrypted value into base64. */
323 base64_size
= base64_encode_alloc (field_value_encrypted
,
325 &field_value_base64
);
326 base64_encode (field_value_encrypted
,
331 /* Prepennd "encrypted-". */
332 aux
= malloc (strlen (field_value_base64
)
333 + strlen (REC_ENCRYPTED_PREFIX
) + 1);
335 REC_ENCRYPTED_PREFIX
,
336 strlen (REC_ENCRYPTED_PREFIX
));
337 memcpy (aux
+ strlen (REC_ENCRYPTED_PREFIX
),
339 strlen (field_value_base64
));
340 aux
[strlen (field_value_base64
)
341 + strlen (REC_ENCRYPTED_PREFIX
)] = '\0';
342 free (field_value_base64
);
343 field_value_base64
= aux
;
345 /* Replace the value of the field. */
346 rec_field_set_value (field
, field_value_base64
);
348 /* Free resources. */
350 free (field_value_encrypted
);
351 free (field_value_base64
);
357 rec_decrypt_field (rec_field_t field
,
358 const char *password
)
360 const char *field_value
;
361 char *base64_decoded
;
362 size_t base64_decoded_size
;
363 char *decrypted_value
;
364 size_t decrypted_value_size
;
366 /* Make sure the field is encrypted. */
367 if ((strlen (rec_field_value (field
)) < strlen (REC_ENCRYPTED_PREFIX
))
368 || (strncmp (rec_field_value (field
), REC_ENCRYPTED_PREFIX
,
369 strlen (REC_ENCRYPTED_PREFIX
)) != 0))
372 /* Skip the "encrypted-" prefix. */
373 field_value
= rec_field_value (field
) + strlen (REC_ENCRYPTED_PREFIX
);
375 /* Decode the Base64. */
377 if (base64_decode_alloc (field_value
,
380 &base64_decoded_size
))
382 base64_decode (field_value
,
385 &base64_decoded_size
);
389 if (rec_decrypt (base64_decoded
,
393 &decrypted_value_size
))
394 rec_field_set_value (field
, decrypted_value
);
396 /* Free resources. */
397 free (base64_decoded
);
404 rec_decrypt_record (rec_rset_t rset
,
406 const char *password
)
409 size_t i
, num_fields
, k
;
411 const char *field_name
;
412 rec_fex_t confidential_fields
;
416 confidential_fields
= rec_rset_confidential (rset
);
417 for (i
= 0; i
< rec_fex_size (confidential_fields
); i
++)
419 field_name
= rec_fex_elem_field_name (rec_fex_get (confidential_fields
, i
));
421 num_fields
= rec_record_get_num_fields_by_name (record
, field_name
);
422 for (k
= 0; k
< num_fields
; k
++)
424 field
= rec_record_get_field_by_name (record
, field_name
, k
);
427 res
= rec_decrypt_field (field
, password
);
438 /* End of rec-crypt.c */