/*
 * @brief Encrypt an ldb value using an aead algorithm.
 *
 * This function uses the samba internal implementation to perform the encryption. However
 * the encrypted data and tag are stored in a manner compatible with gnutls,
 * so the gnutls aead functions can be used to decrypt and verify the data.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param val  The ldb value to encrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return The encrypted ldb_val, or data_blob_null if there was an error.
 */
static struct ldb_val samba_encrypt_aead(int *err,
					 TALLOC_CTX *ctx,
					 struct ldb_context *ldb,
					 const struct ldb_val val,
					 const struct es_data *data)
{
	struct aes_gcm_128_context cctx;
	struct EncryptedSecret *es = NULL;
	DATA_BLOB pt = data_blob_null;
	struct ldb_val enc = data_blob_null;
	DATA_BLOB key_blob = data_blob_null;
	int rc;
	TALLOC_CTX *frame = talloc_stackframe();

	es = makeEncryptedSecret(ldb, frame);
	if (es == NULL) {
		goto error_exit;
	}

	pt = makePlainText(frame, ldb, val);
	if (pt.length == 0) {
		goto error_exit;
	}

	/*
	 * Set the encryption key
	 */
	key_blob = get_key(data);
	if (key_blob.length != AES_BLOCK_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedSecrets key size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_BLOCK_SIZE,
				       key_blob.length);
		goto error_exit;
	}

	/*
	 * Set the initialisation vector
	 */
	{
		uint8_t *iv = talloc_zero_size(frame, AES_GCM_128_IV_SIZE);
		if (iv == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocating iv\n");
			goto error_exit;
		}

		generate_random_buffer(iv, AES_GCM_128_IV_SIZE);

		es->iv.length = AES_GCM_128_IV_SIZE;
		es->iv.data   = iv;
	}

	/*
	 * Encrypt the value, and append the GCM digest to the encrypted
	 * data so that it can be decrypted and validated by the
	 * gnutls aead decryption routines.
	 */
	{
		uint8_t *ct = talloc_zero_size(frame, pt.length + AES_BLOCK_SIZE);
		if (ct == NULL) {
			ldb_oom(ldb);
			goto error_exit;
		}

		memcpy(ct, pt.data, pt.length);
		es->encrypted.length = pt.length + AES_BLOCK_SIZE;
		es->encrypted.data   = ct;
	}

	aes_gcm_128_init(&cctx, key_blob.data, es->iv.data);
	aes_gcm_128_updateA(&cctx,
		    (uint8_t *)&es->header,
		    sizeof(struct EncryptedSecretHeader));
	aes_gcm_128_crypt(&cctx, es->encrypted.data, pt.length);
	aes_gcm_128_updateC(&cctx, es->encrypted.data, pt.length);
	aes_gcm_128_digest(&cctx, &es->encrypted.data[pt.length]);

	rc = ndr_push_struct_blob(&enc,
				  ctx,
				  es,
				  (ndr_push_flags_fn_t)
					ndr_push_EncryptedSecret);
	if (!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_set_errstring(ldb,
				  "Unable to ndr push EncryptedSecret\n");
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return enc;

error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return data_blob_null;
}
/*
 * @brief Decrypt data encrypted using an aead algorithm.
 *
 * Decrypt the data in ed and insert it into ev. The data was encrypted
 * with the samba aes gcm implementation.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully decrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context that will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param ev   The value to be updated with the decrypted data.
 * @param ed   The data to decrypt.
 * @param data The context data for this module.
 *
 * @return ev is updated with the unencrypted data.
 */
