예제 #1
0
        /// <param name="receivedFromUser">comes from local contact book</param>
        internal static InviteSessionDescription Decrypt_Verify(ICryptoLibrary cryptoLibrary, byte[] encryptedSdData,
                                                                InviteRequestPacket req,
                                                                InviteAck1Packet ack1,
                                                                bool ack1SdIsReady,
                                                                InviteSession session,
                                                                UserId receivedFromUser,
                                                                DateTime localTimeNowUtc
                                                                )
        {
            #region key, iv
            PacketProcedures.CreateBinaryWriter(out var ms2, out var w2);
            req.GetSharedSignedFields(w2);
            ack1.GetSharedSignedFields(w2, ack1SdIsReady);
            var iv = cryptoLibrary.GetHashSHA256(ms2.ToArray()).Take(16).ToArray();
            ms2.Write(session.SharedInviteAckDhSecret, 0, session.SharedInviteAckDhSecret.Length);
            var aesKey = cryptoLibrary.GetHashSHA256(ms2.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp
            #endregion

            // decrypt
            var plainTextSdData = new byte[encryptedSdData.Length];
            cryptoLibrary.ProcessAesCbcBlocks(false, aesKey, iv, encryptedSdData, plainTextSdData);

            var r      = new InviteSessionDescription();
            var reader = PacketProcedures.CreateBinaryReader(plainTextSdData, 0);
            r.Flags = reader.ReadByte();
            if ((r.Flags & FlagsMask_MustBeZero) != 0)
            {
                throw new NotImplementedException();
            }
            r.UserCertificate          = UserCertificate.Decode_AssertIsValidNow(reader, cryptoLibrary, receivedFromUser, localTimeNowUtc);
            r.DirectChannelEndPoint    = PacketProcedures.DecodeIPEndPoint(reader);
            r.DirectChannelToken32     = DirectChannelToken32.Decode(reader);
            r.SessionType              = (SessionType)reader.ReadByte();
            r.UserCertificateSignature = UserCertificateSignature.DecodeAndVerify(reader, cryptoLibrary,
                                                                                  w =>
            {
                req.GetSharedSignedFields(w);
                ack1.GetSharedSignedFields(w, ack1SdIsReady);
                r.WriteSignedFields(w);
            },
                                                                                  r.UserCertificate);
            return(r);
        }
예제 #2
0
        /// <summary>
        /// initializes parameters to transmit direct (p2p) packets form requester A to neighbor N
        /// </summary>
        public void Decrypt_ack1_ToResponderTxParametersEncrypted_AtRequester_DeriveSharedDhSecret(Logger logger, RegisterRequestPacket req, RegisterAck1Packet ack1)
        {
            SharedDhSecret = _engine.CryptoLibrary.DeriveEcdh25519SharedSecret(LocalEcdhe25519PrivateKey, ack1.ResponderEcdhePublicKey.Ecdh25519PublicKey);

            #region iv, key
            PacketProcedures.CreateBinaryWriter(out var ms, out var writer);
            req.GetSharedSignedFields(writer, true);
            ack1.GetSharedSignedFields(writer, false, false);

            var iv = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()).Take(16).ToArray();

            ms.Write(SharedDhSecret, 0, SharedDhSecret.Length);
            var aesKey = _engine.CryptoLibrary.GetHashSHA256(ms.ToArray()); // here SHA256 is used as KDF, together with common fields from packets, including both ECDH public keys and timestamp
            #endregion


            var toNeighborTxParametersDecrypted = new byte[ack1.ToResponderTxParametersEncrypted.Length];
            _engine.CryptoLibrary.ProcessAesCbcBlocks(false, aesKey, iv, ack1.ToResponderTxParametersEncrypted, toNeighborTxParametersDecrypted);

            // parse toNeighborTxParametersDecrypted
            using (var reader = new BinaryReader(new MemoryStream(toNeighborTxParametersDecrypted)))
            {
                RemoteEndpoint        = PacketProcedures.DecodeIPEndPoint(reader);
                RemoteNeighborToken32 = NeighborToken32.Decode(reader);
                var magic16 = reader.ReadUInt16();
                if (magic16 != Magic16_responderToRequester)
                {
                    throw new BrokenCipherException();
                }
            }

            if (logger.WriteToLog_detail_enabled)
            {
                if (logger.WriteToLog_detail_enabled)
                {
                    logger.WriteToLog_detail($"decrypted remote responder endpoint={RemoteEndpoint}, remoteNeighborToken={RemoteNeighborToken32} from ACK1");
                }
            }
        }
