--- /dev/null
+/* The Samba Project Contributors - License in the COPYING file */
+
+#include "samba_crypto.h"
+
+#if CRYPTO_USE_OPENSSL
+#include <openssl/evp.h>
+
+struct samba_crypto_cipher_ctx {
+ EVP_CIPHER_CTX ctx;
+ enum samba_crypto_operation op;
+ bool cipher_is_aead;
+ bool cipher_is_ccm;
+};
+
+#elif CRYPTO_USE_GNUTLS
+struct samba_crypto_cipher_ctx {
+ gnutls_cipher_hd_t ctx;
+ enum samba_crypto_operation op;
+ bool cipher_is_aead;
+ bool cipher_is_ccm;
+};
+
+#else
+# error no crypto library available
+#endif
+
+int samba_crypto_cipher_ctx_size(void)
+{
+ return sizeof(struct samba_crypto_cipher_ctx);
+}
+
+#if CRYPTO_USE_OPENSSL
+
+/* older vesions of openssl used the same values but only had
+ * cipher-specific names. Newer versions define 'AEAD' generic
+ * names. Define them if not available. Thy have the same value
+ * as the cipher-secific ones. */
+#ifndef EVP_CTRL_AEAD_SET_IVLEN
+#define EVP_CTRL_AEAD_SET_IVLEN EVP_CTRL_GCM_SET_IVLEN
+#endif
+#ifndef EVP_CTRL_AEAD_SET_TAG
+#define EVP_CTRL_AEAD_SET_TAG EVP_CTRL_GCM_SET_TAG
+#endif
+#ifndef EVP_CTRL_AEAD_GET_TAG
+#define EVP_CTRL_AEAD_GET_TAG EVP_CTRL_GCM_GET_TAG
+#endif
+
+#define OS_EVP_OK 1
+#define OS_EVP_ERR 0
+#define OS_EVP_IS_ERR(val) ((val) == OS_EVP_ERR)
+
+struct samba_crypto_cipher {
+ const EVP_CIPHER *(*cipher)(void);
+} samba_crypto_ciphers[] = {
+ { NULL },
+ { EVP_aes_128_ccm },
+ { EVP_aes_128_gcm },
+};
+
+static bool samba_crypto_cipher_is_valid(enum samba_crypto_cipher_id id)
+{
+ if (id > SAMBA_CRYPTO_CIPHER_NONE &&
+ id < SAMBA_CRYPTO_CIPHER_END) {
+ return true;
+ }
+ return false;
+}
+
+static bool samba_crypto_cipher_is_aead(enum samba_crypto_cipher_id id)
+{
+ switch (id) {
+ case SAMBA_CRYPTO_CIPHER_AES_128_CCM:
+ return true;
+ case SAMBA_CRYPTO_CIPHER_AES_128_GCM:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool samba_crypto_cipher_is_ccm(enum samba_crypto_cipher_id id)
+{
+ return (id == SAMBA_CRYPTO_CIPHER_AES_128_CCM);
+}
+
+NTSTATUS samba_crypto_cipher_init(struct samba_crypto_cipher_ctx *ctx,
+ enum samba_crypto_cipher_id cipher,
+ DATA_BLOB *key_blob,
+ DATA_BLOB *iv_blob,
+ DATA_BLOB *authdata,
+ DATA_BLOB *authtag,
+ int ccm_inputbuffer_len,
+ enum samba_crypto_operation op)
+{
+ unsigned char *key = NULL;
+ unsigned char *iv = NULL;
+ NTSTATUS status;
+ int ret;
+ int enc;
+
+ if (!samba_crypto_cipher_is_valid(cipher)) {
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+
+ ZERO_STRUCTP(ctx);
+
+ switch (op) {
+ case SAMBA_CRYPTO_ENCRYPT:
+ enc = 1;
+ break;
+ case SAMBA_CRYPTO_DECRYPT:
+ enc = 0;
+ break;
+ default:
+ return NT_STATUS_INVALID_PARAMETER;
+ }
+ ctx->op = op;
+
+ if (samba_crypto_cipher_is_aead(cipher)) {
+ ctx->cipher_is_aead = true;
+ }
+
+ if (samba_crypto_cipher_is_ccm(cipher)) {
+ ctx->cipher_is_ccm = true;
+ }
+
+ EVP_CIPHER_CTX_init(&ctx->ctx);
+ ret = EVP_CipherInit_ex(&ctx->ctx,
+ samba_crypto_ciphers[cipher].cipher(),
+ NULL, NULL, NULL, enc);
+ if (OS_EVP_IS_ERR(ret)) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (EVP_CIPHER_CTX_key_length(&ctx->ctx) != key_blob->length) {
+ status = NT_STATUS_INVALID_BUFFER_SIZE;
+ goto done;
+ }
+ key = (unsigned char *)key_blob->data;
+
+ if (iv_blob) {
+ iv = (unsigned char *)iv_blob->data;
+
+ if (ctx->cipher_is_aead) {
+ ret = EVP_CIPHER_CTX_ctrl(&ctx->ctx,
+ EVP_CTRL_AEAD_SET_IVLEN,
+ iv_blob->length, NULL);
+ if (OS_EVP_IS_ERR(ret)) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+ }
+ }
+
+ if (ctx->cipher_is_aead && authtag) {
+ if (ctx->op == SAMBA_CRYPTO_ENCRYPT &&
+ ctx->cipher_is_ccm) {
+ ret = EVP_CIPHER_CTX_ctrl(&ctx->ctx,
+ EVP_CTRL_AEAD_SET_TAG,
+ authtag->length, NULL);
+ } else if (ctx->op == SAMBA_CRYPTO_DECRYPT) {
+ ret = EVP_CIPHER_CTX_ctrl(&ctx->ctx,
+ EVP_CTRL_AEAD_SET_TAG,
+ authtag->length,
+ (void *)authtag->data);
+ }
+ if (OS_EVP_IS_ERR(ret)) {
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto done;
+ }
+ }
+
+ ret = EVP_CipherInit_ex(&ctx->ctx, NULL, NULL, key, iv, enc);
+ if (OS_EVP_IS_ERR(ret)) {
+ status = NT_STATUS_UNSUCCESSFUL;
+ goto done;
+ }
+
+ if (ctx->cipher_is_aead && authdata && authdata->length > 0) {
+ unsigned char *abuf = (unsigned char *)authdata->data;
+ int alen = authdata->length;
+ int tmplen;
+
+ if (ctx->cipher_is_ccm) {
+ ret = EVP_CipherUpdate(&ctx->ctx, NULL,
+ &tmplen, NULL,
+ ccm_inputbuffer_len);
+ if (OS_EVP_IS_ERR(ret)) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+ }
+
+ ret = EVP_CipherUpdate(&ctx->ctx,
+ NULL, &tmplen, abuf, alen);
+ if (OS_EVP_IS_ERR(ret)) {
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto done;
+ }
+ }
+
+ status = NT_STATUS_OK;
+
+done:
+ if (!NT_STATUS_IS_OK(status)) {
+ samba_crypto_cipher_ctx_destroy(ctx);
+ }
+ return status;
+}
+
+int samba_crypto_cipher_block_size(struct samba_crypto_cipher_ctx *ctx)
+{
+ return EVP_CIPHER_block_size(EVP_CIPHER_CTX_cipher(&ctx->ctx));
+}
+
+NTSTATUS samba_crypto_cipher_crypt(struct samba_crypto_cipher_ctx *scc_ctx,
+ DATA_BLOB *plaintext,
+ DATA_BLOB *ciphertext,
+ DATA_BLOB *authtag,
+ bool finalize)
+{
+ EVP_CIPHER_CTX *ctx = &scc_ctx->ctx;
+ unsigned char *outbuf;
+ unsigned char *inbuf;
+ int outlen;
+ int inlen;
+ int totlen;
+ int ret;
+
+ switch (scc_ctx->op) {
+ case SAMBA_CRYPTO_ENCRYPT:
+ outbuf = (unsigned char *)ciphertext->data;
+ outlen = ciphertext->length;
+ inbuf = (unsigned char *)plaintext->data;
+ inlen = plaintext->length;
+ break;
+ case SAMBA_CRYPTO_DECRYPT:
+ outbuf = (unsigned char *)plaintext->data;
+ outlen = plaintext->length;
+ inbuf = (unsigned char *)ciphertext->data;
+ inlen = ciphertext->length;
+
+ break;
+ default:
+ return NT_STATUS_INTERNAL_ERROR;
+ }
+
+ ret = EVP_CipherUpdate(ctx, outbuf, &outlen, inbuf, inlen);
+ totlen = outlen;
+ if (finalize && !OS_EVP_IS_ERR(ret) &&
+ !(scc_ctx->cipher_is_ccm && scc_ctx->op == SAMBA_CRYPTO_DECRYPT)) {
+ outbuf += totlen;
+ outlen = ciphertext->length - totlen;
+ ret = EVP_CipherFinal_ex(ctx, outbuf, &outlen);
+ totlen += outlen;
+ }
+ if (scc_ctx->op == SAMBA_CRYPTO_ENCRYPT) {
+ if (OS_EVP_IS_ERR(ret)) {
+ return NT_STATUS_ENCRYPTION_FAILED;
+ } else {
+ ciphertext->length = totlen;
+ }
+ if (finalize && scc_ctx->cipher_is_aead) {
+ int taglen = authtag->length;
+ ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_AEAD_GET_TAG,
+ taglen,
+ (void *)authtag->data);
+ if (OS_EVP_IS_ERR(ret)) {
+ return NT_STATUS_ENCRYPTION_FAILED;
+ }
+ }
+ } else {
+ if (OS_EVP_IS_ERR(ret)) {
+ return NT_STATUS_DECRYPTION_FAILED;
+ } else {
+ plaintext->length = totlen;
+ }
+ }
+
+ return NT_STATUS_OK;
+}
+
+void samba_crypto_cipher_ctx_destroy(struct samba_crypto_cipher_ctx *ctx)
+{
+ (void)EVP_CIPHER_CTX_cleanup(&ctx->ctx);
+ ctx->op = SAMBA_CRYPTO_UNINITIALIZED;
+}
+#elif CRYPTO_USE_GNUTLS
+NTSTATUS samba_crypto_cipher_init(struct samba_cipher_ctx *ctx,
+ struct samba_crypto_cipher *cipher,
+ DATA_BLOB key,
+ DATA_BLOB iv,
+ enum samba_crypto_operation op);
+
+NTSTATUS samba_crypto_cipher_crypt(struct samba_cipher_ctx *ctx,
+ DATA_BLOB *plaintext,
+ DATA_BLOB *ciphertext,
+ DATA_BLOB *authtag);
+
+void samba_crypto_cipher_ctx_destroy(struct samba_crypto_cipher_ctx *ctx);
+#else
+# error no crypto library available
+#endif
--- /dev/null
+/*
+ AES-GCM-128 tests
+
+ Copyright (C) Stefan Metzmacher 2014
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+#include "replace.h"
+#include "../lib/util/samba_util.h"
+#include "samba_crypto.h"
+
+struct torture_context;
+bool torture_local_samba_crypto(struct torture_context *torture);
+
+enum tlsc_passfail {
+ TLSC_PASS = 0,
+ TLSC_FAIL,
+ TLSC_FAIL_ADATA
+};
+
+struct tlsc_testvector {
+ enum samba_crypto_cipher_id cipher;
+ DATA_BLOB K;
+ DATA_BLOB IV;
+ DATA_BLOB A;
+ DATA_BLOB P;
+ DATA_BLOB C;
+ DATA_BLOB T;
+};
+
+static void tlsc_print_errors(struct tlsc_testvector *tv,
+ DATA_BLOB *P, DATA_BLOB *C, DATA_BLOB *T)
+{
+ printf("Cipher: %d\n", tv->cipher);
+ printf("K\n");
+ dump_data(0, tv->K.data, tv->K.length);
+ printf("IV\n");
+ dump_data(0, tv->IV.data, tv->IV.length);
+ printf("A\n");
+ dump_data(0, tv->A.data, tv->A.length);
+ printf("P\n");
+ dump_data(0, tv->P.data, tv->P.length);
+ if (P) {
+ printf("PV\n");
+ dump_data(0, P->data, P->length);
+ }
+ printf("C\n");
+ dump_data(0, tv->C.data, tv->C.length);
+ if (C) {
+ printf("CV\n");
+ dump_data(0, C->data, C->length);
+ }
+ printf("T\n");
+ dump_data(0, tv->T.data, tv->T.length);
+ if (T) {
+ printf("TV\n");
+ dump_data(0, T->data, T->length);
+ }
+}
+
+/*
+ This uses the test values from ...
+*/
+bool torture_local_samba_crypto(struct torture_context *torture)
+{
+ bool ret = true;
+ uint32_t i;
+ TALLOC_CTX *tctx = talloc_new(torture);
+ struct tlsc_testvector testarray[] = {
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+ .K = strhex_to_data_blob(tctx,
+ "00000000000000000000000000000000"),
+ .IV = strhex_to_data_blob(tctx,
+ "000000000000000000000000"),
+ .A = data_blob_null,
+ .P = strhex_to_data_blob(tctx,
+ "00000000000000000000000000000000"),
+ .C = strhex_to_data_blob(tctx,
+ "0388dace60b6a392f328c2b971b2fe78"),
+ .T = strhex_to_data_blob(tctx,
+ "ab6e47d42cec13bdf53a67b21257bddf")
+ },
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+ .K = strhex_to_data_blob(tctx,
+ "feffe9928665731c6d6a8f9467308308"),
+ .IV = strhex_to_data_blob(tctx,
+ "cafebabefacedbaddecaf888"),
+ .A = data_blob_null,
+ .P = strhex_to_data_blob(tctx,
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b391aafd255"),
+ .C = strhex_to_data_blob(tctx,
+ "42831ec2217774244b7221b784d0d49c"
+ "e3aa212f2c02a4e035c17e2329aca12e"
+ "21d514b25466931c7d8f6a5aac84aa05"
+ "1ba30b396a0aac973d58e091473f5985"),
+ .T = strhex_to_data_blob(tctx,
+ "4d5c2af327cd64a62cf35abd2ba6fab4")
+ },
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_GCM,
+ .K = strhex_to_data_blob(tctx,
+ "feffe9928665731c6d6a8f9467308308"),
+ .IV = strhex_to_data_blob(tctx,
+ "cafebabefacedbaddecaf888"),
+ .A = strhex_to_data_blob(tctx,
+ "feedfacedeadbeeffeedfacedeadbeef"
+ "abaddad2"),
+ .P = strhex_to_data_blob(tctx,
+ "d9313225f88406e5a55909c5aff5269a"
+ "86a7a9531534f7da2e4c303d8a318a72"
+ "1c3c0c95956809532fcf0e2449a6b525"
+ "b16aedf5aa0de657ba637b39"),
+ .C = strhex_to_data_blob(tctx,
+ "42831ec2217774244b7221b784d0d49c"
+ "e3aa212f2c02a4e035c17e2329aca12e"
+ "21d514b25466931c7d8f6a5aac84aa05"
+ "1ba30b396a0aac973d58e091"),
+ .T = strhex_to_data_blob(tctx,
+ "5bc94fbc3221a5db94fae95ae7121a47"),
+ },
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+ .K = strhex_to_data_blob(tctx,
+ "197afb02ffbd8f699dacae87094d5243"),
+ .IV = strhex_to_data_blob(tctx,
+ "5a8aa485c316e9"),
+ .A = data_blob_null,
+ .P = strhex_to_data_blob(tctx,
+ "3796cf51b8726652a4204733b8fbb047"
+ "cf00fb91a9837e22"),
+ .C = strhex_to_data_blob(tctx,
+ "24ab9eeb0e5508cae80074f1070ee188"
+ "a637171860881f1f"),
+ .T = strhex_to_data_blob(tctx,
+ "2d9a3fbc210595b7b8b1b41523111a8e")
+ },
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+ .K = strhex_to_data_blob(tctx,
+ "90929a4b0ac65b350ad1591611fe4829"),
+ .IV = strhex_to_data_blob(tctx,
+ "5a8aa485c316e9403aff859fbb"),
+ .A = data_blob_null,
+ .P = strhex_to_data_blob(tctx,
+ "a16a2e741f1cd9717285b6d882c1fc53"
+ "655e9773761ad697"),
+ .C = strhex_to_data_blob(tctx,
+ "4bfe4e35784f0a65b545477e5e2f4bae"
+ "0e1e6fa717eaf2cb"),
+ .T = strhex_to_data_blob(tctx,
+ "6a9a970b9beb2ac1bd4fd62168f8378a")
+ },
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+ .K = strhex_to_data_blob(tctx,
+ "f9fdca4ac64fe7f014de0f43039c7571"),
+ .IV = strhex_to_data_blob(tctx,
+ "5a8aa485c316e9"),
+ .A = strhex_to_data_blob(tctx,
+ "3796cf51b8726652a4204733b8fbb047"
+ "cf00fb91a9837e22ec22b1a268f88e2c"),
+ .P = strhex_to_data_blob(tctx,
+ "a265480ca88d5f536db0dc6abc40faf0"
+ "d05be7a966977768"),
+ .C = strhex_to_data_blob(tctx,
+ "6be31860ca271ef448de8f8d8b39346d"
+ "af4b81d7e92d65b3"),
+ .T = strhex_to_data_blob(tctx,
+ "38f125fa")
+ },
+ { .cipher = SAMBA_CRYPTO_CIPHER_AES_128_CCM,
+ .K = strhex_to_data_blob(tctx,
+ "26511fb51fcfa75cb4b44da75a6e5a0e"),
+ .IV = strhex_to_data_blob(tctx,
+ "5a8aa485c316e9403aff859fbb"),
+ .A = strhex_to_data_blob(tctx,
+ "a16a2e741f1cd9717285b6d882c1fc53"
+ "655e9773761ad697a7ee6410184c7982"),
+ .P = strhex_to_data_blob(tctx,
+ "8739b4bea1a099fe547499cbc6d1b13d"
+ "849b8084c9b6acc5"),
+ .C = strhex_to_data_blob(tctx,
+ "50038b5fdd364ee747b70d00bd36840e"
+ "ce4ea19998123375"),
+ .T = strhex_to_data_blob(tctx,
+ "c0a458bfcafa3b2609afe0f825cbf503")
+ },
+ { 0 }
+ };
+
+ if (!tctx) { return false; };
+
+ for (i = 0; testarray[i].T.length != 0; i++) {
+ SAMBA_CRYPTO_CIPHER_CTX(ctx);
+ DATA_BLOB T = { 0 };
+ DATA_BLOB C = { 0 };
+ NTSTATUS status;
+ int err;
+
+ status = samba_crypto_cipher_init(ctx,
+ testarray[i].cipher,
+ &testarray[i].K,
+ &testarray[i].IV,
+ &testarray[i].A,
+ &testarray[i].T,
+ testarray[i].P.length,
+ SAMBA_CRYPTO_ENCRYPT);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed [%x]\n",
+ __location__, i, NT_STATUS_V(status));
+ tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+
+ C = data_blob_talloc_zero(tctx, testarray[i].P.length);
+ T = data_blob_talloc_zero(tctx, testarray[i].T.length);
+
+ status = samba_crypto_cipher_crypt(ctx, &testarray[i].P,
+ &C, &T, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+
+ err = memcmp(testarray[i].T.data, T.data, T.length);
+ if (err != 0) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, &C, &T);
+ ret = false;
+ goto fail;
+ }
+
+ err = memcmp(testarray[i].C.data, C.data, C.length);
+ if (err != 0) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, &C, &T);
+ ret = false;
+ goto fail;
+ }
+ }
+
+ for (i = 0; testarray[i].T.length != 0; i++) {
+ SAMBA_CRYPTO_CIPHER_CTX(ctx);
+ DATA_BLOB P = { 0 };
+ NTSTATUS status;
+ int err;
+
+ status = samba_crypto_cipher_init(ctx,
+ testarray[i].cipher,
+ &testarray[i].K,
+ &testarray[i].IV,
+ &testarray[i].A,
+ &testarray[i].T,
+ testarray[i].C.length,
+ SAMBA_CRYPTO_DECRYPT);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+
+ P = data_blob_talloc_zero(tctx, testarray[i].C.length);
+
+ status = samba_crypto_cipher_crypt(ctx,
+ &P, &testarray[i].C,
+ NULL, true);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+
+ err = memcmp(testarray[i].P.data, P.data, P.length);
+ if (err != 0) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], &P, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+ }
+
+ for (i = 0; testarray[i].T.length != 0; i++) {
+ SAMBA_CRYPTO_CIPHER_CTX(ctx);
+ DATA_BLOB T = { 0 };
+ DATA_BLOB C = { 0 };
+ DATA_BLOB P;
+ DATA_BLOB CJ;
+ NTSTATUS status;
+ size_t j;
+ int err;
+
+ if (testarray[i].cipher == SAMBA_CRYPTO_CIPHER_AES_128_CCM) {
+ /* samba_crypto's CCM can't do chunked updates */
+ continue;
+ }
+
+ status = samba_crypto_cipher_init(ctx,
+ testarray[i].cipher,
+ &testarray[i].K,
+ &testarray[i].IV,
+ &testarray[i].A,
+ &testarray[i].T,
+ testarray[i].P.length,
+ SAMBA_CRYPTO_ENCRYPT);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+
+ C = data_blob_talloc_zero(tctx, testarray[i].P.length);
+ T = data_blob_talloc_zero(tctx, testarray[i].T.length);
+
+ CJ = C;
+ P.length = 1;
+ for (j = 0; j < testarray[i].P.length; j++) {
+ bool finalize = (j == (testarray[i].P.length - 1));
+ P.data = &testarray[i].P.data[j];
+ status = samba_crypto_cipher_crypt(ctx, &P, &CJ, &T,
+ finalize);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, &C, &T);
+ ret = false;
+ goto fail;
+ }
+ CJ.data += CJ.length;
+ CJ.length = C.length - (CJ.data - C.data);
+ }
+ C.length = CJ.data - C.data;
+
+ err = memcmp(testarray[i].T.data, T.data, T.length);
+ if (err != 0) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, &C, &T);
+ ret = false;
+ goto fail;
+ }
+
+ err = memcmp(testarray[i].C.data, C.data, C.length);
+ if (err != 0) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, &C, &T);
+ ret = false;
+ goto fail;
+ }
+ }
+
+ for (i = 0; testarray[i].T.length != 0; i++) {
+ SAMBA_CRYPTO_CIPHER_CTX(ctx);
+ DATA_BLOB P = { 0 };
+ DATA_BLOB C;
+ DATA_BLOB PJ;
+ NTSTATUS status;
+ size_t j;
+ int err;
+
+ if (testarray[i].cipher == SAMBA_CRYPTO_CIPHER_AES_128_CCM) {
+ /* samba_crypto's CCM can't do chunked updates */
+ continue;
+ }
+
+ status = samba_crypto_cipher_init(ctx,
+ testarray[i].cipher,
+ &testarray[i].K,
+ &testarray[i].IV,
+ &testarray[i].A,
+ &testarray[i].T,
+ testarray[i].C.length,
+ SAMBA_CRYPTO_DECRYPT);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], NULL, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+
+ P = data_blob_talloc_zero(tctx, testarray[i].C.length);
+
+ PJ = P;
+ C.length = 1;
+ for (j = 0; j < testarray[i].C.length; j++) {
+ bool finalize = (j == (testarray[i].C.length - 1));
+ C.data = &testarray[i].C.data[j];
+ status = samba_crypto_cipher_crypt(ctx, &PJ, &C, NULL,
+ finalize);
+ if (!NT_STATUS_IS_OK(status)) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], &P,
+ NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+ PJ.data += PJ.length;
+ PJ.length = P.length - (PJ.data - P.data);
+ }
+ P.length = PJ.data - P.data;
+
+ err = memcmp(testarray[i].P.data, P.data, P.length);
+ if (err != 0) {
+ printf("%s: aes_gcm_128 test[%u]: failed\n",
+ __location__, i);
+ tlsc_print_errors(&testarray[i], &P, NULL, NULL);
+ ret = false;
+ goto fail;
+ }
+ }
+
+ fail:
+ talloc_free(tctx);
+ return ret;
+}