/// <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); }
// Tests the equivalence of the DecodeFromBytes and Read methods. public static CBORObject FromBytesTestAB(byte[] b) { CBORObject oa = FromBytesA(b); CBORObject ob = FromBytesB(b); if (!oa.Equals(ob)) { Assert.AreEqual(oa, ob); } return(oa); }
// Tests the equivalence of the DecodeFromBytes and Read methods. public static CBORObject FromBytesTestAB(byte[] b, CBOREncodeOptions options) { CBORObject oa = FromBytesA(b, options); CBORObject ob = FromBytesB(b, options); if (!oa.Equals(ob)) { Assert.AreEqual(oa, ob); } return(oa); }
public CBORObject Lookup(CBORObject value) { foreach (KeyValuePair <int, string> o in _dictionary) { if (value.Equals(CBORObject.FromObject(o.Value))) { CBORObject newValue = CBORObject.FromObject(o.Key); if (value.Type == CBORType.Number) { newValue = CBORObject.FromObjectAndTag(newValue, DictionaryTag); } return(newValue); } } return(value); }
public CBORObject Lookup(CBORObject value, bool isIntLegal) { if (value.Type == CBORType.TextString) { return(Lookup(value.AsString(), isIntLegal)); } foreach (KeyValuePair <int, object> o in _dictionary) { if (value.Equals(o.Value)) { if (isIntLegal) { return(CBORObject.FromObjectAndTag(o.Key, DictionaryTag)); } return(CBORObject.FromObject(o.Key)); } } return(value); }
/// <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); }
public static JSONPointer FromPointer(CBORObject obj, string pointer) { var index = 0; if (pointer == null) { throw new ArgumentNullException(nameof(pointer)); } if (pointer.Length == 0) { return(new JSONPointer(obj, pointer)); } while (true) { if (obj == null) { throw new ArgumentNullException(nameof(obj)); } if (obj.Type == CBORType.Array) { if (index >= pointer.Length || pointer[index] != '/') { throw new ArgumentException(pointer); } ++index; var value = new int[] { 0 }; int newIndex = ReadPositiveInteger(pointer, index, value); if (value[0] < 0) { if (index < pointer.Length && pointer[index] == '-' && (index + 1 == pointer.Length || pointer[index + 1] == '/')) { // Index at the end of the array return(new JSONPointer(obj, "-")); } throw new ArgumentException(pointer); } if (newIndex == pointer.Length) { return(new JSONPointer(obj, pointer.Substring(index))); } else { obj = obj[value[0]]; index = newIndex; } index = newIndex; } else if (obj.Type == CBORType.Map) { if (obj.Equals(CBORObject.Null)) { throw new KeyNotFoundException(pointer); } if (index >= pointer.Length || pointer[index] != '/') { throw new ArgumentException(pointer); } ++index; string key = null; int oldIndex = index; var tilde = false; while (index < pointer.Length) { int c = pointer[index]; if (c == '/') { break; } if (c == '~') { tilde = true; break; } ++index; } if (!tilde) { key = pointer.Substring( oldIndex, index - oldIndex); } else { index = oldIndex; var sb = new StringBuilder(); while (index < pointer.Length) { int c = pointer[index]; if (c == '/') { break; } if (c == '~') { if (index + 1 < pointer.Length) { if (pointer[index + 1] == '1') { index += 2; sb.Append('/'); continue; } else if (pointer[index + 1] == '0') { index += 2; sb.Append('~'); continue; } } throw new ArgumentException(pointer); } else { sb.Append((char)c); } ++index; } key = sb.ToString(); } if (index == pointer.Length) { return(new JSONPointer(obj, key)); } else { obj = ((CBORObject)obj)[key]; } } else { throw new KeyNotFoundException(pointer); } } }
OneKey LoadKey(CBORObject obj) { OneKey newKey = new OneKey(); CBORObject kty; switch (obj["kty"].AsString()) { case "oct": kty = GeneralValues.KeyType_Octet; break; case "EC": kty = GeneralValues.KeyType_EC; break; default: throw new Exception("Unknown key type " + obj["cty"].AsString()); } foreach (CBORObject key in obj.Keys) { CBORObject value = obj[key]; CBORObject key2 = key; if (key.AsString().EndsWith("_hex")) { value = CBORObject.FromObject(FromHex(value.AsString())); key2 = CBORObject.FromObject(key.AsString().Substring(0, key.AsString().Length - 4)); } key2 = MapKey(key2); if (key2.Equals(CoseKeyKeys.KeyType)) { value = kty; } else if (key2.Equals(CoseKeyKeys.KeyIdentifier)) { value = CBORObject.FromObject(Encoding.UTF8.GetBytes(value.AsString())); } else if (key2.Equals(CoseKeyKeys.Algorithm)) { value = MapAlgorithm(value.AsString()); } else if (kty.Equals(GeneralValues.KeyType_EC) && key2.Equals(CoseKeyParameterKeys.EC_Curve)) { switch (value.AsString()) { case "P-256": value = GeneralValues.P256; break; default: throw new Exception("Unknown curve " + value.AsString()); } } newKey.Add(key2, value); } return(newKey); }
/// <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); }
/// <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); }