public OscoreEvent(EventCode code, byte[] groupIdentifier, byte[] keyIdentifier, SecurityContext context, SecurityContext.EntityContext recipient) { Code = code; GroupIdentifier = groupIdentifier; KeyIdentifier = keyIdentifier; SecurityContext = context; RecipientContext = recipient; }
/// <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) { 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 Exception("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 Exception("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(CBORObject.Null); // 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 Exception("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 Exception("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); }