// // Flatten the valid iolist to the buffer of // appropriate size pointed to by ptr // uint8_t *iolist_flatten(term_t l, uint8_t *ptr) { if (is_nil(l)) return ptr; if (is_cons(l)) { do { uint32_t *term_data = peel_cons(l); term_t e = term_data[0]; if (is_int(e)) *ptr++ = int_value(e); else { assert(is_list(e) || (is_boxed(e) && is_binary(peel_boxed(e)))); ptr = iolist_flatten(e, ptr); } l = term_data[1]; if (is_boxed(l) && is_binary(peel_boxed(l))) return iolist_flatten(l, ptr); } while (is_cons(l)); assert(is_nil(l)); } else // is_binary() { bits_t bs, to; bits_get_real(peel_boxed(l), &bs); bits_init_buf(ptr, (bs.ends +7) /8, &to); ptr += (bs.ends - bs.starts) /8; bits_copy(&bs, &to); assert(bs.starts == bs.ends); } return ptr; }
term_t cbif_exor2(proc_t *proc, term_t *regs) { term_t Bin1 = regs[0]; term_t Bin2 = regs[1]; if (!is_list(Bin1) && !is_boxed_binary(Bin1)) badarg(Bin1); if (!is_list(Bin2) && !is_boxed_binary(Bin2)) badarg(Bin2); int sz1 = iolist_size(Bin1); if (sz1 < 0) badarg(Bin1); int sz2 = iolist_size(Bin2); if (sz2 != sz1) badarg(Bin2); assert(sz1 <= 65536); //TODO: use heap_tmp_buf for larger binaries uint8_t data1[sz1]; iolist_flatten(Bin1, data1); uint8_t data2[sz2]; iolist_flatten(Bin2, data2); uint8_t *data3; term_t result = heap_make_bin(&proc->hp, sz1, &data3); for (int i = 0; i < sz1; i++) data3[i] = data1[i] ^ data2[i]; return result; }
term_t cbif_aes_cbc_crypt4(proc_t *proc, term_t *regs) { term_t Key = regs[0]; term_t IVec = regs[1]; term_t Data = regs[2]; term_t Dir = regs[3]; if (!is_list(Key) && !is_boxed_binary(Key)) badarg(Key); if (!is_boxed_binary(IVec)) badarg(IVec); if (!is_list(Data) && !is_boxed_binary(Data)) badarg(Data); if (!is_bool(Dir)) badarg(Dir); int key_size = iolist_size(Key); if (key_size < AES_MIN_KEY_SIZE || key_size > AES_MAX_KEY_SIZE) badarg(Key); uint8_t key_buf[key_size]; iolist_flatten(Key, key_buf); bits_t src, dst; bits_get_real(peel_boxed(IVec), &src); if (src.ends -src.starts != AES_BLOCK_SIZE *8) badarg(IVec); uint8_t ivec_buf[AES_BLOCK_SIZE]; bits_init_buf(ivec_buf, AES_BLOCK_SIZE, &dst); bits_copy(&src, &dst); int data_size = iolist_size(Data); if (data_size < 0) badarg(Data); assert(data_size <= 65536); //TODO: use heap_tmp_buf for larger Data uint8_t data_buf[data_size]; iolist_flatten(Data, data_buf); struct CBC_CTX(struct aes_ctx, AES_BLOCK_SIZE) ctx; if (Dir == A_TRUE) aes_set_encrypt_key((struct aes_ctx *)&ctx, key_size, key_buf); else aes_set_decrypt_key((struct aes_ctx *)&ctx, key_size, key_buf); CBC_SET_IV(&ctx, ivec_buf); uint8_t *ptr; term_t cipher_text = heap_make_bin(&proc->hp, data_size, &ptr); if (Dir == A_TRUE) CBC_ENCRYPT(&ctx, aes_encrypt, data_size, ptr, data_buf); else CBC_DECRYPT(&ctx, aes_decrypt, data_size, ptr, data_buf); return cipher_text; }
term_t cbif_sha_update2(proc_t *proc, term_t *regs) { term_t Context = regs[0]; term_t Data = regs[1]; if (!is_boxed_binary(Context)) badarg(Context); bits_t bs, dst; bits_get_real(peel_boxed(Context), &bs); if (bs.ends -bs.starts != sizeof(struct sha1_ctx) *8) badarg(Context); struct sha1_ctx ctx; bits_init_buf((uint8_t *)&ctx, sizeof(ctx), &dst); bits_copy(&bs, &dst); if (!is_boxed_binary(Data) && !is_list(Data)) badarg(Data); int sz = iolist_size(Data); if (sz < 0) badarg(Data); assert(sz <= 65536); //TODO: use heap_tmp_buf for larger Data uint8_t buf[sz]; iolist_flatten(Data, buf); sha1_update(&ctx, sz, buf); uint8_t *ptr; term_t bin = heap_make_bin(&proc->hp, sizeof(ctx), &ptr); memcpy(ptr, &ctx, sizeof(ctx)); return bin; }
term_t cbif_sha_mac_n3(proc_t *proc, term_t *regs) { term_t Key = regs[0]; term_t Data = regs[1]; term_t Size = regs[2]; if (!is_list(Key) && !is_boxed_binary(Key)) badarg(Key); if (!is_list(Data) && !is_boxed_binary(Data)) badarg(Data); if (!is_int(Size)) badarg(Size); int trunc_size = int_value(Size); if (trunc_size < 1 || trunc_size > SHA1_DIGEST_SIZE) badarg(Size); int key_size = iolist_size(Key); if (key_size < 0) badarg(Key); assert(key_size <= 65536); // TODO: use heap_tmp_buf for a longer Key uint8_t key_buf[key_size]; iolist_flatten(Key, key_buf); int data_size = iolist_size(Data); if (data_size < 0) badarg(Data); assert(data_size <= 65536); // TODO: use heap_tmp_buf for larger Data uint8_t data_buf[data_size]; iolist_flatten(Data, data_buf); struct hmac_sha1_ctx ctx; hmac_sha1_set_key(&ctx, key_size, key_buf); hmac_sha1_update(&ctx, data_size, data_buf); uint8_t *ptr; term_t mac = heap_make_bin(&proc->hp, trunc_size, &ptr); hmac_sha1_digest(&ctx, trunc_size, ptr); return mac; }
term_t cbif_sha1(proc_t *proc, term_t *regs) { term_t Data = regs[0]; if (!is_boxed_binary(Data) && !is_list(Data)) badarg(Data); int sz = iolist_size(Data); if (sz < 0) badarg(Data); assert(sz <= 65536); //TODO: use heap_tmp_buf for larger Data uint8_t buf[sz]; iolist_flatten(Data, buf); struct sha1_ctx ctx; sha1_init(&ctx); sha1_update(&ctx, sz, buf); uint8_t *ptr; term_t bin = heap_make_bin(&proc->hp, SHA1_DIGEST_SIZE, &ptr); sha1_digest(&ctx, SHA1_DIGEST_SIZE, ptr); return bin; }