Continued
diff --git a/src/Cose.c b/src/Cose.c
index 9b671e1..369b7e1 100644
--- a/src/Cose.c
+++ b/src/Cose.c
@@ -27,13 +27,16 @@
 	error_setup:
 		_COSE_Release( pobj);
 		if (perror != NULL) perror->err = COSE_ERR_OUT_OF_MEMORY;
-		return false;
+return false;
 	}
 
 	pobj->m_unprotectMap = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &errState);
 	if (pobj->m_unprotectMap == NULL) goto error_setup;
 	pobj->m_ownUnprotectedMap = true;
 
+	pobj->m_dontSendMap = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &errState);
+	if (pobj->m_dontSendMap == NULL) goto error_setup;
+
 	pobj->m_cbor = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &errState);
 	if (pobj->m_cbor == NULL) goto error_setup;
 	pobj->m_ownMsg = true;
@@ -58,14 +61,14 @@
 			_COSE_Release(pobj);
 			return false;
 		}
-		pobj->m_protectedMap = (cn_cbor *) cn_cbor_decode((const byte *) pmap->v.str, pmap->length, context, &errState);
+		pobj->m_protectedMap = (cn_cbor *)cn_cbor_decode((const byte *)pmap->v.str, pmap->length, context, &errState);
 		if (pobj->m_protectedMap == NULL) {
 			if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER; // M00BUG - get error state from errState
 			goto setup_error;
 		}
 	}
 
-	pobj->m_unprotectMap = (cn_cbor *) cn_cbor_mapget_int(pcbor, COSE_Header_Unprotected);
+	pobj->m_unprotectMap = (cn_cbor *)cn_cbor_mapget_int(pcbor, COSE_Header_Unprotected);
 	pobj->m_ownUnprotectedMap = false;
 
 	pobj->m_cbor = pcbor;
@@ -80,9 +83,59 @@
 
 	if (pobj->m_protectedMap != NULL) CN_CBOR_FREE(pobj->m_protectedMap, context);
 	if (pobj->m_ownUnprotectedMap && (pobj->m_unprotectMap != NULL)) CN_CBOR_FREE(pobj->m_unprotectMap, context);
+	if (pobj->m_dontSendMap != NULL) CN_CBOR_FREE(pobj->m_dontSendMap, context);
 	if (pobj->m_ownMsg && (pobj->m_cbor != NULL)) CN_CBOR_FREE(pobj->m_cbor, context);
 }
 
+
+HCOSE COSE_Decode(const byte * rgbData, int cbData, int * ptype, CBOR_CONTEXT_COMMA cose_errback * errp)
+{
+	cn_cbor * cbor;
+	const cn_cbor * pType = NULL;
+	HCOSE h;
+
+	if ((rgbData == NULL) || (ptype == NULL)) {
+		if (errp != NULL) errp->err = COSE_ERR_INVALID_PARAMETER;
+		return NULL;
+	}
+
+	cbor = (cn_cbor *)cn_cbor_decode(rgbData, cbData, CBOR_CONTEXT_PARAM_COMMA NULL);
+	if (cbor == NULL) {
+		if (errp != NULL) errp->err = COSE_ERR_CBOR;
+		return NULL;
+	}
+
+	if (cbor->type != CN_CBOR_MAP) {
+	error:
+		COSE_FREE(cbor, context);
+		if (errp != NULL) errp->err = COSE_ERR_INVALID_PARAMETER;
+		return NULL;
+	}
+
+	pType = cn_cbor_mapget_int(cbor, COSE_Header_Type);
+	if ((pType == NULL) || (pType->type != CN_CBOR_UINT)) goto error;
+
+	switch (pType->v.sint) {
+	case 1:
+		h = (HCOSE)_COSE_Encrypt_Init_From_Object(cbor, NULL, CBOR_CONTEXT_PARAM_COMMA errp);
+		if (h == NULL) {
+			COSE_FREE(cbor, context);
+			return NULL;
+		}
+		return h;
+
+	case 2:
+		h = (HCOSE)_COSE_Sign_Init_From_Object(cbor, NULL, CBOR_CONTEXT_PARAM_COMMA errp);
+		if (h == NULL) {
+			COSE_FREE(cbor, context);
+			return NULL;
+		}
+		return h;
+	}
+
+	goto error;
+}
+
 cn_cbor * COSE_get_cbor(HCOSE h)
 {
 	COSE * msg = (COSE *)h;
@@ -104,8 +157,12 @@
 
 	if ((pcose->m_unprotectMap != NULL) && ((flags & COSE_UNPROTECT_ONLY) != 0)) {
 		p = cn_cbor_mapget_int(pcose->m_unprotectMap, key);
+		if (p != NULL) return p;
 	}
 
+	if ((pcose->m_dontSendMap != NULL) && ((flags & COSE_DONT_SEND) != 0)) {
+		p = cn_cbor_mapget_int(pcose->m_dontSendMap, key);
+	}
 	return p;
 }
 
