2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Crypto subroutines used in backup.c
23 * Split from backup.c August 2014
25 * Kern Sibbald, August MMXIV
35 bool crypto_allocate_ctx(bctx_t &bctx)
39 if ((bctx.ff_pkt->flags & FO_SPARSE) || (bctx.ff_pkt->flags & FO_OFFSETS)) {
40 Jmsg0(jcr, M_FATAL, 0, _("Encrypting sparse or offset data not supported.\n"));
43 /** Allocate the cipher context */
44 if ((bctx.cipher_ctx = crypto_cipher_new(jcr->crypto.pki_session, true,
45 &bctx.cipher_block_size)) == NULL) {
46 /* Shouldn't happen! */
47 Jmsg0(jcr, M_FATAL, 0, _("Failed to initialize encryption context.\n"));
52 * Grow the crypto buffer, if necessary.
53 * crypto_cipher_update() will buffer up to (cipher_block_size - 1).
54 * We grow crypto_buf to the maximum number of blocks that
55 * could be returned for the given read buffer size.
56 * (Using the larger of either rsize or max_compress_len)
58 jcr->crypto.crypto_buf = check_pool_memory_size(jcr->crypto.crypto_buf,
59 (MAX(bctx.rsize + (int)sizeof(uint32_t), (int32_t)bctx.max_compress_len) +
60 bctx.cipher_block_size - 1) / bctx.cipher_block_size * bctx.cipher_block_size);
62 bctx.wbuf = jcr->crypto.crypto_buf; /* Encrypted, possibly compressed output here. */
67 bool crypto_setup_digests(bctx_t &bctx)
70 FF_PKT *ff_pkt = bctx.ff_pkt;
72 crypto_digest_t signing_algorithm = (crypto_digest_t)me->pki_digest;
75 * Setup for digest handling. If this fails, the digest will be set to NULL
76 * and not used. Note, the digest (file hash) can be any one of the four
79 * The signing digest is a single algorithm depending on
80 * whether or not we have SHA2.
81 * ****FIXME**** the signing algoritm should really be
82 * determined a different way!!!!!! What happens if
83 * sha2 was available during backup but not restore?
85 if (ff_pkt->flags & FO_MD5) {
86 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_MD5);
87 bctx.digest_stream = STREAM_MD5_DIGEST;
89 } else if (ff_pkt->flags & FO_SHA1) {
90 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA1);
91 bctx.digest_stream = STREAM_SHA1_DIGEST;
93 } else if (ff_pkt->flags & FO_SHA256) {
94 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA256);
95 bctx.digest_stream = STREAM_SHA256_DIGEST;
97 } else if (ff_pkt->flags & FO_SHA512) {
98 bctx.digest = crypto_digest_new(jcr, CRYPTO_DIGEST_SHA512);
99 bctx.digest_stream = STREAM_SHA512_DIGEST;
102 /** Did digest initialization fail? */
103 if (bctx.digest_stream != STREAM_NONE && bctx.digest == NULL) {
104 Jmsg(jcr, M_WARNING, 0, _("%s digest initialization failed\n"),
105 stream_to_ascii(bctx.digest_stream));
109 * Set up signature digest handling. If this fails, the signature digest
110 * will be set to NULL and not used.
112 /* TODO landonf: We should really only calculate the digest once, for
113 * both verification and signing.
115 if (jcr->crypto.pki_sign) {
116 bctx.signing_digest = crypto_digest_new(jcr, signing_algorithm);
118 /** Full-stop if a failure occurred initializing the signature digest */
119 if (bctx.signing_digest == NULL) {
120 Jmsg(jcr, M_NOTSAVED, 0, _("%s signature digest initialization failed\n"),
121 stream_to_ascii(signing_algorithm));
127 /** Enable encryption */
128 if (jcr->crypto.pki_encrypt) {
129 ff_pkt->flags |= FO_ENCRYPT;
135 bool crypto_session_start(JCR *jcr)
137 crypto_cipher_t cipher = (crypto_cipher_t) me->pki_cipher;
140 * Create encryption session data and a cached, DER-encoded session data
141 * structure. We use a single session key for each backup, so we'll encode
142 * the session data only once.
144 if (jcr->crypto.pki_encrypt) {
147 /** Create per-job session encryption context */
148 jcr->crypto.pki_session = crypto_session_new(cipher, jcr->crypto.pki_recipients);
149 if (!jcr->crypto.pki_session) {
150 Jmsg(jcr, M_FATAL, 0, _("Unsupported cipher on this system.\n"));
154 /** Get the session data size */
155 if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)0, &size)) {
156 Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n"));
160 /** Allocate buffer */
161 jcr->crypto.pki_session_encoded = get_memory(size);
163 /** Encode session data */
164 if (!crypto_session_encode(jcr->crypto.pki_session, (uint8_t *)jcr->crypto.pki_session_encoded, &size)) {
165 Jmsg(jcr, M_FATAL, 0, _("An error occurred while encrypting the stream.\n"));
169 /** ... and store the encoded size */
170 jcr->crypto.pki_session_encoded_size = size;
172 /** Allocate the encryption/decryption buffer */
173 jcr->crypto.crypto_buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE);
178 void crypto_session_end(JCR *jcr)
180 if (jcr->crypto.crypto_buf) {
181 free_pool_memory(jcr->crypto.crypto_buf);
182 jcr->crypto.crypto_buf = NULL;
184 if (jcr->crypto.pki_session) {
185 crypto_session_free(jcr->crypto.pki_session);
187 if (jcr->crypto.pki_session_encoded) {
188 free_pool_memory(jcr->crypto.pki_session_encoded);
189 jcr->crypto.pki_session_encoded = NULL;
193 bool crypto_session_send(JCR *jcr, BSOCK *sd)
197 /** Send our header */
198 Dmsg2(100, "Send hdr fi=%ld stream=%d\n", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA);
199 sd->fsend("%ld %d %lld", jcr->JobFiles, STREAM_ENCRYPTED_SESSION_DATA,
200 (int64_t)jcr->ff->statp.st_size);
202 sd->msg = jcr->crypto.pki_session_encoded;
203 sd->msglen = jcr->crypto.pki_session_encoded_size;
204 jcr->JobBytes += sd->msglen;
206 Dmsg1(100, "Send data len=%d\n", sd->msglen);
209 sd->signal(BNET_EOD);
213 bool crypto_terminate_digests(bctx_t &bctx)
221 ff_pkt = bctx.ff_pkt;
223 /** Terminate the signing digest and send it to the Storage daemon */
224 if (bctx.signing_digest) {
227 if ((bctx.sig = crypto_sign_new(jcr)) == NULL) {
228 Jmsg(jcr, M_FATAL, 0, _("Failed to allocate memory for crypto signature.\n"));
232 if (!crypto_sign_add_signer(bctx.sig, bctx.signing_digest, jcr->crypto.pki_keypair)) {
233 Jmsg(jcr, M_FATAL, 0, _("An error occurred while adding signer the stream.\n"));
237 /** Get signature size */
238 if (!crypto_sign_encode(bctx.sig, NULL, &size)) {
239 Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n"));
243 /** Grow the bsock buffer to fit our message if necessary */
244 if (sizeof_pool_memory(sd->msg) < (int32_t)size) {
245 sd->msg = realloc_pool_memory(sd->msg, size);
248 /** Send our header */
249 sd->fsend("%ld %ld 0", jcr->JobFiles, STREAM_SIGNED_DIGEST);
250 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
252 /** Encode signature data */
253 if (!crypto_sign_encode(bctx.sig, (uint8_t *)sd->msg, &size)) {
254 Jmsg(jcr, M_FATAL, 0, _("An error occurred while signing the stream.\n"));
260 sd->signal(BNET_EOD); /* end of checksum */
263 /** Terminate any digest and send it to Storage daemon */
267 sd->fsend("%ld %d 0", jcr->JobFiles, bctx.digest_stream);
268 Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
270 size = CRYPTO_DIGEST_MAX_SIZE;
272 /** Grow the bsock buffer to fit our message if necessary */
273 if (sizeof_pool_memory(sd->msg) < (int32_t)size) {
274 sd->msg = realloc_pool_memory(sd->msg, size);
277 if (!crypto_digest_finalize(bctx.digest, (uint8_t *)sd->msg, &size)) {
278 Jmsg(jcr, M_FATAL, 0, _("An error occurred finalizing signing the stream.\n"));
282 /* Keep the checksum if this file is a hardlink */
283 if (ff_pkt->linked) {
284 ff_pkt_set_link_digest(ff_pkt, bctx.digest_stream, sd->msg, size);
289 sd->signal(BNET_EOD); /* end of checksum */
292 /* Check if original file has a digest, and send it */
293 if (ff_pkt->type == FT_LNKSAVED && ff_pkt->digest) {
294 Dmsg2(300, "Link %s digest %d\n", ff_pkt->fname, ff_pkt->digest_len);
295 sd->fsend("%ld %d 0", jcr->JobFiles, ff_pkt->digest_stream);
297 sd->msg = check_pool_memory_size(sd->msg, ff_pkt->digest_len);
298 memcpy(sd->msg, ff_pkt->digest, ff_pkt->digest_len);
299 sd->msglen = ff_pkt->digest_len;
302 sd->signal(BNET_EOD); /* end of hardlink record */
308 void crypto_free(bctx_t &bctx)
311 crypto_digest_free(bctx.digest);
314 if (bctx.signing_digest) {
315 crypto_digest_free(bctx.signing_digest);
316 bctx.signing_digest = NULL;
319 crypto_sign_free(bctx.sig);