static void samba_decrypt_aead(int *err,
			       TALLOC_CTX *ctx,
			       struct ldb_context *ldb,
			       struct EncryptedSecret *es,
			       struct PlaintextSecret *ps,
			       const struct es_data *data)
{
	struct aes_gcm_128_context cctx;
	DATA_BLOB pt = data_blob_null;
	DATA_BLOB key_blob = data_blob_null;
	uint8_t sig[AES_BLOCK_SIZE] = {0, };
	int rc;
	int cmp;
	TALLOC_CTX *frame = talloc_stackframe();

	/*
	 * Set the encryption key
	 */
	key_blob = get_key(data);
	if (key_blob.length != AES_BLOCK_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedSecrets key size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_BLOCK_SIZE,
				       key_blob.length);
		goto error_exit;
	}

	if (es->iv.length < AES_GCM_128_IV_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedSecrets iv size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_GCM_128_IV_SIZE,
				       es->iv.length);
		goto error_exit;
	}

	if (es->encrypted.length < AES_BLOCK_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedData size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_BLOCK_SIZE,
				       es->encrypted.length);
		goto error_exit;
	}

	pt.length = es->encrypted.length - AES_BLOCK_SIZE;
	pt.data   = talloc_zero_size(ctx, pt.length);
	if (pt.data == NULL) {
		ldb_set_errstring(ldb,
			          "Out of memory allocating space for "
				  "plain text\n");
		goto error_exit;
	}
	memcpy(pt.data, es->encrypted.data, pt.length);

	aes_gcm_128_init(&cctx, key_blob.data, es->iv.data);
	aes_gcm_128_updateA(&cctx,
		    (uint8_t *)&es->header,
		    sizeof(struct EncryptedSecretHeader));
	aes_gcm_128_updateC(&cctx, pt.data, pt.length);
	aes_gcm_128_crypt(&cctx, pt.data, pt.length);
	aes_gcm_128_digest(&cctx, sig);

	/*
	 * Check the authentication tag
	 */
	cmp = memcmp(&es->encrypted.data[pt.length], sig, AES_BLOCK_SIZE);
	if (cmp != 0) {
		ldb_set_errstring(ldb,
				  "Tag does not match, "
				  "data corrupted or altered\n");
		goto error_exit;
	}

	rc = ndr_pull_struct_blob(&pt,
				  ctx,
				  ps,
				  (ndr_pull_flags_fn_t)
					ndr_pull_PlaintextSecret);
	if(!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_asprintf_errstring(ldb,
				       "Error(%d)  unpacking decrypted data, "
				       "data possibly corrupted or altered\n",
				       rc);
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return;

error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return;
}
Exemple #3
0
/*
 This uses the test values from ...
*/
bool torture_local_crypto_aes_gcm_128(struct torture_context *torture)
{
	bool ret = true;
	uint32_t i;
	struct {
		DATA_BLOB K;
		DATA_BLOB IV;
		DATA_BLOB A;
		DATA_BLOB P;
		DATA_BLOB C;
		DATA_BLOB T;
	} testarray[5];

	TALLOC_CTX *tctx = talloc_new(torture);
	if (!tctx) { return false; };

	ZERO_STRUCT(testarray);

	testarray[0].K = strhex_to_data_blob(tctx,
				"00000000000000000000000000000000");
	testarray[0].IV = strhex_to_data_blob(tctx,
				"000000000000000000000000");
	testarray[0].A = data_blob_null;
	testarray[0].P = data_blob_null;
	testarray[0].C = data_blob_null;
	testarray[0].T = strhex_to_data_blob(tctx,
				"58e2fccefa7e3061367f1d57a4e7455a");

	testarray[1].K = strhex_to_data_blob(tctx,
				"00000000000000000000000000000000");
	testarray[1].IV = strhex_to_data_blob(tctx,
				"000000000000000000000000");
	testarray[1].A = data_blob_null;
	testarray[1].P = strhex_to_data_blob(tctx,
				"00000000000000000000000000000000");
	testarray[1].C = strhex_to_data_blob(tctx,
				"0388dace60b6a392f328c2b971b2fe78");
	testarray[1].T = strhex_to_data_blob(tctx,
				"ab6e47d42cec13bdf53a67b21257bddf");

	testarray[2].K = strhex_to_data_blob(tctx,
				"feffe9928665731c6d6a8f9467308308");
	testarray[2].IV = strhex_to_data_blob(tctx,
				"cafebabefacedbaddecaf888");
	testarray[2].A = data_blob_null;
	testarray[2].P = strhex_to_data_blob(tctx,
				"d9313225f88406e5a55909c5aff5269a"
				"86a7a9531534f7da2e4c303d8a318a72"
				"1c3c0c95956809532fcf0e2449a6b525"
				"b16aedf5aa0de657ba637b391aafd255");
	testarray[2].C = strhex_to_data_blob(tctx,
				"42831ec2217774244b7221b784d0d49c"
				"e3aa212f2c02a4e035c17e2329aca12e"
				"21d514b25466931c7d8f6a5aac84aa05"
				"1ba30b396a0aac973d58e091473f5985");
	testarray[2].T = strhex_to_data_blob(tctx,
				"4d5c2af327cd64a62cf35abd2ba6fab4");

	testarray[3].K = strhex_to_data_blob(tctx,
				"feffe9928665731c6d6a8f9467308308");
	testarray[3].IV = strhex_to_data_blob(tctx,
				"cafebabefacedbaddecaf888");
	testarray[3].A = strhex_to_data_blob(tctx,
				"feedfacedeadbeeffeedfacedeadbeef"
				"abaddad2");
	testarray[3].P = strhex_to_data_blob(tctx,
				"d9313225f88406e5a55909c5aff5269a"
				"86a7a9531534f7da2e4c303d8a318a72"
				"1c3c0c95956809532fcf0e2449a6b525"
				"b16aedf5aa0de657ba637b39");
	testarray[3].C = strhex_to_data_blob(tctx,
				"42831ec2217774244b7221b784d0d49c"
				"e3aa212f2c02a4e035c17e2329aca12e"
				"21d514b25466931c7d8f6a5aac84aa05"
				"1ba30b396a0aac973d58e091");
	testarray[3].T = strhex_to_data_blob(tctx,
				"5bc94fbc3221a5db94fae95ae7121a47");

	for (i=1; testarray[i].T.length != 0; i++) {
		struct aes_gcm_128_context ctx;
		uint8_t T[AES_BLOCK_SIZE];
		DATA_BLOB C;
		int e;

		C = data_blob_dup_talloc(tctx, testarray[i].P);

		aes_gcm_128_init(&ctx, testarray[i].K.data, testarray[i].IV.data);
		aes_gcm_128_updateA(&ctx,
				    testarray[i].A.data,
				    testarray[i].A.length);
		aes_gcm_128_crypt(&ctx, C.data, C.length);
		aes_gcm_128_updateC(&ctx, C.data, C.length);
		aes_gcm_128_digest(&ctx, T);

		e = memcmp(testarray[i].T.data, T, sizeof(T));
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("C1\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("C2\n");
			dump_data(0, C.data, C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}

		e = memcmp(testarray[i].C.data, C.data, C.length);
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("C1\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("C2\n");
			dump_data(0, C.data, C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}
	}

	for (i=1; testarray[i].T.length != 0; i++) {
		struct aes_gcm_128_context ctx;
		uint8_t T[AES_BLOCK_SIZE];
		DATA_BLOB C;
		int e;
		size_t j;

		C = data_blob_dup_talloc(tctx, testarray[i].P);

		aes_gcm_128_init(&ctx, testarray[i].K.data, testarray[i].IV.data);
		for (j=0; j < testarray[i].A.length; j++) {
			aes_gcm_128_updateA(&ctx, &testarray[i].A.data[j], 1);
		}
		for (j=0; j < C.length; j++) {
			aes_gcm_128_crypt(&ctx, &C.data[j], 1);
			aes_gcm_128_updateC(&ctx, &C.data[j], 1);
		}
		aes_gcm_128_digest(&ctx, T);

		e = memcmp(testarray[i].T.data, T, sizeof(T));
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("C1\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("C2\n");
			dump_data(0, C.data, C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}

		e = memcmp(testarray[i].C.data, C.data, C.length);
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("C1\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("C2\n");
			dump_data(0, C.data, C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}
	}

	for (i=1; testarray[i].T.length != 0; i++) {
		struct aes_gcm_128_context ctx;
		uint8_t T[AES_BLOCK_SIZE];
		DATA_BLOB P;
		int e;
		size_t j;

		P = data_blob_dup_talloc(tctx, testarray[i].C);

		aes_gcm_128_init(&ctx, testarray[i].K.data, testarray[i].IV.data);
		for (j=0; j < testarray[i].A.length; j++) {
			aes_gcm_128_updateA(&ctx, &testarray[i].A.data[j], 1);
		}
		for (j=0; j < P.length; j++) {
			aes_gcm_128_updateC(&ctx, &P.data[j], 1);
			aes_gcm_128_crypt(&ctx, &P.data[j], 1);
		}
		aes_gcm_128_digest(&ctx, T);

		e = memcmp(testarray[i].T.data, T, sizeof(T));
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P1\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("P2\n");
			dump_data(0, P.data, P.length);
			printf("C\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}

		e = memcmp(testarray[i].P.data, P.data, P.length);
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P1\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("P2\n");
			dump_data(0, P.data, P.length);
			printf("C\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}
	}

	for (i=1; testarray[i].T.length != 0; i++) {
		struct aes_gcm_128_context ctx;
		uint8_t T[AES_BLOCK_SIZE];
		DATA_BLOB P;
		int e;

		P = data_blob_dup_talloc(tctx, testarray[i].C);

		aes_gcm_128_init(&ctx, testarray[i].K.data, testarray[i].IV.data);
		aes_gcm_128_updateA(&ctx, testarray[i].A.data, testarray[i].A.length);
		aes_gcm_128_updateC(&ctx, P.data, P.length);
		aes_gcm_128_crypt(&ctx, P.data, P.length);
		aes_gcm_128_digest(&ctx, T);

		e = memcmp(testarray[i].T.data, T, sizeof(T));
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P1\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("P2\n");
			dump_data(0, P.data, P.length);
			printf("C\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}

		e = memcmp(testarray[i].P.data, P.data, P.length);
		if (e != 0) {
			printf("%s: aes_gcm_128 test[%u]: failed\n", __location__, i);
			printf("K\n");
			dump_data(0, testarray[i].K.data, testarray[i].K.length);
			printf("IV\n");
			dump_data(0, testarray[i].IV.data, testarray[i].IV.length);
			printf("A\n");
			dump_data(0, testarray[i].A.data, testarray[i].A.length);
			printf("P1\n");
			dump_data(0, testarray[i].P.data, testarray[i].P.length);
			printf("P2\n");
			dump_data(0, P.data, P.length);
			printf("C\n");
			dump_data(0, testarray[i].C.data, testarray[i].C.length);
			printf("T1\n");
			dump_data(0, testarray[i].T.data, testarray[i].T.length);
			printf("T2\n");
			dump_data(0, T, sizeof(T));
			ret = false;
			goto fail;
		}
	}

 fail:
	talloc_free(tctx);
	return ret;
}