2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
20 * Crypto subroutines used in backup.c
22 * Split from backup.c August 2014
24 * Kern Sibbald, August MMXIV
34 bool crypto_allocate_ctx(bctx_t &bctx)
38 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
39 Jmsg0(jcr, M_FATAL, 0, _("Encrypting sparse or offset data not supported.\n"));
42 /** Allocate the cipher context */
43 if ((bctx.cipher_ctx = crypto_cipher_new(jcr->crypto.pki_session, true,
44 &bctx.cipher_block_size)) == NULL) {
45 /* Shouldn't happen! */
46 Jmsg0(jcr, M_FATAL, 0, _("Failed to initialize encryption context.\n"));
51 * Grow the crypto buffer, if necessary.
52 * crypto_cipher_update() will buffer up to (cipher_block_size - 1).
53 * We grow crypto_buf to the maximum number of blocks that
54 * could be returned for the given read buffer size.
55 * (Using the larger of either rsize or max_compress_len)
57 jcr->crypto.crypto_buf = check_pool_memory_size(jcr->crypto.crypto_buf,
58 (MAX(bctx.rsize + (int)sizeof(uint32_t), (int32_t)bctx.max_compress_len) +
59 bctx.cipher_block_size - 1) / bctx.cipher_block_size * bctx.cipher_block_size);
61 bctx.wbuf = jcr->crypto.crypto_buf; /* Encrypted, possibly compressed output here. */
66 bool crypto_setup_digests(bctx_t &bctx)
69 FF_PKT *ff_pkt = bctx.ff_pkt;
71 crypto_digest_t signing_algorithm = (crypto_digest_t)me->pki_digest;
74 * Setup for digest handling. If this fails, the digest will be set to NULL
75 * and not used. Note, the digest (file hash) can be any one of the four
78 * The signing digest is a single algorithm depending on
79 * whether or not we have SHA2.
80 * ****FIXME**** the signing algoritm should really be
81 * determined a different way!!!!!! What happens if
82 * sha2 was available during backup but not restore?
84 if (ff_pkt->flags & FO_MD5) {
85 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
86 bctx.digest_stream = STREAM_MD5_DIGEST;
88 } else if (ff_pkt->flags & FO_SHA1) {
89 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
90 bctx.digest_stream = STREAM_SHA1_DIGEST;
92 } else if (ff_pkt->flags & FO_SHA256) {
93 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
94 bctx.digest_stream = STREAM_SHA256_DIGEST;
96 } else if (ff_pkt->flags & FO_SHA512) {
97 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
98 bctx.digest_stream = STREAM_SHA512_DIGEST;
101 /** Did digest initialization fail? */
102 if (bctx.digest_stream != STREAM_NONE && bctx.digest == NULL) {
103 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
104 stream_to_ascii(bctx.digest_stream));
108 * Set up signature digest handling. If this fails, the signature digest
109 * will be set to NULL and not used.
111 /* TODO landonf: We should really only calculate the digest once, for
112 * both verification and signing.
114 if (jcr->crypto.pki_sign) {
115 bctx.signing_digest = crypto_digest_new(jcr, signing_algorithm);
117 /** Full-stop if a failure occurred initializing the signature digest */
118 if (bctx.signing_digest == NULL) {
119 Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"),
120 stream_to_ascii(signing_algorithm));
126 /** Enable encryption */
127 if (jcr->crypto.pki_encrypt) {
128 ff_pkt->flags |= FO_ENCRYPT;
134 bool crypto_session_start(JCR *jcr)
136 crypto_cipher_t cipher = (crypto_cipher_t) me->pki_cipher;
139 * Create encryption session data and a cached, DER-encoded session data
140 * structure. We use a single session key for each backup, so we'll encode
141 * the session data only once.
143 if (jcr->crypto.pki_encrypt) {
146 /** Create per-job session encryption context */
147 jcr->crypto.pki_session = crypto_session_new(cipher, jcr->crypto.pki_recipients);
148 if (!jcr->crypto.pki_session) {
149 Jmsg(jcr, M_FATAL, 0, _("Unsupported cipher on this system.\n"));
153 /** Get the session data size */
154 if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)0, &size)) {
155 Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n"));
159 /** Allocate buffer */
160 jcr->crypto.pki_session_encoded = get_memory(size);
162 /** Encode session data */
163 if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)jcr->crypto.pki_session_encoded, &size)) {
164 Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n"));
168 /** ... and store the encoded size */
169 jcr->crypto.pki_session_encoded_size = size;
171 /** Allocate the encryption/decryption buffer */
172 jcr->crypto.crypto_buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE);
177 void crypto_session_end(JCR *jcr)
179 if (jcr->crypto.crypto_buf) {
180 free_pool_memory(jcr->crypto.crypto_buf);
181 jcr->crypto.crypto_buf = NULL;
183 if (jcr->crypto.pki_session) {
184 crypto_session_free(jcr->crypto.pki_session);
186 if (jcr->crypto.pki_session_encoded) {
187 free_pool_memory(jcr->crypto.pki_session_encoded);
188 jcr->crypto.pki_session_encoded = NULL;
192 bool crypto_session_send(JCR *jcr, BSOCK *sd)
196 /** Send our header */
197 Dmsg2(100, "Send hdr fi=%ld stream=%d\n", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA);
198 sd->fsend("%ld %d %lld", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA,
199 (int64_t)jcr->ff->statp.st_size);
201 sd->msg = jcr->crypto.pki_session_encoded;
202 sd->msglen = jcr->crypto.pki_session_encoded_size;
203 jcr->JobBytes += sd->msglen;
205 Dmsg1(100, "Send data len=%d\n", sd->msglen);
208 sd->signal(BNET_EOD);
212 bool crypto_terminate_digests(bctx_t &bctx)
220 ff_pkt = bctx.ff_pkt;
222 /** Terminate the signing digest and send it to the Storage daemon */
223 if (bctx.signing_digest) {
226 if ((bctx.sig = crypto_sign_new(jcr)) == NULL) {
227 Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for crypto signature.\n"));
231 if (!crypto_sign_add_signer(bctx.sig, bctx.signing_digest, jcr->crypto.pki_keypair)) {
232 Jmsg(jcr, M_FATAL, 0, _("An error occurred while adding signer the stream.\n"));
236 /** Get signature size */
237 if (!crypto_sign_encode(bctx.sig, NULL, &size)) {
238 Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n"));
242 /** Grow the bsock buffer to fit our message if necessary */
243 if (sizeof_pool_memory(sd->msg) < (int32_t)size) {
244 sd->msg = realloc_pool_memory(sd->msg, size);
247 /** Send our header */
248 sd->fsend("%ld %ld 0", jcr->JobFiles, STREAM_SIGNED_DIGEST);
249 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
251 /** Encode signature data */
252 if (!crypto_sign_encode(bctx.sig, (uint8_t *)sd->msg, &size)) {
253 Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n"));
259 sd->signal(BNET_EOD); /* end of checksum */
262 /** Terminate any digest and send it to Storage daemon */
266 sd->fsend("%ld %d 0", jcr->JobFiles, bctx.digest_stream);
267 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
269 size = CRYPTO_DIGEST_MAX_SIZE;
271 /** Grow the bsock buffer to fit our message if necessary */
272 if (sizeof_pool_memory(sd->msg) < (int32_t)size) {
273 sd->msg = realloc_pool_memory(sd->msg, size);
276 if (!crypto_digest_finalize(bctx.digest, (uint8_t *)sd->msg, &size)) {
277 Jmsg(jcr, M_FATAL, 0, _("An error occurred finalizing signing the stream.\n"));
281 /* Keep the checksum if this file is a hardlink */
282 if (ff_pkt->linked) {
283 ff_pkt_set_link_digest(ff_pkt, bctx.digest_stream, sd->msg, size);
288 sd->signal(BNET_EOD); /* end of checksum */
291 /* Check if original file has a digest, and send it */
292 if (ff_pkt->type == FT_LNKSAVED && ff_pkt->digest) {
293 Dmsg2(300, "Link %s digest %d\n", ff_pkt->fname, ff_pkt->digest_len);
294 sd->fsend("%ld %d 0", jcr->JobFiles, ff_pkt->digest_stream);
296 sd->msg = check_pool_memory_size(sd->msg, ff_pkt->digest_len);
297 memcpy(sd->msg, ff_pkt->digest, ff_pkt->digest_len);
298 sd->msglen = ff_pkt->digest_len;
301 sd->signal(BNET_EOD); /* end of hardlink record */
307 void crypto_free(bctx_t &bctx)
310 crypto_digest_free(bctx.digest);
313 if (bctx.signing_digest) {
314 crypto_digest_free(bctx.signing_digest);
315 bctx.signing_digest = NULL;
318 crypto_sign_free(bctx.sig);