Example #1
0
        /// <summary>
        /// Given the set of inputs, perform the crptographic operations that are needed
        /// to build a security context for a single sender and recipient.
        /// </summary>
        /// <param name="masterSecret">pre-shared key</param>
        /// <param name="entityId">name assigned to sender</param>
        /// <param name="masterSalt">salt value</param>
        /// <param name="algAEAD">encryption algorithm</param>
        /// <param name="algKeyAgree">key agreement algorithm</param>
        /// <returns></returns>
        private static EntityContext DeriveEntityContext(byte[] masterSecret, byte[] entityId, byte[] masterSalt = null, CBORObject algAEAD = null, CBORObject algKeyAgree = null)
        {
            EntityContext ctx = new EntityContext();

            ctx.Algorithm = algAEAD ?? AlgorithmValues.AES_CCM_64_64_128;
            ctx.Id        = entityId ?? throw new ArgumentNullException(nameof(entityId));
            if (algKeyAgree == null)
            {
                algKeyAgree = AlgorithmValues.ECDH_SS_HKDF_256;
            }

            ctx.ReplayWindow = new ReplayWindow(0, 64);

            CBORObject info = CBORObject.NewArray();

            // M00TODO - add the group id into this

            info.Add(entityId);                 // 0
            info.Add(ctx.Algorithm);            // 1
            info.Add("Key");                    // 2
            info.Add(128 / 8);                  // 3 in bytes


            IDigest sha256;

            if (algKeyAgree == null || algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_256))
            {
                sha256 = new Sha256Digest();
            }
            else if (algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_512))
            {
                sha256 = new Sha512Digest();
            }
            else
            {
                throw new ArgumentException("Unknown key agree algorithm");
            }

            IDerivationFunction hkdf = new HkdfBytesGenerator(sha256);

            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));

            ctx.Key = new byte[128 / 8];
            hkdf.GenerateBytes(ctx.Key, 0, ctx.Key.Length);

            info[2] = CBORObject.FromObject("IV");
            info[3] = CBORObject.FromObject(56 / 8);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.BaseIV = new byte[56 / 8];
            hkdf.GenerateBytes(ctx.BaseIV, 0, ctx.BaseIV.Length);

            return(ctx);
        }
        /// <summary>
        /// Given the set of inputs, perform the crptographic operations that are needed
        /// to build a security context for a single sender and recipient.
        /// </summary>
        /// <param name="masterSecret">pre-shared key</param>
        /// <param name="groupId">Group/Context Identifier</param>
        /// <param name="entityId">name assigned to sender</param>
        /// <param name="masterSalt">salt value</param>
        /// <param name="algAEAD">encryption algorithm</param>
        /// <param name="algKeyAgree">key agreement algorithm</param>
        /// <returns></returns>
        private static EntityContext DeriveEntityContext(byte[] masterSecret, byte[] groupId, byte[] entityId, byte[] masterSalt = null, CBORObject algAEAD = null, CBORObject algKeyAgree = null)
        {
            EntityContext ctx = new EntityContext();
            int           keySize;
            int           ivSize;

            ctx.Algorithm = algAEAD ?? AlgorithmValues.AES_CCM_16_64_128;
            ctx.Id        = entityId ?? throw new ArgumentNullException(nameof(entityId));
            if (algKeyAgree == null)
            {
                algKeyAgree = AlgorithmValues.ECDH_SS_HKDF_256;
            }

            if (ctx.Algorithm.Type != CBORType.Number)
            {
                throw new ArgumentException("algorithm is unknown");
            }
            switch ((AlgorithmValuesInt)ctx.Algorithm.AsInt32())
            {
            case AlgorithmValuesInt.AES_CCM_16_64_128:
                keySize = 128 / 8;
                ivSize  = 13;
                break;

            case AlgorithmValuesInt.AES_GCM_128:
                keySize = 128 / 8;
                ivSize  = 96 / 8;
                break;

            default:
                throw new ArgumentException("algorithm is unknown");
            }

            ctx.ReplayWindow = new ReplayWindow(0, 64);

            CBORObject info = CBORObject.NewArray();

            // M00TODO - add the group id into this

            info.Add(entityId);                 // 0
            info.Add(groupId);                  // 1
            info.Add(ctx.Algorithm);            // 2
            info.Add("Key");                    // 3
            info.Add(keySize);                  // 4 in bytes


            IDigest sha256;

            if (algKeyAgree == null || algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_256))
            {
                sha256 = new Sha256Digest();
            }
            else if (algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_512))
            {
                sha256 = new Sha512Digest();
            }
            else
            {
                throw new ArgumentException("Unknown key agree algorithm");
            }

            IDerivationFunction hkdf = new HkdfBytesGenerator(sha256);

            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));

            ctx.Key = new byte[keySize];
            hkdf.GenerateBytes(ctx.Key, 0, ctx.Key.Length);

            info[0] = CBORObject.FromObject(new byte[0]);
            info[3] = CBORObject.FromObject("IV");
            info[4] = CBORObject.FromObject(ivSize);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.BaseIV = new byte[ivSize];
            hkdf.GenerateBytes(ctx.BaseIV, 0, ctx.BaseIV.Length);

            // Modify the context

            if (ivSize - 6 < entityId.Length)
            {
                throw new CoAPException("Entity id is too long");
            }
            ctx.BaseIV[0] ^= (byte)entityId.Length;
            int i1 = ivSize - 5 - entityId.Length /*- 1*/;

            for (int i = 0; i < entityId.Length; i++)
            {
                ctx.BaseIV[i1 + i] ^= entityId[i];
            }

            return(ctx);
        }
