Exemplo n.º 1
0
        public void roundTrip()
        {
            Encrypt0Message msg = new Encrypt0Message();

            msg.AddAttribute(HeaderKeys.Algorithm, AlgorithmValues.AES_GCM_128, Attributes.PROTECTED);
            msg.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(rgbIV96), Attributes.UNPROTECTED);
            msg.SetContent(strContent);
            msg.Encrypt(rgbKey128);
            byte[] rgbMsg = msg.EncodeToBytes();

            msg = (Encrypt0Message)Message.DecodeFromBytes(rgbMsg);
            msg.Decrypt(rgbKey128);

            Assert.AreEqual <string>(msg.GetContentAsString(), strContent);
        }
Exemplo n.º 2
0
        public void TestRoundTrip4()
        {
            Encrypt0Message msg = new Encrypt0Message();

            msg.AddAttribute(HeaderKeys.Algorithm, AlgorithmValues.AES_GCM_128, Attributes.PROTECTED);
            msg.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(rgbIV96), Attributes.PROTECTED);
            msg.SetContent(rgbContent);
            msg.Encrypt(rgbKey128);
            CBORObject rgbMsg = msg.EncodeToCBORObject();

            msg = (Encrypt0Message)Message.DecodeFromCBOR(rgbMsg);
            byte[] contentNew = msg.Decrypt(rgbKey128);

            CollectionAssert.AreEqual(rgbContent, (contentNew));
        }
Exemplo n.º 3
0
        public void roundTripDetached()
        {
            Encrypt0Message msg = new Encrypt0Message(true, false);

            msg.AddAttribute(HeaderKeys.Algorithm, AlgorithmValues.AES_GCM_128, Attributes.PROTECTED);
            msg.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(rgbIV96), Attributes.UNPROTECTED);
            msg.SetContent(strContent);
            msg.Encrypt(rgbKey128);

            byte[] content = msg.GetEncryptedContent();

            byte[] rgb = msg.EncodeToBytes();

            msg = (Encrypt0Message)Message.DecodeFromBytes(rgb);
            msg.SetEncryptedContent(content);
            msg.Decrypt(rgbKey128);
        }
Exemplo n.º 4
0
        public void nullKeyForDecrypt()
        {
            Encrypt0Message msg = new Encrypt0Message(true, true);

            //        thrown.expect(CoseException.class);
            //        thrown.expectMessage("No Encrypted Content Specified");

            msg.AddAttribute(HeaderKeys.Algorithm, AlgorithmValues.AES_GCM_128, Attributes.PROTECTED);
            msg.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(rgbIV96), Attributes.UNPROTECTED);
            msg.SetContent(strContent);
            msg.Encrypt(rgbKey128);

            byte[] rgb = msg.EncodeToBytes();

            msg = (Encrypt0Message)Message.DecodeFromBytes(rgb);
            msg.Decrypt(null);
        }
Exemplo n.º 5
0
        public void NoContentForDecrypt()
        {
            Encrypt0Message msg = new Encrypt0Message(true, false);


            msg.AddAttribute(HeaderKeys.Algorithm, AlgorithmValues.AES_GCM_128, Attributes.PROTECTED);
            msg.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(rgbIV96), Attributes.UNPROTECTED);
            msg.SetContent(rgbContent);
            msg.Encrypt(rgbKey128);

            byte[] rgb = msg.EncodeToBytes();

            msg = (Encrypt0Message)Message.DecodeFromBytes(rgb);
            CoseException e = Assert.ThrowsException <CoseException>(() =>
                                                                     msg.Decrypt(rgbKey128));

            Assert.AreEqual(e.Message, ("No Encrypted Content Specified."));
        }