예제 #3
0
        /// <summary>
        /// when REQ is received from neighbor, verifies senderHMAC and NeighborToken32
        /// </summary>
        /// <param name="receivedFromNeighborNullable">is NULL when decoding REQ from A at EP</param>
        public static RegisterRequestPacket Decode_OptionallyVerifyNeighborHMAC(byte[] udpData, ConnectionToNeighbor receivedFromNeighborNullable, int numberOfDimensions)
        {
            var r = new RegisterRequestPacket();

            r.DecodedUdpPayloadData = udpData;
            var reader = PacketProcedures.CreateBinaryReader(udpData, 1);

            var flags = reader.ReadByte();

            if ((flags & FlagsMask_MustBeZero) != 0)
            {
                throw new NotImplementedException();
            }
            if ((flags & Flag_AtoEP) == 0)
            {
                if (receivedFromNeighborNullable == null)
                {
                    throw new UnmatchedFieldsException();
                }
                r.NeighborToken32 = NeighborToken32.Decode(reader);
                if (receivedFromNeighborNullable.LocalNeighborToken32.Equals(r.NeighborToken32) == false)
                {
                    throw new UnmatchedFieldsException();
                }
            }
            else
            {
                if (receivedFromNeighborNullable != null)
                {
                    throw new UnmatchedFieldsException();
                }
            }

            r.RequesterRegistrationId         = RegistrationId.Decode(reader);
            r.RequesterNeighborsBusySectorIds = reader.ReadUInt16();
            r.RequesterEcdhePublicKey         = EcdhPublicKey.Decode(reader);
            r.ReqTimestamp64            = reader.ReadInt64();
            r.MinimalDistanceToNeighbor = reader.ReadUInt32();

            if ((flags & Flag_DirectionVectorExists) != 0)
            {
                r.DirectionVectorNullable = new sbyte[numberOfDimensions];
                for (int i = 0; i < numberOfDimensions; i++)
                {
                    r.DirectionVectorNullable[i] = reader.ReadSByte();
                }
            }

            r.EpEndpoint         = PacketProcedures.DecodeIPEndPoint(reader);
            r.RequesterSignature = RegistrationSignature.Decode(reader);

            if ((flags & Flag_AtoEP) != 0)
            {
                r.ProofOfWork2 = reader.ReadBytes(64);
            }
            r.NumberOfHopsRemaining       = reader.ReadByte();
            r.NumberOfRandomHopsRemaining = reader.ReadByte();
            r.ReqP2pSeq16 = RequestP2pSequenceNumber16.Decode(reader);
            if ((flags & Flag_AtoEP) == 0)
            {
                r.NeighborHMAC = HMAC.Decode(reader);
                if (r.NeighborHMAC.Equals(receivedFromNeighborNullable.GetNeighborHMAC(r.GetSignedFieldsForNeighborHMAC)) == false)
                {
                    throw new BadSignatureException("invalid REGISTER REQ NeighborHMAC 1573");
                }
            }

            return(r);
        }
예제 #4
0
        /// <summary>
        /// decodes the packet, decrypts ToNeighborTxParametersEncrypted, verifies NeighborSignature, verifies match to register REQ
        /// </summary>
        /// <param name="newConnectionToNeighborAtRequesterNullable">if not null (at requester) - this procedure verifies ResponderSignature</param>
        /// <param name="reader">is positioned after first byte = packet type</param>
        public static RegisterAck1Packet DecodeAndOptionallyVerify(Logger logger, byte[] ack1UdpData, RegisterRequestPacket reqNullable,
                                                                   ConnectionToNeighbor newConnectionToNeighborAtRequesterNullable)
        {
            var reader = PacketProcedures.CreateBinaryReader(ack1UdpData, 1);
            var ack1   = new RegisterAck1Packet();

            ack1.DecodedUdpPayloadData = ack1UdpData;
            ack1.Flags = reader.ReadByte();
            if ((ack1.Flags & Flag_EPtoA) == 0)
            {
                ack1.NeighborToken32 = NeighborToken32.Decode(reader);
            }
            if ((ack1.Flags & FlagsMask_MustBeZero) != 0)
            {
                throw new NotImplementedException();
            }
            ack1.RequesterRegistrationId          = RegistrationId.Decode(reader);
            ack1.ReqTimestamp64                   = reader.ReadInt64();
            ack1.ResponderEcdhePublicKey          = EcdhPublicKey.Decode(reader);
            ack1.ToResponderTxParametersEncrypted = reader.ReadBytes(ToResponderTxParametersEncryptedLength);
            ack1.ResponderRegistrationId          = RegistrationId.Decode(reader);

            if (newConnectionToNeighborAtRequesterNullable != null)
            {
                if (reqNullable == null)
                {
                    throw new ArgumentException();
                }
                ack1.ResponderSignature = RegistrationSignature.DecodeAndVerify(
                    reader, newConnectionToNeighborAtRequesterNullable.Engine.CryptoLibrary,
                    w =>
                {
                    reqNullable.GetSharedSignedFields(w, true);
                    ack1.GetSharedSignedFields(w, false, true);
                },
                    ack1.ResponderRegistrationId);
            }
            else
            { // at proxy we don't verify responder's signature, to avoid high spending of resources
                ack1.ResponderSignature = RegistrationSignature.Decode(reader);
            }

            if (reqNullable != null)
            {
                ack1.AssertMatchToRegisterReq(reqNullable);
                if (newConnectionToNeighborAtRequesterNullable != null)
                {
                    newConnectionToNeighborAtRequesterNullable.Decrypt_ack1_ToResponderTxParametersEncrypted_AtRequester_DeriveSharedDhSecret(logger, reqNullable, ack1);
                }
            }

            if ((ack1.Flags & Flag_EPtoA) != 0)
            {
                ack1.RequesterEndpoint = PacketProcedures.DecodeIPEndPoint(reader);
            }
            else
            {
                ack1.ReqP2pSeq16  = RequestP2pSequenceNumber16.Decode(reader);
                ack1.NeighborHMAC = HMAC.Decode(reader);
            }

            return(ack1);
        }