END_TEST /******************************************************************************* * test for chunk_hash_static[_inc]() */ START_TEST(test_chunk_hash_static) { chunk_t in; u_int32_t out, hash_a, hash_b, hash_inc = 0x7b891a95; int i, count; count = countof(sip_vectors); in = chunk_alloca(count); for (i = 0; i < count; ++i) { in.ptr[i] = i; in.len = i; /* compared to chunk_mac() we only get half the value back */ out = chunk_hash_static(in); fail_unless(sipeq(&out, sip_vectors[i], 4), "test vector failed for %d bytes", i); } hash_a = chunk_hash_static_inc(in, out); ck_assert_int_eq(hash_a, hash_inc); hash_b = chunk_hash_static_inc(in, out); ck_assert_int_eq(hash_a, hash_b); }
END_TEST /******************************************************************************* * htoun/untoh */ START_TEST(test_htoun) { chunk_t net64, expected; uint16_t host16 = 513; uint32_t net16 = 0, host32 = 67305985; uint64_t net32 = 0, host64 = 578437695752307201ULL; net64 = chunk_alloca(16); memset(net64.ptr, 0, net64.len); expected = chunk_from_chars(0x00, 0x02, 0x01, 0x00); htoun16((char*)&net16 + 1, host16); ck_assert(chunk_equals(expected, chunk_from_thing(net16))); expected = chunk_from_chars(0x00, 0x00, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00); htoun32((uint16_t*)&net32 + 1, host32); ck_assert(chunk_equals(expected, chunk_from_thing(net32))); expected = chunk_from_chars(0x00, 0x00, 0x00, 0x00, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00); htoun64((uint32_t*)net64.ptr + 1, host64); ck_assert(chunk_equals(expected, net64)); }
/** * Generates a unique fingerprint of the pkcs10 request * by computing an MD5 hash over it */ chunk_t scep_generate_pkcs10_fingerprint(chunk_t pkcs10) { chunk_t digest = chunk_alloca(HASH_SIZE_MD5); hasher_t *hasher; hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); hasher->get_hash(hasher, pkcs10, digest.ptr); hasher->destroy(hasher); return chunk_to_hex(digest, NULL, FALSE); }
/** * read the last serial number from file */ static chunk_t read_serial(void) { chunk_t hex, serial = chunk_empty; char one[] = {0x01}; FILE *fd; fd = fopen(OPENAC_SERIAL, "r"); if (fd) { hex = chunk_alloca(64); hex.len = fread(hex.ptr, 1, hex.len, fd); if (hex.len) { /* remove any terminating newline character */ if (hex.ptr[hex.len-1] == '\n') { hex.len--; } serial = chunk_alloca((hex.len / 2) + (hex.len % 2)); serial = chunk_from_hex(hex, serial.ptr); } fclose(fd); } else { DBG1(DBG_LIB, " file '%s' does not exist yet - serial number " "set to 01", OPENAC_SERIAL); } if (!serial.len) { return chunk_clone(chunk_create(one, 1)); } if (chunk_increment(serial)) { /* overflow, prepend 0x01 */ return chunk_cat("cc", chunk_create(one, 1), serial); } return chunk_clone(serial); }
/** * Generate a transaction id as the MD5 hash of an public key * the transaction id is also used as a unique serial number */ void scep_generate_transaction_id(public_key_t *key, chunk_t *transID, chunk_t *serialNumber) { chunk_t digest = chunk_alloca(HASH_SIZE_MD5); chunk_t keyEncoding = chunk_empty, keyInfo; hasher_t *hasher; bool msb_set; u_char *pos; key->get_encoding(key, PUBKEY_ASN1_DER, &keyEncoding); keyInfo = asn1_wrap(ASN1_SEQUENCE, "mm", asn1_algorithmIdentifier(OID_RSA_ENCRYPTION), asn1_bitstring("m", keyEncoding)); hasher = lib->crypto->create_hasher(lib->crypto, HASH_MD5); if (!hasher || !hasher->get_hash(hasher, keyInfo, digest.ptr)) { memset(digest.ptr, 0, digest.len); } DESTROY_IF(hasher); free(keyInfo.ptr); /* is the most significant bit of the digest set? */ msb_set = (*digest.ptr & 0x80) == 0x80; /* allocate space for the serialNumber */ serialNumber->len = msb_set + digest.len; serialNumber->ptr = malloc(serialNumber->len); /* the serial number as the two's complement of the digest */ pos = serialNumber->ptr; if (msb_set) { *pos++ = 0x00; } memcpy(pos, digest.ptr, digest.len); /* the transaction id is the serial number in hex format */ *transID = chunk_to_hex(digest, NULL, TRUE); }
static bool do_test_mct(test_vector_t *test) { crypter_t *crypter; chunk_t prev, *input, *output; int i, j; crypter = lib->crypto->create_crypter(lib->crypto, ENCR_AES_CBC, test->key.len); if (!crypter) { DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported", encryption_algorithm_names, ENCR_AES_CBC, test->key.len * 8); return FALSE; } input = ctx.decrypt ? &test->cipher : &test->plain; output = ctx.decrypt ? &test->plain : &test->cipher; if (crypter->get_block_size(crypter) != input->len) { DBG1(DBG_APP, "MCT only works for input with a length of one block"); crypter->destroy(crypter); return FALSE; } prev = chunk_alloca(input->len); /* assume initial IV as previous output */ *output = chunk_clone(test->iv); for (i = 0; i < 100; i++) { if (i > 0) { /* we copied the original lines already */ fprintf(ctx.out, "COUNT = %d\n", i); fprintf(ctx.out, "KEY = %+B\n", &test->key); fprintf(ctx.out, "IV = %+B\n", &test->iv); fprintf(ctx.out, "%s = %+B\n", ctx.decrypt ? "CIPHERTEXT" : "PLAINTEXT", input); } if (!crypter->set_key(crypter, test->key)) { DBG1(DBG_APP, "failed to set key"); return FALSE; } for (j = 0; j < 1000; j++) { /* store previous output as it is used as input after next */ memcpy(prev.ptr, output->ptr, prev.len); chunk_free(output); if (!do_crypt(crypter, test)) { crypter->destroy(crypter); return FALSE; } /* prepare the next IV (our API does not allow incremental calls) */ if (ctx.decrypt) { memcpy(test->iv.ptr, input->ptr, test->iv.len); } else { memcpy(test->iv.ptr, output->ptr, test->iv.len); } /* the previous output is the next input */ memcpy(input->ptr, prev.ptr, input->len); } fprintf(ctx.out, "%s = %+B\n\n", ctx.decrypt ? "PLAINTEXT" : "CIPHERTEXT", output); /* derive key for next round */ switch (test->key.len) { case 16: memxor(test->key.ptr, output->ptr, output->len); break; case 24: memxor(test->key.ptr, prev.ptr + 8, 8); memxor(test->key.ptr + 8, output->ptr, output->len); break; case 32: memxor(test->key.ptr, prev.ptr, prev.len); memxor(test->key.ptr + prev.len, output->ptr, output->len); break; } /* the current output is used as IV for the next round */ memcpy(test->iv.ptr, output->ptr, test->iv.len); } crypter->destroy(crypter); /* we return FALSE as we print the output ourselves */ return FALSE; }
static bool do_test_gcm(test_vector_t *test) { encryption_algorithm_t alg; chunk_t key, iv; aead_t *aead; size_t saltlen, ivlen; switch (ctx.icvlen / 8) { case 8: alg = ENCR_AES_GCM_ICV8; break; case 12: alg = ENCR_AES_GCM_ICV12; break; case 16: alg = ENCR_AES_GCM_ICV16; break; default: DBG1(DBG_APP, "unsupported ICV length: %d", ctx.icvlen); return FALSE; } aead = lib->crypto->create_aead(lib->crypto, alg, test->key.len, 4); if (!aead) { DBG1(DBG_APP, "algorithm %N or key length (%d bits) not supported", encryption_algorithm_names, alg, test->key.len * 8); return FALSE; } /* our API is quite RFC 4106 specific, that is, part of the IV is provided * at the end of the key. */ saltlen = aead->get_key_size(aead) - test->key.len; ivlen = aead->get_iv_size(aead); if (ctx.ivlen / 8 != saltlen + ivlen) { DBG1(DBG_APP, "unsupported IV length: %d", ctx.ivlen); aead->destroy(aead); return FALSE; } if (!test->external_iv) { rng_t *rng; /* the IV consists of saltlen random bytes (usually additional keymat) * followed by a counter, zero here */ test->iv = chunk_alloc(saltlen + ivlen); memset(test->iv.ptr, 0, test->iv.len); rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG); if (!rng || !rng->get_bytes(rng, saltlen, test->iv.ptr)) { DBG1(DBG_APP, "failed to generate IV"); DESTROY_IF(rng); aead->destroy(aead); return FALSE; } rng->destroy(rng); } key = chunk_alloca(test->key.len + saltlen); memcpy(key.ptr, test->key.ptr, test->key.len); memcpy(key.ptr + test->key.len, test->iv.ptr, saltlen); iv = chunk_alloca(ivlen); memcpy(iv.ptr, test->iv.ptr + saltlen, iv.len); if (!aead->set_key(aead, key)) { DBG1(DBG_APP, "failed to set key"); aead->destroy(aead); return FALSE; } if (ctx.decrypt) { /* the ICV is expected to follow the cipher text */ chunk_t cipher = chunk_cata("cc", test->cipher, test->icv); /* store if the verification of the ICV verification is successful */ test->success = aead->decrypt(aead, cipher, test->aad, iv, &test->plain); } else { if (!aead->encrypt(aead, test->plain, test->aad, iv, &test->cipher)) { DBG1(DBG_APP, "encryption failed"); aead->destroy(aead); return FALSE; } /* copy ICV from the end of the cipher text */ test->icv = chunk_alloc(ctx.icvlen / 8); test->cipher.len -= test->icv.len; memcpy(test->icv.ptr, test->cipher.ptr + test->cipher.len, test->icv.len); } aead->destroy(aead); return TRUE; }