Exemplo n.º 6
0
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (response.HasOption(OptionType.Oscoap))
            {
                Option op = response.GetFirstOption(OptionType.Oscoap);

                if (exchange.OscoapContext == null)
                {
                    return;
                }

                SecurityContext ctx = exchange.OscoapContext;

                bool fServerIv = true;

                Encrypt0Message msg = Uncompress(op.RawValue);
                if (msg == null)
                {
                    return;
                }
                msg.SetEncryptedContent(response.Payload);

                SecurityContext.EntityContext recip = ctx.Recipient;
                if (recip == null)
                {
                    if (ctx.GroupId == null)
                    {
                        //  This is not currently a valid state to be in
                        return;
                    }
                    CBORObject kid = msg.FindAttribute(HeaderKeys.KeyId);
                    if (kid == null)
                    {
                        //  this is not currently a valid state to be in
                        return;
                    }
                    recip = ctx.Recipients[kid.GetByteString()];
                    if (recip == null)
                    {
                        // M00TODO - deal with asking the user for a recipient structure at this point.
                        return;
                    }
                }

                if (msg.FindAttribute(HeaderKeys.PartialIV) == null)
                {
                    msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV), Attributes.DO_NOT_SEND);
                    fServerIv = false;
                }


                byte[] partialIV  = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString();
                byte[] seqNoArray = new byte[8];
                Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(seqNoArray);
                }
                Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0);

                if (fServerIv)
                {
                    if (_replayWindow && recip.ReplayWindow.HitTest(seqNo))
                    {
                        return;
                    }
                }

                msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND);

                CBORObject fullIV;
                if (fServerIv)
                {
                    fullIV = recip.GetIV(partialIV);
                }
                else
                {
                    fullIV = ctx.Sender.GetIV(partialIV);
                }
                msg.AddAttribute(HeaderKeys.IV, fullIV, Attributes.DO_NOT_SEND);

                //  build aad
                CBORObject aad = CBORObject.NewArray();
                aad.Add(1);
                aad.Add(CBORObject.NewArray());
                aad[1].Add(recip.Algorithm);
                aad.Add(ctx.Sender.Id);
                aad.Add(ctx.Sender.PartialIV);
                aad.Add(CBORObject.FromObject(new byte[0])); // OPTIONS
                if (ctx.GroupId != null)
                {
                    aad.Add(ctx.GroupId);
                }

                msg.SetExternalData(aad.EncodeToBytes());

                _Log.Info(m => m($"fServerIv = {fServerIv}"));
                _Log.Info(m => m("ReceiveResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes())));
                _Log.Info(m => m($"ReceiveResponse: IV = {BitConverter.ToString(fullIV.GetByteString())}"));
                _Log.Info(m => m($"ReceiveResponse: Key = {BitConverter.ToString(recip.Key)}"));

                byte[] payload = msg.Decrypt(recip.Key);

                recip.ReplayWindow.SetHit(seqNo);

                byte[] rgb = new byte[payload.Length + _FixedHeader.Length - 1];
                Array.Copy(_FixedHeader, rgb, _FixedHeader.Length);
                Array.Copy(payload, 1, rgb, _FixedHeader.Length, payload.Length - 1);
                rgb[1] = payload[0];
                Codec.IMessageDecoder me = Spec.NewMessageDecoder(rgb);
                Response decryptedReq    = me.DecodeResponse();

                response.Payload    = decryptedReq.Payload;
                response.StatusCode = decryptedReq.StatusCode;

                RestoreOptions(response, decryptedReq);
            }
            base.ReceiveResponse(nextLayer, exchange, response);
        }
