/** * crypto_aesctr_stream(stream, inbuf, outbuf, buflen): * Generate the next ${buflen} bytes of the AES-CTR stream and xor them with * bytes from ${inbuf}, writing the result into ${outbuf}. If the buffers * ${inbuf} and ${outbuf} overlap, they must be identical. */ void crypto_aesctr_stream(struct crypto_aesctr * stream, const uint8_t * inbuf, uint8_t * outbuf, size_t buflen) { uint8_t pblk[16]; size_t pos; int bytemod; for (pos = 0; pos < buflen; pos++) { /* How far through the buffer are we? */ bytemod = stream->bytectr % 16; /* Generate a block of cipherstream if needed. */ if (bytemod == 0) { be64enc(pblk, stream->nonce); be64enc(pblk + 8, stream->bytectr / 16); AES_encrypt(pblk, stream->buf, stream->key); } /* Encrypt a byte. */ outbuf[pos] = inbuf[pos] ^ stream->buf[bytemod]; /* Move to the next byte of cipherstream. */ stream->bytectr += 1; } }
/** * proto_lbs_response_params2(Q, ID, blklen, blkno, lastblk): * Send a PARAMS2 response with ID ${ID} to the write queue ${Q} indicating * that the block size is ${blklen} bytes, the next available block # is * ${blkno}, and the last block written was ${lastblk}. */ int proto_lbs_response_params2(struct netbuf_write * Q, uint64_t ID, uint32_t blklen, uint64_t blkno, uint64_t lastblk) { uint8_t * wbuf; /* Get a packet data buffer. */ if ((wbuf = wire_writepacket_getbuf(Q, ID, 20)) == NULL) goto err0; /* Write the packet data. */ be32enc(&wbuf[0], blklen); be64enc(&wbuf[4], blkno); be64enc(&wbuf[12], lastblk); /* Finish the packet. */ if (wire_writepacket_done(Q, wbuf, 20)) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); }
static int test_be64enc() { uint8_t buf[8]; be64enc(buf, 0x0102030405060708ULL); if(buf[0] != 1 || buf[1] != 2 || buf[2] != 3 || buf[3] != 4 || buf[4] != 5 || buf[5] != 6 || buf[6] != 7 || buf[7] != 8) return -1; be64enc(buf, 0xffefdfcfbfaf9f8fULL); if(buf[0] != 0xff || buf[1] != 0xef || buf[2] != 0xdf || buf[3] != 0xcf || buf[4] != 0xbf || buf[5] != 0xaf || buf[6] != 0x9f || buf[7] != 0x8f) return -1; return 0; }
static const char *tencode(int t, uint64_t val) { static char res[64]; uint8_t buf[16]; bool be = t > 0; int i; if (t < 0) t = -t; memset(buf, 0xFC, sizeof(buf)); if (be) { switch (t) { case 2: be16enc(buf, val); break; case 4: be32enc(buf, val); break; case 8: be64enc(buf, val); break; } } else { switch (t) { case 2: le16enc(buf, val); break; case 4: le32enc(buf, val); break; case 8: le64enc(buf, val); break; } } for (i = t; i < (int)sizeof(buf); i++) { if (buf[i] != 0xFC) return "OVER"; } snprintf(res, sizeof(res), "%02X %02X %02X %02X %02X %02X %02X %02X ", buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); res[t*3 - 1] = 0; return res; }
/** * proto_lbs_response_append(Q, ID, status, blkno): * Send an APPEND response with ID ${ID} to the write queue ${Q} with status * code ${status} and next block number ${blkno} if ${status} is zero. */ int proto_lbs_response_append(struct netbuf_write * Q, uint64_t ID, uint32_t status, uint64_t blkno) { uint8_t * wbuf; size_t len; /* Compute the response length. */ len = (status == 0) ? 12 : 4; /* Get a packet data buffer. */ if ((wbuf = wire_writepacket_getbuf(Q, ID, len)) == NULL) goto err0; /* Write the packet data. */ be32enc(&wbuf[0], status); if (status == 0) be64enc(&wbuf[4], blkno); /* Finish the packet. */ if (wire_writepacket_done(Q, wbuf, len)) goto err0; /* Success! */ return (0); err0: /* Failure! */ return (-1); }
/** * proto_crypt_enc(ibuf, len, obuf, k): * Encrypt ${len} bytes from ${ibuf} into PCRYPT_ESZ bytes using the keys in * ${k}, and write the result into ${obuf}. */ void proto_crypt_enc(uint8_t * ibuf, size_t len, uint8_t obuf[PCRYPT_ESZ], struct proto_keys * k) { HMAC_SHA256_CTX ctx; uint8_t pnum_exp[8]; /* Sanity-check the length. */ assert(len <= PCRYPT_MAXDSZ); /* Copy the decrypted data into the encrypted buffer. */ memcpy(obuf, ibuf, len); /* Pad up to PCRYPT_MAXDSZ with zeroes. */ memset(&obuf[len], 0, PCRYPT_MAXDSZ - len); /* Add the length. */ be32enc(&obuf[PCRYPT_MAXDSZ], len); /* Encrypt the buffer in-place. */ crypto_aesctr_buf(k->k_aes, k->pnum, obuf, obuf, PCRYPT_MAXDSZ + 4); /* Append an HMAC. */ be64enc(pnum_exp, k->pnum); HMAC_SHA256_Init(&ctx, k->k_hmac, 32); HMAC_SHA256_Update(&ctx, obuf, PCRYPT_MAXDSZ + 4); HMAC_SHA256_Update(&ctx, pnum_exp, 8); HMAC_SHA256_Final(&obuf[PCRYPT_MAXDSZ + 4], &ctx); /* Increment packet number. */ k->pnum += 1; }
void write_kdfp(uint8_t *addr, kdfp *kdfp) { uint64_t *N = (uint64_t *) (addr + SALT_LEN); uint32_t *r = (uint32_t *) (N + 1); uint32_t *p = (uint32_t *) (r + 1); memcpy(addr, kdfp->salt, SALT_LEN); be64enc(N, kdfp->N); be32enc(r, kdfp->r); be32enc(p, kdfp->p); }
/** * mkval(X, Y, buf): * Write the 40-byte value * offset length * ------ ------ * 0 8 64-bit big-endian X * 2^16 + Y * 8 32 sha256(\001.(64-bit big-endian X).(64-bit big-endian Y)) * into ${buf}. */ void mkval(uint64_t X, uint64_t Y, uint8_t * buf) { SHA256_CTX ctx; uint8_t hbuf[17]; /* Store big-endian X * 2^16 + Y. */ be64enc(&buf[0], (X << 16) + Y); /* Generate \001.X.Y. */ hbuf[0] = 0; be64enc(&hbuf[1], X); be64enc(&hbuf[9], Y); /* Compute sha256(\001.X.Y). */ SHA256_Init(&ctx); SHA256_Update(&ctx, hbuf, 17); SHA256_Final(&buf[8], &ctx); }
static void vhd_make_footer(struct vhd_footer *footer, uint64_t image_size, uint32_t disk_type, uint64_t data_offset) { uuid_t id; memset(footer, 0, sizeof(*footer)); be64enc(&footer->cookie, VHD_FOOTER_COOKIE); be32enc(&footer->features, VHD_FEATURES_RESERVED); be32enc(&footer->version, VHD_VERSION); be64enc(&footer->data_offset, data_offset); be32enc(&footer->timestamp, vhd_timestamp()); be32enc(&footer->creator_tool, VHD_CREATOR_TOOL); be32enc(&footer->creator_version, VHD_CREATOR_VERSION); be32enc(&footer->creator_os, VHD_CREATOR_OS); be64enc(&footer->original_size, image_size); be64enc(&footer->current_size, image_size); vhd_geometry(footer, image_size); be32enc(&footer->disk_type, disk_type); mkimg_uuid(&id); vhd_uuid_enc(&footer->id, &id); be32enc(&footer->checksum, vhd_checksum(footer, sizeof(*footer))); }
/** * crypto_session_sign(CS, buf, buflen, sig): * Generate sig = write_auth(buf). */ void crypto_session_sign(CRYPTO_SESSION * CS, const uint8_t * buf, size_t buflen, uint8_t sig[32]) { uint8_t nonce[8]; /* Convert nonce to 8-byte big-endian format, and increment. */ be64enc(nonce, CS->auth_write_nonce); CS->auth_write_nonce += 1; /* Generate hash. */ crypto_hash_data_key_2(CS->auth_write, 32, nonce, 8, buf, buflen, sig); }
static bool stratum_notify_m7(struct stratum_ctx *sctx, json_t *params) { const char *job_id, *prevblock, *accroot, *merkleroot, *version, *ntime; int height; bool clean; job_id = json_string_value(json_array_get(params, 0)); prevblock = json_string_value(json_array_get(params, 1)); accroot = json_string_value(json_array_get(params, 2)); merkleroot = json_string_value(json_array_get(params, 3)); height = json_integer_value(json_array_get(params, 4)); version = json_string_value(json_array_get(params, 5)); ntime = json_string_value(json_array_get(params, 6)); clean = json_is_true(json_array_get(params, 7)); if (!job_id || !prevblock || !accroot || !merkleroot || !version || !height || !ntime || strlen(prevblock) != 32*2 || strlen(accroot) != 32*2 || strlen(merkleroot) != 32*2 || strlen(ntime) != 8*2 || strlen(version) != 2*2) { applog(LOG_ERR, "Stratum (M7) notify: invalid parameters"); return false; } pthread_mutex_lock(&sctx->work_lock); if (!sctx->job.job_id || strcmp(sctx->job.job_id, job_id)) { sctx->job.xnonce2 = (unsigned char *)realloc(sctx->job.xnonce2, sctx->xnonce2_size); memset(sctx->job.xnonce2, 0, sctx->xnonce2_size); } free(sctx->job.job_id); sctx->job.job_id = strdup(job_id); hex2bin(sctx->job.m7prevblock, prevblock, 32); hex2bin(sctx->job.m7accroot, accroot, 32); hex2bin(sctx->job.m7merkleroot, merkleroot, 32); be64enc(sctx->job.m7height, height); hex2bin(sctx->job.m7version, version, 2); hex2bin(sctx->job.m7ntime, ntime, 8); sctx->job.clean = clean; sctx->job.diff = sctx->next_diff; pthread_mutex_unlock(&sctx->work_lock); return true; }
static void le_lebuffer_copyfromdesc(struct lance_softc *sc, void *tov, int off, int len) { struct le_lebuffer_softc *lesc = (struct le_lebuffer_softc *)sc; caddr_t to = tov; for (; len >= 8; len -= 8, off += 8, to += 8) be64enc(to, bus_read_8(lesc->sc_bres, off)); for (; len >= 4; len -= 4, off += 4, to += 4) be32enc(to, bus_read_4(lesc->sc_bres, off)); for (; len >= 2; len -= 2, off += 2, to += 2) be16enc(to, bus_read_2(lesc->sc_bres, off)); if (len == 1) *to = bus_read_1(lesc->sc_bres, off); }
/** * crypto_session_verify(CS, buf, buflen, sig): * Verify that sig = read_auth(buf). Return non-zero if the signature * does not match. */ int crypto_session_verify(CRYPTO_SESSION * CS, const uint8_t * buf, size_t buflen, const uint8_t sig[32]) { uint8_t nonce[8]; uint8_t sig_actual[32]; /* Convert nonce to 8-byte big-endian format, and increment. */ be64enc(nonce, CS->auth_read_nonce); CS->auth_read_nonce += 1; /* Generate hash. */ crypto_hash_data_key_2(CS->auth_read, 32, nonce, 8, buf, buflen, sig_actual); /* Determine if the signatures match. */ if (crypto_verify_bytes(sig, sig_actual, 32)) return (1); else return (0); }
/** * proto_crypt_dec(ibuf, obuf, k): * Decrypt PCRYPT_ESZ bytes from ${ibuf} using the keys in ${k}. If the data * is valid, write it into ${obuf} and return the length; otherwise, return * -1. */ ssize_t proto_crypt_dec(uint8_t ibuf[PCRYPT_ESZ], uint8_t * obuf, struct proto_keys * k) { HMAC_SHA256_CTX ctx; uint8_t hbuf[32]; uint8_t pnum_exp[8]; size_t len; /* Verify HMAC. */ be64enc(pnum_exp, k->pnum); HMAC_SHA256_Init(&ctx, k->k_hmac, 32); HMAC_SHA256_Update(&ctx, ibuf, PCRYPT_MAXDSZ + 4); HMAC_SHA256_Update(&ctx, pnum_exp, 8); HMAC_SHA256_Final(hbuf, &ctx); if (crypto_verify_bytes(hbuf, &ibuf[PCRYPT_MAXDSZ + 4], 32)) return (-1); /* Decrypt the buffer in-place. */ crypto_aesctr_buf(k->k_aes, k->pnum, ibuf, ibuf, PCRYPT_MAXDSZ + 4); /* Increment packet number. */ k->pnum += 1; /* Parse length. */ len = be32dec(&ibuf[PCRYPT_MAXDSZ]); /* Make sure nobody is being evil here... */ if ((len == 0) || (len > PCRYPT_MAXDSZ)) return (-1); /* Copy the bytes into the output buffer. */ memcpy(obuf, ibuf, len); /* Return the decrypted length. */ return (len); }
static int vhd_dyn_write(int fd) { struct vhd_footer footer; struct vhd_dyn_header header; uint64_t imgsz; lba_t blk, blkcnt, nblks; uint32_t *bat; void *bitmap; size_t batsz; uint32_t sector; int bat_entries, error, entry; imgsz = image_get_size() * secsz; bat_entries = imgsz / VHD_BLOCK_SIZE; vhd_make_footer(&footer, imgsz, VHD_DISK_TYPE_DYNAMIC, sizeof(footer)); if (sparse_write(fd, &footer, sizeof(footer)) < 0) return (errno); memset(&header, 0, sizeof(header)); be64enc(&header.cookie, VHD_HEADER_COOKIE); be64enc(&header.data_offset, ~0ULL); be64enc(&header.table_offset, sizeof(footer) + sizeof(header)); be32enc(&header.version, VHD_VERSION); be32enc(&header.max_entries, bat_entries); be32enc(&header.block_size, VHD_BLOCK_SIZE); be32enc(&header.checksum, vhd_checksum(&header, sizeof(header))); if (sparse_write(fd, &header, sizeof(header)) < 0) return (errno); batsz = bat_entries * sizeof(uint32_t); batsz = (batsz + VHD_SECTOR_SIZE - 1) & ~(VHD_SECTOR_SIZE - 1); bat = malloc(batsz); if (bat == NULL) return (errno); memset(bat, 0xff, batsz); blkcnt = VHD_BLOCK_SIZE / secsz; sector = (sizeof(footer) + sizeof(header) + batsz) / VHD_SECTOR_SIZE; for (entry = 0; entry < bat_entries; entry++) { blk = entry * blkcnt; if (image_data(blk, blkcnt)) { be32enc(&bat[entry], sector); sector += (VHD_BLOCK_SIZE / VHD_SECTOR_SIZE) + 1; } } if (sparse_write(fd, bat, batsz) < 0) { free(bat); return (errno); } free(bat); bitmap = malloc(VHD_SECTOR_SIZE); if (bitmap == NULL) return (errno); memset(bitmap, 0xff, VHD_SECTOR_SIZE); blk = 0; blkcnt = VHD_BLOCK_SIZE / secsz; error = 0; nblks = image_get_size(); while (blk < nblks) { if (!image_data(blk, blkcnt)) { blk += blkcnt; continue; } if (sparse_write(fd, bitmap, VHD_SECTOR_SIZE) < 0) { error = errno; break; } error = image_copyout_region(fd, blk, blkcnt); if (error) break; blk += blkcnt; } free(bitmap); if (blk != nblks) return (error); if (sparse_write(fd, &footer, sizeof(footer)) < 0) return (errno); return (0); }
/* Do a round of deletes if appropriate. */ static int poke(struct deleteto * D) { uint64_t BIT; uint64_t X; uint8_t DeletedMarker[8]; /* If we're trying to shut down, don't do anything. */ if (D->shuttingdown) return (0); /* If operations are already in progress, don't do anything. */ if (! D->idle) return (0); /* Sanity-check. */ assert(D->npending == 0); /* * Store the M to object DeletedMarker if it's a multiple of 256 * (periodic stores so DeletedMarker doesn't fall too far behind * reality if we are doing a very large number of deletes) and we * haven't yet stored this value of M. * * If we crash and restart, we may end up re-issuing as many as ~256 * deletes;but this is better than more-frequent updating of the * deletion marker since (a) DELETEs are free but PUTs aren't, and * (b) we want to optimize for the common case, which is a long-lived * lbs-s3 process. */ if ((D->M % 256 == 0) && (D->updateDeletedTo == 1)) { D->idle = 0; D->npending += 1; be64enc(DeletedMarker, D->M); if (proto_s3_request_put(D->Q, D->bucket, "DeletedMarker", 8, DeletedMarker, callback_done, D)) goto err0; D->updateDeletedTo = 0; } /* If we can't delete anything, don't. */ if (D->N <= D->M) return (0); /* * We want to run one step of the DeleteTo algorithm: Delete or * overwrite objects which are needed by M but not by M+1, and * increment M. If nothing needs to be done, we'll repeat the * process for the new (incremented) M. */ /* For each bit... */ for (BIT = 1; BIT != 0; BIT += BIT) { /* If it's set in M but not in M+1... */ if (((D->M & BIT) == BIT) && (((D->M + 1) & BIT) == 0)) { /* M - M % BIT is deletable... */ X = D->M - (D->M % BIT); /* ... unless it's a power of two. */ if (X == BIT) continue; /* Issue a delete. */ D->idle = 0; D->npending += 1; if (proto_s3_request_delete(D->Q, D->bucket, objmap(X), callback_done, D)) goto err0; } } /* * Powers of 2 will never be DELETEd, and multiples of 256 can't be * deleted until at least 256 iterations later (since N = ...abcdefgh) * needs the file ...00000000 to still exist), but we don't need the * data for M any more; so issue an empty PUT for it if it falls into * one of those two categories. */ if (((D->M & (D->M-1)) == 0) || ((D->M % 256) == 0)) { D->idle = 0; D->npending += 1; if (proto_s3_request_put(D->Q, D->bucket, objmap(D->M), 0, NULL, callback_done, D)) goto err0; } /* We've issued all the deletes needed for this M. */ D->M = D->M + 1; D->updateDeletedTo = 1; /* If we haven't found anything to do yet, poke ourselves again. */ if (D->idle) return (poke(D)); /* Success! */ return (0); err0: /* Failure! */ return (-1); }