@@ -124,29 +181,50 @@
 		p = cn_cbor_mapget_string(pcose->m_unprotectMap, key);
 	}
 
+	if ((pcose->m_dontSendMap != NULL) && ((flags & COSE_DONT_SEND) != 0)) {
+		p = cn_cbor_mapget_string(pcose->m_dontSendMap, key);
+	}
+
 	return p;
 }
 
-bool _COSE_map_put(COSE * pCose, int key, cn_cbor * value, int flags, cose_errback * perror)
+bool _COSE_map_put(COSE * pCose, int key, cn_cbor * value, int flags, cose_errback * perr)
 {
 	cn_cbor_context * context = &pCose->m_allocContext;
 	cn_cbor_errback error;
 	bool f;
 
 	if ((flags & COSE_BOTH) == COSE_BOTH) {
-		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		if (perr != NULL) perr->err = COSE_ERR_INVALID_PARAMETER;
+	errorReturn:
 		return false;
 	}
 
-	if (perror != NULL) perror->err = COSE_ERR_NONE;
-	if (flags & COSE_PROTECT_ONLY) {
+	if (perr != NULL) perr->err = COSE_ERR_NONE;
+
+	switch (flags) {
+	case COSE_PROTECT_ONLY:
 		f = cn_cbor_mapput_int(pCose->m_protectedMap, key, value, CBOR_CONTEXT_PARAM_COMMA &error);
-	}
-	else {
+		break;
+
+	case COSE_UNPROTECT_ONLY:
 		f = cn_cbor_mapput_int(pCose->m_unprotectMap, key, value, CBOR_CONTEXT_PARAM_COMMA &error);
+		break;
+
+	case COSE_DONT_SEND:
+		if (pCose->m_dontSendMap == NULL) {
+			pCose->m_dontSendMap = cn_cbor_map_create(CBOR_CONTEXT_PARAM_COMMA &error);
+			CHECK_CONDITION(pCose->m_dontSendMap != NULL, COSE_ERR_OUT_OF_MEMORY);
+		}
+		f = cn_cbor_mapput_int(pCose->m_dontSendMap, key, value, CBOR_CONTEXT_PARAM_COMMA &error);
+		break;
+
+	default:
+		CHECK_CONDITION(false, COSE_ERR_INVALID_PARAMETER);
+		break;
 	}
-	if (!f && perror != NULL) {
-		perror->err = error.err; // M00BUG
-	}
+
+	CHECK_CONDITION(f, error.err);
+
 	return f;
 }
diff --git a/src/MacMessage.c b/src/MacMessage.c
new file mode 100644
index 0000000..31c6bd3
--- /dev/null
+++ b/src/MacMessage.c
@@ -0,0 +1,381 @@
+#include <stdlib.h>
+#include <memory.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "cose.h"
+#include "cose_int.h"
+#include "configure.h"
+#include "crypto.h"
+
+byte RgbDontUse2[8 * 1024];   //  Remove this array when we can compute the size of a cbor serialization without this hack.
+
+
+bool IsValidMacHandle(HCOSE_MAC h)
+{
+	COSE_MacMessage * p = (COSE_MacMessage *)h;
+	if (p == NULL) return false;
+	return true;
+}
+
+
+HCOSE_MAC COSE_Mac_Init(CBOR_CONTEXT_COMMA cose_errback * perror)
+{
+	COSE_MacMessage * pobj = (COSE_MacMessage *)COSE_CALLOC(1, sizeof(COSE_MacMessage), context);
+	if (pobj == NULL) {
+		if (perror != NULL) perror->err = COSE_ERR_OUT_OF_MEMORY;
+		return NULL;
+	}
+
+	if (!_COSE_Init(&pobj->m_message, CBOR_CONTEXT_PARAM_COMMA perror)) {
+	error_setup:
+		COSE_Mac_Free((HCOSE_MAC)pobj);
+		return NULL;
+	}
+
+	if (!cn_cbor_mapput_int(pobj->m_message.m_cbor, COSE_Header_Type, cn_cbor_int_create(2, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) {
+		if (perror != NULL) perror->err = COSE_ERR_OUT_OF_MEMORY;
+		goto error_setup;
+	}
+
+	return (HCOSE_MAC)pobj;
+}
+
+HCOSE_MAC _COSE_Mac_Init_From_Object(cn_cbor * cbor, COSE_MacMessage * pIn, CBOR_CONTEXT_COMMA cose_errback * perr)
+{
+	COSE_MacMessage * pobj = pIn;
+	cn_cbor * pRecipients = NULL;
+	// cn_cbor * tmp;
+	cose_errback error = { COSE_ERR_NONE };
+	if (perr == NULL) perr = &error;
+
+	if (pobj == NULL) pobj = (COSE_MacMessage *)COSE_CALLOC(1, sizeof(COSE_MacMessage), context);
+	if (pobj == NULL) {
+		perr->err = COSE_ERR_OUT_OF_MEMORY;
+	errorReturn:
+		if ((pIn == NULL) && (pobj != NULL)) COSE_FREE(pobj, context);
+		return NULL;
+	}
+
+	if (!_COSE_Init_From_Object(&pobj->m_message, cbor, CBOR_CONTEXT_PARAM_COMMA perr)) {
+		goto errorReturn;
+	}
+
+	pRecipients = (cn_cbor *)cn_cbor_mapget_int(cbor, COSE_Header_Recipients);
+	if (pRecipients != NULL) {
+		CHECK_CONDITION(pRecipients->type == CN_CBOR_ARRAY, COSE_ERR_INVALID_PARAMETER);
+
+		pRecipients = pRecipients->first_child;
+		while (pRecipients != NULL) {
+			COSE_RecipientInfo * pInfo = _COSE_Recipient_Init_From_Object(pRecipients, CBOR_CONTEXT_PARAM_COMMA perr);
+			CHECK_CONDITION(pInfo != NULL, COSE_ERR_OUT_OF_MEMORY);
+
+			pInfo->m_recipientNext = pobj->m_recipientFirst;
+			pobj->m_recipientFirst = pInfo;
+			pRecipients = pRecipients->next;
+		}
+	}
+
+	return(HCOSE_MAC)pobj;
+}
+
+bool COSE_Mac_Free(HCOSE_MAC h)
+{
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context context;
+#endif
+
+	if (!IsValidMacHandle(h)) return false;
+
+#ifdef USE_CBOR_CONTEXT
+	context = ((COSE_MacMessage *)h)->m_message.m_allocContext;
+#endif
+
+	_COSE_Mac_Release((COSE_MacMessage *)h);
+
+	COSE_FREE((COSE_MacMessage *)h, &context);
+
+	return true;
+}
+
+void _COSE_Mac_Release(COSE_MacMessage * p)
+{
+	// if (p->pbContent != NULL) COSE_FREE(p->pbContent, &p->m_message.m_allocContext);
+	//	if (p->pbIV != NULL) COSE_FREE(p->pbIV, &p->m_message.m_allocContext);
+	if (p->pbKey != NULL) COSE_FREE(p->pbKey, &p->m_message.m_allocContext);
+
+	_COSE_Release(&p->m_message);
+}
+
+
+
+HCOSE_RECIPIENT COSE_Mac_add_shared_secret(HCOSE_MAC hcose, COSE_Algorithms alg, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perror)
+{
+#ifdef USE_CBOR_CONTEXT
+	cn_cbor_context * context;
+#endif // USE_CBOR_CONTEXT
+	COSE_RecipientInfo * pobj;
+	COSE_MacMessage * pcose = (COSE_MacMessage *)hcose;
+
+	if (!IsValidMacHandle(hcose) || (rgbKey == NULL)) {
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return NULL;
+	}
+
+	switch (alg) {
+	case COSE_Algorithm_Direct:
+		break;
+
+	default:
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return NULL;
+	}
+
+
+#ifdef USE_CBOR_CONTEXT
+	context = &pcose->m_message.m_allocContext;
+#endif // USE_CBOR_CONTEXT
+
+	pobj = (COSE_RecipientInfo *)COSE_CALLOC(1, sizeof(COSE_RecipientInfo), context);
+	if (pobj == NULL) {
+	oom_error:
+		if (perror != NULL) perror->err = COSE_ERR_OUT_OF_MEMORY;
+	error:
+		// M00BUG COSE_Recipient_Free(pobj);
+		return NULL;
+	}
+
+	if (!_COSE_Init(&pobj->m_encrypt.m_message, CBOR_CONTEXT_PARAM_COMMA perror)) {
+		goto error;
+	}
+
+	if (!cn_cbor_mapput_int(pobj->m_encrypt.m_message.m_unprotectMap, COSE_Header_Algorithm, cn_cbor_int_create(alg, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) goto error;
+
+	if (cbKid > 0) {
+		byte * pb = (byte *)COSE_CALLOC(cbKid, 1, context);
+		if (pb == NULL) goto oom_error;
+		memcpy(pb, rgbKid, cbKid);
+		if (!cn_cbor_mapput_int(pobj->m_encrypt.m_message.m_unprotectMap, COSE_Header_KID, cn_cbor_data_create(pb, cbKid, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) {
+			COSE_FREE(pb, context);
+			goto oom_error; // M00BUG - get error from CBOR
+		}
+	}
+
+
+	pobj->m_encrypt.pbKey = (byte *)COSE_CALLOC(cbKey, 1, context);
+	if (pobj->m_encrypt.pbKey == NULL) goto error;
+	memcpy(pobj->m_encrypt.pbKey, rgbKey, cbKey);
+	pobj->m_encrypt.cbKey = cbKey;
+
+	pobj->m_recipientNext = pcose->m_recipientFirst;
+	pcose->m_recipientFirst = pobj;
+
+	cn_cbor * pRecipients = (cn_cbor *)cn_cbor_mapget_int(pcose->m_message.m_cbor, COSE_Header_Recipients);
+	if (pRecipients == NULL) {
+		pRecipients = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA NULL);
+		if (pRecipients == NULL) goto error;
+		if (!cn_cbor_mapput_int(pcose->m_message.m_cbor, COSE_Header_Recipients, pRecipients, CBOR_CONTEXT_PARAM_COMMA NULL)) {
+			cn_cbor_free(pRecipients, context);
+			goto error;
+		}
+	}
+
+	cn_cbor_array_append(pRecipients, pobj->m_encrypt.m_message.m_cbor, NULL);
+
+	pobj->m_encrypt.m_message.m_flags |= 1;
+	return (HCOSE_RECIPIENT)pobj;
+}
+
+void COSE_Mac_SetContent(HCOSE_MAC cose, const byte * rgbContent, size_t cbContent, cose_errback * errp)
+{
+	COSE_MacMessage * p = (COSE_MacMessage *)cose;
+	cn_cbor_context * context = &p->m_message.m_allocContext;
+
+	if (!IsValidMacHandle(cose)) {
+		if (errp != NULL) errp->err = COSE_ERR_INVALID_PARAMETER;
+		return;
+	}
+
+	p->pbContent = rgbContent;
+	p->cbContent = cbContent;
+
+	if (!cn_cbor_mapput_int(p->m_message.m_cbor, COSE_Header_PlainText, cn_cbor_data_create (rgbContent, cbContent, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) {
+		if (errp != NULL) errp->err = COSE_ERR_CBOR;
+		return;
+	}
+}
+
+
+const cn_cbor * COSE_Mac_map_get_int(HCOSE_MAC h, int key, int flags, cose_errback * perror)
+{
+	if (!IsValidMacHandle(h)) {
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return NULL;
+	}
+
+	return _COSE_map_get_int(&((COSE_MacMessage *)h)->m_message, key, flags, perror);
+}
+
+
+bool COSE_Mac_map_put(HCOSE_MAC h, int key, cn_cbor * value, int flags, cose_errback * perror)
+{
+	if (!IsValidMacHandle(h) || (value == NULL)) {
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return false;
+	}
+
+	return _COSE_map_put(&((COSE_MacMessage *)h)->m_message, key, value, flags, perror);
+}
+
+
+bool COSE_Mac_encrypt(HCOSE_MAC h, cose_errback * perror)
+{
+	int alg;
+	int t;
+	COSE_RecipientInfo * pri;
+	const cn_cbor * cn_Alg = NULL;
+	byte * pbAuthData = NULL;
+	cn_cbor * pAuthData = NULL;
+	cn_cbor * ptmp = NULL;
+	byte * pbProtected = NULL;
+	ssize_t cbProtected = 0;
+	size_t cbitKey;
+	cn_cbor_context * context;
+	COSE_Encrypt * pcose = (COSE_Encrypt *)h;
+	cose_errback error;
+
+	if (!IsValidMacHandle(h)) {
+		if (perror != NULL) perror->err = COSE_ERR_INVALID_PARAMETER;
+		return false;
+	}
+#ifdef USE_CBOR_CONTEXT
+	context = &pcose->m_message.m_allocContext;
+#endif // USE_CBOR_CONTEXT
+
+	cn_Alg = _COSE_map_get_int(&pcose->m_message, COSE_Header_Algorithm, COSE_BOTH, &error);
+
+	if (cn_Alg == NULL) {
+	error:
+		if (pbProtected != NULL) COSE_FREE(pbProtected, context);
+		if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
+		if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
+		if (ptmp != NULL) cn_cbor_free(ptmp CBOR_CONTEXT_PARAM);
+		if (perror != NULL) *perror = error;
+		return false;
+	}
+	if (cn_Alg->type != CN_CBOR_UINT) goto error;
+	alg = cn_Alg->v.uint;
+
+	//  Get the key size
+
+	switch (alg) {
+	case COSE_Algorithm_HMAC_256_256:
+		cbitKey = 256;
+		break;
+
+	default:
+		goto error;
+	}
+
+	//  If we are doing direct encryption - then recipient generates the key
+
+	if (pcose->pbKey == NULL) {
+		t = 0;
+		for (pri = pcose->m_recipientFirst; pri != NULL; pri = pri->m_recipientNext) {
+			if (pri->m_encrypt.m_message.m_flags & 1) {
+				t |= 1;
+				pcose->pbKey = _COSE_RecipientInfo_generateKey(pri, cbitKey);
+				if (pcose->pbKey == NULL) goto error;
+				pcose->cbKey = cbitKey / 8;
+			}
+			else {
+				t |= 2;
+			}
+		}
+		if (t == 3) {
+			error.err = CN_CBOR_ERR_INVALID_PARAMETER;
+			goto error;
+		}
+	}
+
+	if (pcose->pbKey == NULL) {
+		pcose->pbKey = (byte *)COSE_CALLOC(cbitKey / 8, 1, context);
+		if (pcose->pbKey == NULL) goto error;
+		pcose->cbKey = cbitKey / 8;
+		rand_bytes(pcose->pbKey, pcose->cbKey);
+	}
+
+	//  Build protected headers
+
+	if (pcose->m_message.m_protectedMap->first_child != NULL) {
+		cbProtected = cn_cbor_encoder_write(RgbDontUse2, 0, sizeof(RgbDontUse2), pcose->m_message.m_protectedMap);
+		pbProtected = (byte *)COSE_CALLOC(cbProtected, 1, context);
+		if (pbProtected == NULL) goto error;
+		if (cn_cbor_encoder_write(pbProtected, 0, cbProtected, pcose->m_message.m_protectedMap) != cbProtected) goto error;
+		if (!cn_cbor_mapput_int(pcose->m_message.m_cbor, COSE_Header_Protected, cn_cbor_data_create(pbProtected, cbProtected, CBOR_CONTEXT_PARAM_COMMA NULL), CBOR_CONTEXT_PARAM_COMMA NULL)) goto error;
+	}
+	else {
+		pbProtected = NULL;
+		cbProtected = 0;
+	}
+
+	//  Add Unprotected headers
+	if (pcose->m_message.m_unprotectMap->first_child != NULL) {
+		if (!cn_cbor_mapput_int(pcose->m_message.m_cbor, COSE_Header_Unprotected, pcose->m_message.m_unprotectMap, CBOR_CONTEXT_PARAM_COMMA NULL)) goto error;
+		pcose->m_message.m_ownUnprotectedMap = false;
+	}
+
+	//  Build authenticated data
+	//  Protected headers
+	//  external data
+	//  body
+
+	ssize_t cbAuthData = 0;
+	pbAuthData = NULL;
+	pAuthData = cn_cbor_array_create(CBOR_CONTEXT_PARAM_COMMA NULL);
+
+	ptmp = cn_cbor_data_create(pbProtected, cbProtected, CBOR_CONTEXT_PARAM_COMMA NULL);
+	if (ptmp == NULL) goto error;
+	cn_cbor_array_append(pAuthData, ptmp, NULL);
+	pbProtected = NULL;
+	ptmp = NULL;
+
+	ptmp = cn_cbor_data_create(NULL, 0, CBOR_CONTEXT_PARAM_COMMA NULL);
+	if (ptmp == NULL) goto error;
+	cn_cbor_array_append(pAuthData, ptmp, NULL);
+	ptmp = NULL;
+
+	ptmp = cn_cbor_data_create(pcose->pbContent, pcose->cbContent, CBOR_CONTEXT_PARAM_COMMA NULL);
+	if (ptmp == NULL) goto error;
+	cn_cbor_array_append(pAuthData, ptmp, NULL);
+	ptmp = NULL;
+
+	cbAuthData = cn_cbor_encoder_write(RgbDontUse2, 0, sizeof(RgbDontUse2), pAuthData);
+	pbAuthData = (byte *)COSE_CALLOC(cbAuthData, 1, context);
+	if (pbAuthData == NULL) goto error;
+	if (cn_cbor_encoder_write(pbAuthData, 0, cbAuthData, pAuthData) != cbAuthData) goto error;
+
+	switch (alg) {
+	case COSE_Algorithm_HMAC_256_256:
+		if (!HMAC_Create(pcose, 256, 256, pbAuthData, cbAuthData, perror)) goto error;
+		break;
+
+	default:
+		return false;
+	}
+
+	for (pri = pcose->m_recipientFirst; pri != NULL; pri = pri->m_recipientNext) {
+		_COSE_Encrypt_SetContent(&pri->m_encrypt, pcose->pbKey, pcose->cbKey, &error);
+		if (error.err != COSE_ERR_NONE) goto error;
+
+		if (!COSE_Encrypt_encrypt((HCOSE_ENCRYPT)&pri->m_encrypt, &error)) goto error;
+	}
+
+	//  Figure out the clean up
+
+	if (pbAuthData != NULL) COSE_FREE(pbAuthData, context);
+	if (pAuthData != NULL) cn_cbor_free(pAuthData CBOR_CONTEXT_PARAM);
+
+	return true;
+}
+
diff --git a/src/cose.h b/src/cose.h
index 10811c1..28b0560 100644
--- a/src/cose.h
+++ b/src/cose.h
@@ -6,9 +6,10 @@
 
 typedef struct _cose * HCOSE;
 typedef struct _cose_sign * HCOSE_SIGN;
+typedef struct _cose_signer * HCOSE_SIGNER;
 typedef struct _cose_encrypt * HCOSE_ENCRYPT;
 typedef struct _cose_recipient * HCOSE_RECIPIENT;
-
+typedef struct _cose_mac * HCOSE_MAC;
 
 /**
 * All of the different kinds of errors
@@ -27,13 +28,15 @@
 	/** No usable recipient found */
 	COSE_ERR_NO_RECIPIENT_FOUND,
 	/** Decryption operation failed */
-	COSE_ERR_DECRYPT_FAILED
+	COSE_ERR_DECRYPT_FAILED,
+	/** Cryptographic failure */
+	COSE_ERR_CRYPTO_FAIL
 } cose_error;
 
 /**
 * Errors
 */
-typedef struct cose_errback {
+typedef struct _cose_errback {
 	/** The error, or CN_CBOR_NO_ERROR if none */
 	cose_error err;
 } cose_errback;
@@ -47,23 +50,39 @@
 
 //  Functions for the signing object
 
-HCOSE_SIGN * COSE_Sign_Init(CBOR_CONTEXT_COMMA cose_errback * perr);
-// COSE_SignMessage * COSE_Sign_Init(const cn_cbor * COMMA_CBOR_CONTEXT);
-
+HCOSE_SIGN COSE_Sign_Init(CBOR_CONTEXT_COMMA cose_errback * perr);
+bool COSE_Sign_Free(HCOSE_SIGN cose);
 
 HCOSE_ENCRYPT  COSE_Encrypt_Init(CBOR_CONTEXT_COMMA cose_errback * perr);
 bool COSE_Encrypt_Free(HCOSE_ENCRYPT cose);
 
+HCOSE_MAC COSE_Mac_Init(CBOR_CONTEXT_COMMA cose_errback * perr);
+bool COSE_Mac_Free(HCOSE_MAC cose);
+
 typedef enum {
 	COSE_PROTECT_ONLY = 1,
 	COSE_UNPROTECT_ONLY = 2,
-	COSE_BOTH = 3
+	COSE_DONT_SEND = 4,
+	COSE_BOTH = 7
 } cose_protect_state;
 
 typedef enum {
-	COSE_Algorithm_AES_CCM_64 = 1,
-	COSE_Algorithm_Direct,
-	COSE_Algorithm_ECDH_ES_Direct
+	COSE_Algorithm_HMAC_256_256 = 4,
+
+	COSE_Algorithm_AES_CCM_16_64_128 = 10,
+	COSE_Algoirthm_AES_CCM_16_64_256 = 11,
+	COSE_Algorithm_AES_CCM_64_64_128 = 30,
+	COSE_Algorithm_AES_CCM_64_64_256 = 31,
+	COSE_Algorithm_AES_CCM_16_128_128 = 12,
+	COSE_Algorithm_AES_CCM_16_128_256 = 13,
+	COSE_Algorithm_AES_CCM_64_128_128 = 32,
+	COSE_Algorithm_AES_CCM_64_128_256 = 33,
+
+	COSE_Algorithm_Direct = -6,
+	COSE_Algorithm_ECDH_ES_Direct, 
+	COSE_Algorithm_PS256 = -26,
+	COSE_Algorithm_PS384 = -27,
+	COSE_Algorithm_PS512 = -28,
 } COSE_Algorithms;
 
 typedef enum {
@@ -74,7 +93,9 @@
 	COSE_Header_IV,
 	COSE_Header_Ciphertext,
 	COSE_Header_Recipients,
-	COSE_Header_Type
+	COSE_Header_Type,
+	COSE_Header_PlainText,
+	COSE_Header_Tag
 } COSE_Header;
 
 
@@ -93,3 +114,20 @@
 
 HCOSE_RECIPIENT COSE_Encrypt_GetRecipient(HCOSE_ENCRYPT cose, int iRecipient, cose_errback * perr);
 bool COSE_Recipient_SetKey(HCOSE_RECIPIENT h, const byte * rgb, int cb, cose_errback * perr);
+
+//
+//
+
+void COSE_Mac_SetContent(HCOSE_MAC cose, const byte * rgbContent, size_t cbContent, cose_errback * errp);
+
+const cn_cbor * COSE_Mac_map_get_int(HCOSE_MAC h, int key, int flags, cose_errback * perror);
+bool COSE_Mac_map_put(HCOSE_MAC cose, int key, cn_cbor * value, int flags, cose_errback * errp);
+
+bool COSE_Mac_encrypt(HCOSE_MAC cose, cose_errback * perror);
+
+void COSE_Encrypt_SetContent(HCOSE_ENCRYPT cose, const byte * rgbContent, size_t cbContent, cose_errback * errp);
+
+HCOSE_RECIPIENT COSE_Mac_add_shared_secret(HCOSE_MAC cose, COSE_Algorithms algId, byte * rgbKey, int cbKey, byte * rgbKid, int cbKid, cose_errback * perr);
+
+HCOSE_RECIPIENT COSE_Mac_GetRecipient(HCOSE_MAC cose, int iRecipient, cose_errback * perr);
+
diff --git a/src/cose_int.h b/src/cose_int.h
index 69afe6a..750c6a2 100644
--- a/src/cose_int.h
+++ b/src/cose_int.h
@@ -9,15 +9,26 @@
 	cn_cbor * m_cbor;
 	cn_cbor * m_protectedMap;
 	cn_cbor * m_unprotectMap;
+	cn_cbor * m_dontSendMap;
 #ifdef USE_CBOR_CONTEXT
 	cn_cbor_context m_allocContext;
 #endif
 } COSE;
 
+struct _SignerInfo;
+typedef struct _SignerInfo COSE_SignerInfo;
+
 typedef struct {
 	COSE m_message;	    // The message object
+	COSE_SignerInfo * m_signerFirst;
 } COSE_SignMessage;
 
+typedef struct _SignerInfo {
+	COSE m_message;
+	byte * pbKey;
+	size_t cbKey;
+	COSE_SignerInfo * m_signerNext;
+} COSE_SignerInfo;
 
 struct _RecipientInfo;
 typedef struct _RecipientInfo COSE_RecipientInfo;
@@ -29,8 +40,6 @@
 	size_t cbContent;
 	byte * pbKey;
 	size_t cbKey;
-//	byte * pbIV;
-//	size_t cbIV;
 } COSE_Encrypt;
 
 typedef struct _RecipientInfo {
@@ -38,6 +47,14 @@
 	COSE_RecipientInfo * m_recipientNext;
 } COSE_RecipientInfo;
 
+typedef struct {
+	COSE m_message;			// The message object
+	COSE_RecipientInfo * m_recipientFirst;
+	byte * pbContent;
+	size_t cbContent;
+	byte * pbKey;
+	size_t cbKey;
+} COSE_MacMessage;
 
 #ifdef USE_CBOR_CONTEXT
 /**
@@ -104,10 +121,22 @@
 
 extern HCOSE_ENCRYPT _COSE_Encrypt_Init_From_Object(cn_cbor *, COSE_Encrypt * pIn, CBOR_CONTEXT_COMMA cose_errback * errp);
 extern void _COSE_Encrypt_Release(COSE_Encrypt * p);
-extern bool _COSE_Encrypt_decrypt(COSE_Encrypt * pbody, COSE_RecipientInfo * pRecip, cose_errback * perr);
+extern bool _COSE_Encrypt_decrypt(COSE_Encrypt * pcose, COSE_RecipientInfo * pRecip, int cbitKey, byte *pbKeyIn, cose_errback * perr);
 extern void _COSE_Encrypt_SetContent(COSE_Encrypt * cose, const byte * rgbContent, size_t cbContent, cose_errback * errp);
 
 extern COSE_RecipientInfo * _COSE_Recipient_Init_From_Object(cn_cbor *, CBOR_CONTEXT_COMMA cose_errback * errp);
 extern void _COSE_Recipient_Free(COSE_RecipientInfo *);
 extern bool _COSE_Recipient_decrypt(COSE_RecipientInfo * pRecip, int cbitKey, byte * pbKey, cose_errback * errp);
 extern byte * _COSE_RecipientInfo_generateKey(COSE_RecipientInfo * pRecipient, size_t cbitKeySize);
+
+
+//  Signed items
+extern HCOSE_SIGN _COSE_Sign_Init_From_Object(cn_cbor *, COSE_SignMessage * pIn, CBOR_CONTEXT_COMMA cose_errback * errp);
+extern void _COSE_Sign_Release(COSE_SignMessage * p);
+
+//  Mac-ed items
+extern HCOSE_MAC _COSE_Mac_Init_From_Object(cn_cbor *, COSE_MacMessage * pIn, CBOR_CONTEXT_COMMA cose_errback * errp);
+extern void _COSE_Mac_Release(COSE_MacMessage * p);
+
+
+#define CHECK_CONDITION(condition, error) { if (!(condition)) { perr->err = error; goto errorReturn;}}
diff --git a/src/crypto.h b/src/crypto.h
index 3a74fb8..1f382dc 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -8,7 +8,7 @@
 * @param[in]   int          Size of authenticated data structure
 * @return                   Did the function succeed?
 */
-bool AES_CCM_Decrypt(COSE_Encrypt * pcose, int TSize, int LSize, const byte * pbAuthData, int cbAuthData);
+bool AES_CCM_Decrypt(COSE_Encrypt * pcose, int TSize, int LSize, const byte * pbKey, int cbKey, const byte * pbAuthData, int cbAuthData, cose_errback * perr);
 
 /**
 * Perform an AES-CCM Encryption operation
@@ -20,7 +20,21 @@
 * @param[in]   int          Size of authenticated data structure
 * @return                   Did the function succeed?
 */
-bool AES_CCM_Encrypt(COSE_Encrypt * pcose, int TSize, int LSize, const byte * pbAuthData, int cbAuthData);
+bool AES_CCM_Encrypt(COSE_Encrypt * pcose, int TSize, int LSize, const byte * pbAuthData, int cbAuthData, cose_errback * perr);
+
+
+/**
+* Perform an HMAC Creation operation
+*
+* @param[in]	COSE_Encrypt	Pointer to COSE Encryption context object
+* @param[in]	int				Hash function to be used
+* @param[in]	int				Size of Tag value to be created
+* @param[in]	byte *			Pointer to authenticated data structure
+* @param[in]	int				Size of authenticated data structure
+* @param[in]	cose_errback *	Error return location
+* @return						Did the function succeed?
+*/
+bool HMAC_Create(COSE_Encrypt * pcose, int HSize, int TSize, const byte * pbAuthData, int cbAuthData, cose_errback * perr);
 
 /**
 *  Generate random bytes in a buffer