Exemplo n.º 7
0
        /// <inheritdoc />
        public override void ReceiveRequest(INextLayer nextLayer, Exchange exchange, Request request)
        {
            if (!request.HasOption(OptionType.Oscoap))
            {
                base.ReceiveRequest(nextLayer, exchange, request);
                return;
            }
            Response response;

            try {
                Option op = request.GetFirstOption(OptionType.Oscoap);
                request.RemoveOptions(OptionType.Oscoap);

                _Log.Info(m => m("Incoming Request: {0}", Util.Utils.ToString(request)));

                Encrypt0Message msg = Uncompress(op.RawValue);
                if (msg == null)
                {
                    //  Only bother to reply to CON messages
                    if (request.Type == MessageType.CON)
                    {
                        response = new Response(StatusCode.BadOption)
                        {
                            PayloadString = "Unable to decompress"
                        };
                        exchange.SendResponse(response);
                    }
                    return;
                }
                msg.SetEncryptedContent(request.Payload);

                List <SecurityContext> contexts = new List <SecurityContext>();
                SecurityContext        ctx      = null;
                CBORObject             kid;

                //  We may know the context because it is a follow up on a conversation -
                //  In which case we can just use the same one.
                //  M00BUG - Multicast problem of recipient ID?

                CBORObject gid = null;
                if (exchange.OscoapContext != null)
                {
                    contexts.Add(exchange.OscoapContext);
                    if (exchange.OscoapContext.GroupId != null)
                    {
                        gid = CBORObject.FromObject(exchange.OscoapContext.GroupId);
                    }
                    kid = CBORObject.FromObject(exchange.OscoapSenderId);
                }
                else
                {
                    gid = msg.FindAttribute(CBORObject.FromObject("gid"));
                    kid = msg.FindAttribute(HeaderKeys.KeyId);

                    if (kid == null)
                    {
                        exchange.SendResponse(new Response(StatusCode.BadRequest));
                        return;
                    }

                    if (gid != null)
                    {
                        contexts = SecurityContextSet.AllContexts.FindByGroupId(gid.GetByteString());
                    }
                    else
                    {
                        contexts = SecurityContextSet.AllContexts.FindByKid(kid.GetByteString());
                    }

                    if (contexts.Count == 0)
                    {
                        response = new Response(StatusCode.Unauthorized)
                        {
                            PayloadString = "No Context Found - 1"
                        };
                        exchange.SendResponse(response);
                        return; // Ignore messages that have no known security context.
                    }
                }

                byte[] partialIV = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString();

                //  Build AAD
                CBORObject aad = CBORObject.NewArray();
                aad.Add(CBORObject.FromObject(1));    // M00BUG
                aad.Add(CBORObject.NewArray());       // Array place holder
                aad[1].Add(CBORObject.FromObject(0)); // Place holder for algorithm
                aad.Add(CBORObject.FromObject(kid));
                aad.Add(CBORObject.FromObject(partialIV));
                aad.Add(CBORObject.FromObject(new byte[0])); // encoded I options
                if (gid != null)
                {
                    aad.Add(gid);
                }

                byte[] payload = null;

                byte[] seqNoArray = new byte[8];
                Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(seqNoArray);
                }
                Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0);

                String responseString = "General decrypt failure";

                foreach (SecurityContext context in contexts)
                {
                    SecurityContext.EntityContext recip = context.Recipient;
                    if (recip == null)
                    {
                        if (kid == null)
                        {
                            continue;
                        }
                        recip = context.Recipients[kid.GetByteString()];
                        if (recip == null)
                        {
                            continue;
                        }
                    }

                    if (_replayWindow && recip.ReplayWindow.HitTest(seqNo))
                    {
                        _Log.Info(m => m("Hit test on {0} failed", seqNo));
                        responseString = "Hit test - duplicate";
                        continue;
                    }

                    aad[1][0] = recip.Algorithm;

                    if (_Log.IsInfoEnabled)
                    {
                        _Log.Info("AAD = " + BitConverter.ToString(aad.EncodeToBytes()));
                        _Log.Info("IV = " + BitConverter.ToString(recip.GetIV(partialIV).GetByteString()));
                        _Log.Info("Key = " + BitConverter.ToString(recip.Key));
                    }


                    msg.SetExternalData(aad.EncodeToBytes());

                    msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND);
                    msg.AddAttribute(HeaderKeys.IV, recip.GetIV(partialIV), Attributes.DO_NOT_SEND);

                    try {
                        ctx     = context;
                        payload = msg.Decrypt(recip.Key);
                        recip.ReplayWindow.SetHit(seqNo);
                    }
                    catch (Exception e) {
                        if (_Log.IsInfoEnabled)
                        {
                            _Log.Info("--- ", e);
                        }
                        ctx = null;
                    }

                    if (ctx != null)
                    {
                        break;
                    }
                }

                if (ctx == null)
                {
                    if (request.Type == MessageType.CON)
                    {
                        response = new Response(StatusCode.BadRequest)
                        {
                            PayloadString = responseString
                        };
                        exchange.SendResponse(response);
                    }
                    return;
                }

                exchange.OscoapContext        = ctx; // So we know it on the way back.
                request.OscoapContext         = ctx;
                exchange.OscoapSequenceNumber = partialIV;
                exchange.OscoapSenderId       = kid.GetByteString();

                byte[] newRequestData = new byte[payload.Length + _FixedHeader.Length - 1];
                Array.Copy(_FixedHeader, newRequestData, _FixedHeader.Length);
                Array.Copy(payload, 1, newRequestData, _FixedHeader.Length, payload.Length - 1);
                newRequestData[1] = payload[0];

                Codec.IMessageDecoder me = Spec.NewMessageDecoder(newRequestData);
                Request newRequest       = me.DecodeRequest();

                //  Update headers is a pain

                RestoreOptions(request, newRequest);
                request.Method = newRequest.Method;

                if (_Log.IsInfoEnabled)
                {
                    // log.Info(String.Format("Secure message post = " + Util.Utils.ToString(request)));
                }

                //  We may want a new exchange at this point if it relates to a new message for blockwise.

                if (request.HasOption(OptionType.Block2))
                {
                    Exchange.KeyUri keyUri = new Exchange.KeyUri(request.URI, null, request.Source);
                    BlockHolder     block;
                    _ongoingExchanges.TryGetValue(keyUri, out block);

                    if (block != null)
                    {
                        block.RestoreTo(exchange);
                    }
                }

                request.Payload = newRequest.Payload;
            }
            catch (Exception e) {
                _Log.Error("OSCOAP Layer: reject message because ", e);
                exchange.OscoapContext = null;

                if (request.Type == MessageType.CON)
                {
                    response = new Response(StatusCode.Unauthorized)
                    {
                        Payload = Encoding.UTF8.GetBytes("Error is " + e.Message)
                    };
                    exchange.SendResponse(response);
                }
                //  Ignore messages that we cannot decrypt.
                return;
            }

            base.ReceiveRequest(nextLayer, exchange, request);
        }