Example #3
0
        /// <summary>
        /// Given the set of inputs, perform the crptographic operations that are needed
        /// to build a security context for a single sender and recipient.
        /// </summary>
        /// <param name="masterSecret">pre-shared key</param>
        /// <param name="senderId">name assigned to sender</param>
        /// <param name="recipientId">name assigned to recipient</param>
        /// <param name="masterSalt">salt value</param>
        /// <param name="algAEAD">encryption algorithm</param>
        /// <param name="algKeyAgree">key agreement algorithm</param>
        /// <returns></returns>
        public static SecurityContext DeriveContext(byte[] masterSecret, byte[] senderId, byte[] recipientId, byte[] masterSalt = null, CBORObject algAEAD = null, CBORObject algKeyAgree = null)
        {
            SecurityContext ctx = new SecurityContext();

            if (algAEAD == null)
            {
                ctx.Sender.Algorithm = AlgorithmValues.AES_CCM_64_64_128;
            }
            else
            {
                ctx.Sender.Algorithm = algAEAD;
            }
            ctx.Sender.Id = senderId ?? throw new ArgumentNullException(nameof(senderId));

            ctx.Recipient = new EntityContext {
                Algorithm = ctx.Sender.Algorithm,
                Id        = recipientId ?? throw new ArgumentNullException(nameof(recipientId)),
                                  ReplayWindow = new ReplayWindow(0, 64)
            };


            CBORObject info = CBORObject.NewArray();

            info.Add(senderId);             // 0
            info.Add(ctx.Sender.Algorithm); // 1
            info.Add("Key");                // 2
            info.Add(128 / 8);              // 3 in bytes

            IDigest sha256;

            if (algKeyAgree == null || algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_256))
            {
                sha256 = new Sha256Digest();
            }
            else if (algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_512))
            {
                sha256 = new Sha512Digest();
            }
            else
            {
                throw new ArgumentException("Unrecognized key agreement algorithm");
            }

            IDerivationFunction hkdf = new HkdfBytesGenerator(sha256);

            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));

            ctx.Sender.Key = new byte[128 / 8];
            hkdf.GenerateBytes(ctx.Sender.Key, 0, ctx.Sender.Key.Length);

            info[0] = CBORObject.FromObject(recipientId);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.Recipient.Key = new byte[128 / 8];
            hkdf.GenerateBytes(ctx.Recipient.Key, 0, ctx.Recipient.Key.Length);

            info[2] = CBORObject.FromObject("IV");
            info[3] = CBORObject.FromObject(56 / 8);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.Recipient.BaseIV = new byte[56 / 8];
            hkdf.GenerateBytes(ctx.Recipient.BaseIV, 0, ctx.Recipient.BaseIV.Length);

            info[0] = CBORObject.FromObject(senderId);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.Sender.BaseIV = new byte[56 / 8];
            hkdf.GenerateBytes(ctx.Sender.BaseIV, 0, ctx.Sender.BaseIV.Length);

            //  Give a unique context number for doing comparisons

            ctx.ContextNo   = _ContextNumber;
            _ContextNumber += 1;

            return(ctx);
        }
        /// <summary>
        /// Given the set of inputs, perform the crptographic operations that are needed
        /// to build a security context for a single sender and recipient.
        /// </summary>
        /// <param name="masterSecret">pre-shared key</param>
        /// <param name="senderContext">context for the ID</param>
        /// <param name="senderId">name assigned to sender</param>
        /// <param name="recipientId">name assigned to recipient</param>
        /// <param name="masterSalt">salt value</param>
        /// <param name="algAEAD">encryption algorithm</param>
        /// <param name="algKeyAgree">key agreement algorithm</param>
        /// <returns></returns>
        public static SecurityContext DeriveContext(byte[] masterSecret, byte[] senderContext, byte[] senderId, byte[] recipientId,
                                                    byte[] masterSalt = null, CBORObject algAEAD = null, CBORObject algKeyAgree = null)
        {
            int             cbKey;
            int             cbIV;
            SecurityContext ctx = new SecurityContext();

            if (algAEAD == null)
            {
                ctx.Sender.Algorithm = AlgorithmValues.AES_CCM_16_64_128;
            }
            else
            {
                ctx.Sender.Algorithm = algAEAD;
            }

            if (ctx.Sender.Algorithm.Type != CBORType.Number)
            {
                throw new CoAPException("Unsupported algorithm");
            }
            switch ((AlgorithmValuesInt)ctx.Sender.Algorithm.AsInt32())
            {
            case AlgorithmValuesInt.AES_CCM_16_64_128:
                cbKey = 128 / 8;
                cbIV  = 13;
                break;

            case AlgorithmValuesInt.AES_CCM_64_64_128:
                cbKey = 128 / 8;
                cbIV  = 56 / 8;
                break;

            case AlgorithmValuesInt.AES_CCM_64_128_128:
                cbKey = 128 / 8;
                cbIV  = 56 / 8;
                break;

            case AlgorithmValuesInt.AES_CCM_16_128_128:
                cbKey = 128 / 8;
                cbIV  = 13;
                break;

            case AlgorithmValuesInt.AES_GCM_128:
                cbKey = 128 / 8;
                cbIV  = 96 / 8;
                break;

            default:
                throw new CoAPException("Unsupported algorithm");
            }

            ctx.Sender.Id = senderId ?? throw new ArgumentNullException(nameof(senderId));

            ctx.Recipient = new EntityContext {
                Algorithm = ctx.Sender.Algorithm,
                Id        = recipientId ?? throw new ArgumentNullException(nameof(recipientId)),
                                  ReplayWindow = new ReplayWindow(0, 64)
            };


            CBORObject info = CBORObject.NewArray();

            info.Add(senderId);             // 0
            info.Add(senderContext);        // 1
            info.Add(ctx.Sender.Algorithm); // 2
            info.Add("Key");                // 3
            info.Add(cbKey);                // 4 in bytes

            IDigest sha256;

            if (algKeyAgree == null || algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_256))
            {
                sha256 = new Sha256Digest();
            }
            else if (algKeyAgree.Equals(AlgorithmValues.ECDH_SS_HKDF_512))
            {
                sha256 = new Sha512Digest();
            }
            else
            {
                throw new ArgumentException("Unrecognized key agreement algorithm");
            }

            IDerivationFunction hkdf = new HkdfBytesGenerator(sha256);

            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));

            ctx.Sender.Key = new byte[cbKey];
            hkdf.GenerateBytes(ctx.Sender.Key, 0, ctx.Sender.Key.Length);

            info[0] = CBORObject.FromObject(recipientId);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.Recipient.Key = new byte[cbKey];
            hkdf.GenerateBytes(ctx.Recipient.Key, 0, ctx.Recipient.Key.Length);

            info[0] = CBORObject.FromObject(new byte[0]);
            info[3] = CBORObject.FromObject("IV");
            info[4] = CBORObject.FromObject(cbIV);
            hkdf.Init(new HkdfParameters(masterSecret, masterSalt, info.EncodeToBytes()));
            ctx.Recipient.BaseIV = new byte[cbIV];
            hkdf.GenerateBytes(ctx.Recipient.BaseIV, 0, ctx.Recipient.BaseIV.Length);
            ctx.Sender.BaseIV = (byte[])ctx.Recipient.BaseIV.Clone();

            int iIv = cbIV - 5 - senderId.Length;

            if (cbIV - 6 < senderId.Length)
            {
                throw new CoAPException("Sender Id too long");
            }
            ctx.Sender.BaseIV[0] ^= (byte)senderId.Length;
            for (int i = 0; i < senderId.Length; i++)
            {
                ctx.Sender.BaseIV[iIv + i] ^= senderId[i];
            }

            iIv = cbIV - 5 - recipientId.Length;
            if (cbIV - 6 < recipientId.Length)
            {
                throw new CoAPException("Recipient Id too long");
            }
            ctx.Recipient.BaseIV[0] ^= (byte)recipientId.Length;
            for (int i = 0; i < recipientId.Length; i++)
            {
                ctx.Recipient.BaseIV[iIv + i] ^= recipientId[i];
            }

            //  Give a unique context number for doing comparisons

            ctx.ContextNo   = _contextNumber;
            _contextNumber += 1;

            return(ctx);
        }