static bool test_ctr_op(const struct encrypt_desc *encrypt_desc, const char *description, int encrypt, PK11SymKey *sym_key, const char *encoded_cb, const char *output_cb, const char *input_name, const char *input, const char *output_name, const char *output) { const char *op = encrypt ? "encrypt" : "decrypt"; bool ok = TRUE; chunk_t cb = decode_to_chunk("input counter-block: ", encoded_cb); chunk_t tmp = decode_to_chunk(input_name, input); chunk_t expected_output = decode_to_chunk(output_name, output); chunk_t expected_cb = decode_to_chunk("expected counter-block: ", output_cb); /* do_crypt modifies the data and IV in place. */ encrypt_desc->encrypt_ops->do_crypt(encrypt_desc, tmp.ptr, tmp.len, sym_key, cb.ptr, encrypt); if (!verify_chunk(op, expected_output, tmp)) { DBG(DBG_CRYPT, DBG_log("test_ctr_op: %s: %s: output does not match", description, op)); ok = FALSE; } if (!verify_chunk("counter-block", expected_cb, cb)) { DBG(DBG_CRYPT, DBG_log("test_ctr_op: %s: %s: counter-block does not match", description, op)); ok = FALSE; } freeanychunk(cb); freeanychunk(expected_cb); freeanychunk(tmp); freeanychunk(expected_output); return ok; }
/* * Turn the raw key into a SECItem and then SymKey. * * Since slots are referenced counted and ImportSymKey adds a * reference, immediate freeing of the local slot is possible. * * ImportSymKey makes a copy of the key chunk so that can also be * released. */ PK11SymKey *decode_to_key(CK_MECHANISM_TYPE cipher_mechanism, const char *encoded_key) { chunk_t raw_key = decode_to_chunk("key", encoded_key); PK11SymKey *sym_key = chunk_to_symkey(cipher_mechanism, raw_key); freeanychunk(raw_key); return sym_key; }
/* * Turn the raw key into SymKey. */ PK11SymKey *decode_to_key(const struct encrypt_desc *encrypt_desc, const char *encoded_key) { chunk_t raw_key = decode_to_chunk("raw_key", encoded_key); PK11SymKey *symkey = symkey_from_chunk("symkey", DBG_CRYPT, &encrypt_desc->common, raw_key); freeanychunk(raw_key); return symkey; }
static bool test_gcm_vector(const struct encrypt_desc *encrypt_desc, const struct gcm_test_vector *test) { DBG(DBG_CRYPT, DBG_log("test_gcm_vector: enter")); const size_t salt_size = encrypt_desc->salt_size; bool ok = TRUE; PK11SymKey *sym_key = decode_to_key(encrypt_desc, test->key); chunk_t salted_iv = decode_to_chunk("salted IV", test->salted_iv); passert(salted_iv.len == encrypt_desc->wire_iv_size + salt_size); chunk_t salt = { .ptr = salted_iv.ptr, .len = salt_size }; chunk_t wire_iv = { .ptr = salted_iv.ptr + salt_size, .len = salted_iv.len - salt_size }; chunk_t aad = decode_to_chunk("AAD", test->aad); chunk_t plaintext = decode_to_chunk("plaintext", test->plaintext); chunk_t ciphertext = decode_to_chunk("ciphertext", test->ciphertext); passert(plaintext.len == ciphertext.len); size_t len = plaintext.len; chunk_t tag = decode_to_chunk("tag", test->tag); chunk_t text_and_tag; text_and_tag.len = len + tag.len; text_and_tag.ptr = alloc_bytes(text_and_tag.len, "GCM data"); /* macro to test encryption or decryption * * This would be better as a function but it uses too many locals * from test_gcm_vector to be pleasant: * text_and_tag, len, tag, aad, salt, wire_iv, sym_key */ # define try(enc, desc, from, to) { \ memcpy(text_and_tag.ptr, from.ptr, from.len); \ text_and_tag.len = len + tag.len; \ DBG(DBG_CRYPT, \ DBG_log("test_gcm_vector: %s: aad-size=%zd salt-size=%zd wire-IV-size=%zd text-size=%zd tag-size=%zd", \ desc, aad.len, salt.len, wire_iv.len, len, tag.len); \ DBG_dump_chunk("test_gcm_vector: text+tag on call", \ text_and_tag)); \ if (!encrypt_desc->encrypt_ops->do_aead(encrypt_desc, \ salt.ptr, salt.len, \ wire_iv.ptr, wire_iv.len, \ aad.ptr, aad.len, \ text_and_tag.ptr, \ len, tag.len, \ sym_key, enc) || \ !verify_chunk_data("output ciphertext", \ to, text_and_tag.ptr) || \ !verify_chunk_data("TAG", tag, text_and_tag.ptr + len)) \ ok = FALSE; \ DBG(DBG_CRYPT, DBG_dump_chunk("test_gcm_vector: text+tag on return", \ text_and_tag)); \ } /* test decryption */ memcpy(text_and_tag.ptr + len, tag.ptr, tag.len); try(FALSE, "decrypt", ciphertext, plaintext); /* test encryption */ memset(text_and_tag.ptr + len, '\0', tag.len); try(TRUE, "encrypt", plaintext, ciphertext); # undef try freeanychunk(salted_iv); freeanychunk(aad); freeanychunk(plaintext); freeanychunk(ciphertext); freeanychunk(tag); freeanychunk(text_and_tag); /* Clean up. */ release_symkey(__func__, "sym_key", &sym_key); DBG(DBG_CRYPT, DBG_log("test_gcm_vector: %s", ok ? "passed" : "failed")); return ok; } bool test_gcm_vectors(const struct encrypt_desc *encrypt_desc, const struct gcm_test_vector *tests) { bool ok = TRUE; const struct gcm_test_vector *test; for (test = tests; test->key != NULL; test++) { if (!test_gcm_vector(encrypt_desc, test)) { ok = FALSE; } } return ok; }