Exemplo n.º 8
0
        static public EdhocResponder ParseMessage3(byte[] msgData, KeySet serverKeys)
        {
            CBORObject algVerify = null;

            CBORObject msg = CBORObject.DecodeFromBytes(msgData);

            if (msg.Type != CBORType.Array)
            {
                throw new Exception("Invalid message");
            }

            EdhocResponder edhoc = MessageList[new ListKey(msg[1].GetByteString())];

            edhoc._Messages[2] = msgData;

            if (edhoc._fSymmetricSecret)
            {
                if (msg[0].AsInt16() != 6)
                {
                    throw new Exception("Invalid Message");
                }
            }
            else
            {
                if (msg[0].AsInt16() != 3)
                {
                    throw new Exception("Invalid Message");
                }
            }


            Encrypt0Message enc0 = (Encrypt0Message)Com.AugustCellars.COSE.Message.DecodeFromBytes(msg[2].GetByteString(), Tags.Encrypt0);

            msg.Remove(msg[2]);

            byte[] data_3 = msg.EncodeToBytes();
            byte[] aad_3  = ConcatenateAndHash(new byte[][] { edhoc._LastMessageAuthenticator, data_3 }, edhoc._MessageDigest);

            byte[][] useKeys = _DeriveKeys(edhoc._Keys, edhoc._SecretSalt, aad_3, edhoc._algAEAD);
            byte[]   encKey  = useKeys[0];

            enc0.AddAttribute(HeaderKeys.Algorithm, edhoc._algAEAD, Attributes.DO_NOT_SEND);
            enc0.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(useKeys[1]), Attributes.DO_NOT_SEND);
            enc0.SetExternalData(aad_3);
            byte[] body = enc0.Decrypt(encKey);

            if (!edhoc._fSymmetricSecret)
            {
                CBORObject encBody = CBORObject.DecodeFromBytes(body);

                Sign1Message sign1 = (Sign1Message)Com.AugustCellars.COSE.Message.DecodeFromBytes(encBody[0].GetByteString(), Tags.Sign1);
                sign1.AddAttribute(HeaderKeys.Algorithm, edhoc._algSign, Attributes.DO_NOT_SEND);

                CBORObject kidObject = sign1.FindAttribute(HeaderKeys.KeyId);
                byte[]     kid       = null;
                if (kidObject != null)
                {
                    kid = kidObject.GetByteString();
                }
                sign1.SetExternalData(aad_3);

                KeySet keys = new KeySet();
                foreach (OneKey sigKey in serverKeys)
                {
                    if (sigKey.HasKid(kid))
                    {
                        keys.AddKey(sigKey);
                    }
                }

                List <OneKey> ks  = new List <OneKey>();
                List <OneKey> ks2 = ks.Where(f => f.HasKid(kid)).ToList();

                OneKey signingKey = null;
                foreach (OneKey sigKey in keys)
                {
                    try {
                        sign1.Validate(sigKey);
                        signingKey = sigKey;
                    }
                    catch (Exception) {
                        // nop;
                    }
                }

                if (signingKey == null)
                {
                    throw new Exception("Unable to complete - no signing key found");
                }
            }
            else
            {
                // body is the EXT_3 value
            }

            edhoc._LastMessageAuthenticator = ConcatenateAndHash(new byte[][] { edhoc._LastMessageAuthenticator, msgData }, edhoc._MessageDigest);

            return(edhoc);
        }
Exemplo n.º 9
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="msgData"></param>
        /// <param name="keySetPublic"></param>
        public void ParseMessage2(byte[] msgData, KeySet keySetPublic)
        {
            int        msgIndex;
            CBORObject algVerify = null;

            CBORObject msg = CBORObject.DecodeFromBytes(msgData);

            if (msg.Type != CBORType.Array)
            {
                throw new Exception("Invalid message");
            }

            _Messages[1] = msgData;

            if (_fSymmetricSecret)
            {
                if (msg[0].AsInt16() != 5)
                {
                    throw new Exception("Invalid Message");
                }
            }
            else
            {
                if (msg[0].AsInt16() != 2)
                {
                    throw new Exception("Invalid Message");
                }
            }

            _SessionId[1] = msg[2].GetByteString();       // S_V
            _Nonce[1]     = msg[3].GetByteString();       // N_V
            _Keys[1]      = new OneKey(msg[4]);           // E_V
            _algKeyAgree  = msg[5];                       // HKDF_V
            _algAEAD      = msg[6];                       // AAEAD_V
            if (_fSymmetricSecret)
            {
                msgIndex = 7;
            }
            else
            {
                algVerify = msg[7];                                                                            // SIG_V
                _algSign  = _SelectAlgorithm(msg[8], new CBORObject[] { _SigningKey[CoseKeyKeys.Algorithm] }); // SIG_U
                msgIndex  = 9;
            }

            //  What is the hash algorithm to use?
            switch ((AlgorithmValuesInt)_algKeyAgree.AsInt32())
            {
            case AlgorithmValuesInt.ECDH_SS_HKDF_256:
                _MessageDigest = new Sha256Digest();
                break;

            case AlgorithmValuesInt.ECDH_SS_HKDF_512:
                _MessageDigest = new Sha512Digest();
                break;
            }


            Encrypt0Message enc0 = (Encrypt0Message)Com.AugustCellars.COSE.Message.DecodeFromBytes(msg[msgIndex].EncodeToBytes(), Tags.Encrypt0);

            msg.Remove(msg[msgIndex]);
            byte[] data_2 = msg.EncodeToBytes();
            byte[] aad_2  = ConcatenateAndHash(new byte[2][] { _Messages[0], data_2 }, _MessageDigest);

            byte[][] useKeys = _DeriveKeys(_Keys, _SecretSalt, aad_2, _algAEAD);
            byte[]   encKey  = useKeys[0];
            enc0.AddAttribute(HeaderKeys.Algorithm, _algAEAD, Attributes.DO_NOT_SEND);
            enc0.AddAttribute(HeaderKeys.IV, CBORObject.FromObject(useKeys[1]), Attributes.DO_NOT_SEND);
            enc0.SetExternalData(aad_2);
            byte[] body = enc0.Decrypt(encKey);

            if (!_fSymmetricSecret)
            {
                CBORObject encBody = CBORObject.DecodeFromBytes(body);

                Sign1Message sign1 = (Sign1Message)Com.AugustCellars.COSE.Message.DecodeFromBytes(encBody[0].GetByteString(), Tags.Sign1);
                sign1.AddAttribute(HeaderKeys.Algorithm, algVerify, Attributes.DO_NOT_SEND);

                CBORObject kid = sign1.FindAttribute(HeaderKeys.KeyId);
                sign1.SetExternalData(aad_2);



                foreach (OneKey sigKey in keySetPublic)
                {
                    sign1.Validate(sigKey); //FIND KEY);
                }
            }
            else
            {
                // body is the EXT_2 value
            }

            _LastMessageAuthenticator = ConcatenateAndHash(new byte[2][] { _LastMessageAuthenticator, msgData }, _MessageDigest);
        }
Exemplo n.º 10
0
        public override void ReceiveResponse(INextLayer nextLayer, Exchange exchange, Response response)
        {
            if (response.HasOption(OptionType.Oscoap))
            {
                Option op = response.GetFirstOption(OptionType.Oscoap);

                if (exchange.OscoreContext == null)
                {
                    return;
                }

                _Log.Info($"Incoming message for OSCORE\n{Utils.ToString(response)}");

                SecurityContext ctx = exchange.OscoreContext;

                bool fServerIv = true;

                Encrypt0Message msg = Uncompress(op.RawValue);
                if (msg == null)
                {
                    return;
                }
                msg.SetEncryptedContent(response.Payload);

                SecurityContext.EntityContext recip = ctx.Recipient;
                if (ctx.IsGroupContext)
                {
                    if (ctx.GroupId == null)
                    {
                        //  This is not currently a valid state to be in
                        return;
                    }

                    CBORObject kid = msg.FindAttribute(HeaderKeys.KeyId);
                    if (kid == null)
                    {
                        //  this is not currently a valid state to be in
                        return;
                    }
                    recip = ctx.Recipients[kid.GetByteString()];
                    if (recip == null)
                    {
                        // M00TODO - deal with asking the user for a recipient structure at this point.
                        return;
                    }

                    if (msg.FindAttribute(HeaderKeys.PartialIV) == null)
                    {
                        msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV),
                                         Attributes.DO_NOT_SEND);
                        fServerIv = false;
                    }
                }
                else
                {
                    if (msg.FindAttribute(HeaderKeys.PartialIV) == null)
                    {
                        msg.AddAttribute(HeaderKeys.PartialIV, CBORObject.FromObject(ctx.Sender.PartialIV),
                                         Attributes.DO_NOT_SEND);
                        fServerIv = false;
                    }
                }

                byte[] partialIV  = msg.FindAttribute(HeaderKeys.PartialIV).GetByteString();
                byte[] seqNoArray = new byte[8];
                Array.Copy(partialIV, 0, seqNoArray, 8 - partialIV.Length, partialIV.Length);
                if (BitConverter.IsLittleEndian)
                {
                    Array.Reverse(seqNoArray);
                }
                Int64 seqNo = BitConverter.ToInt64(seqNoArray, 0);

                if (fServerIv)
                {
                    if (_replayWindow && recip.ReplayWindow.HitTest(seqNo))
                    {
                        return;
                    }
                }

                msg.AddAttribute(HeaderKeys.Algorithm, recip.Algorithm, Attributes.DO_NOT_SEND);

                CBORObject fullIV;
                if (fServerIv)
                {
                    fullIV = recip.GetIV(partialIV);
                }
                else
                {
                    fullIV = ctx.Sender.GetIV(partialIV);
                }

                msg.AddAttribute(HeaderKeys.IV, fullIV, Attributes.DO_NOT_SEND);

                //  build aad
                CBORObject aad = CBORObject.NewArray();
                aad.Add(1); // Version #
                aad.Add(CBORObject.NewArray());
                aad[1].Add(recip.Algorithm);
                aad.Add(ctx.Sender.Id);
                aad.Add(ctx.Sender.PartialIV);
                aad.Add(CBORObject.FromObject(new byte[0])); // OPTIONS

                if (ctx.Sender.SigningAlgorithm != null)
                {
                    aad[1].Add(ctx.Sender.SigningAlgorithm);
                    if (ctx.CountersignParams != null)
                    {
                        aad[1].Add(ctx.CountersignParams);
                    }

                    if (ctx.CountersignKeyParams != null)
                    {
                        aad[1].Add(ctx.CountersignKeyParams);
                    }
                }

                msg.SetExternalData(aad.EncodeToBytes());

                _Log.Info(m => m($"fServerIv = {fServerIv}"));
                _Log.Info(m => m("ReceiveResponse: AAD = " + BitConverter.ToString(aad.EncodeToBytes())));
                _Log.Info(m => m($"ReceiveResponse: IV = {BitConverter.ToString(fullIV.GetByteString())}"));
                _Log.Info(m => m($"ReceiveResponse: Key = {BitConverter.ToString(recip.Key)}"));

                if (ctx.IsGroupContext)
                {
                    aad.Add(op.RawValue);

                    int    cbSignature  = 64; // M00TODO   Need to figure out the size of the signature from the context.
                    byte[] rgbSignature = new byte[cbSignature];
                    byte[] rgbPayload   = new byte[response.Payload.Length - cbSignature];

                    Array.Copy(response.Payload, rgbPayload, rgbPayload.Length);
                    Array.Copy(response.Payload, rgbPayload.Length, rgbSignature, 0, cbSignature);

                    CounterSignature1 cs1 = new CounterSignature1(rgbSignature);
                    cs1.AddAttribute(HeaderKeys.Algorithm, ctx.Sender.SigningAlgorithm, Attributes.DO_NOT_SEND);
                    cs1.SetObject(msg);
                    cs1.SetKey(recip.SigningKey);

                    byte[] aadData = aad.EncodeToBytes();
                    cs1.SetExternalData(aadData);
                    msg.SetEncryptedContent(rgbPayload);

                    try {
                        if (!msg.Validate(cs1))
                        {
                            return;
                        }
                    }
                    catch (CoseException e) {
                        // try the next possible one
                        return;
                    }
                }

                byte[] payload = msg.Decrypt(recip.Key);

                recip.ReplayWindow.SetHit(seqNo);

                byte[] rgb = new byte[payload.Length + _FixedHeader.Length - 1];
                Array.Copy(_FixedHeader, rgb, _FixedHeader.Length);
                Array.Copy(payload, 1, rgb, _FixedHeader.Length, payload.Length - 1);
                rgb[1] = payload[0];
                Codec.IMessageDecoder me = Spec.NewMessageDecoder(rgb);
                Response decryptedReq    = me.DecodeResponse();

                _Log.Info($"Inner message for OSCORE{Utils.ToString(decryptedReq)}");

                response.Payload = decryptedReq.Payload;
                response.Code    = (int)decryptedReq.StatusCode;

                RestoreOptions(response, decryptedReq);
                if (decryptedReq.HasOption(OptionType.Observe))
                {
                    if (partialIV.Length > 3)
                    {
                        byte[] x = new byte[3];
                        Array.Copy(partialIV, partialIV.Length - 3, x, 0, 3);
                        partialIV = x;
                    }
                    response.AddOption(Option.Create(OptionType.Observe, partialIV));
                }

                _Log.Info($"Outgoing message for OSCORE{Utils.ToString(response)}");
            }
            base.ReceiveResponse(nextLayer, exchange, response);
        }