O motivo do Whatsapp não fornecer dados a justiça

 

Criptografia forte e vulnerabilidades se tornaram assuntos do momento no mundo dos políticos e legisladores, mas os experts em segurança dizem que essas pessoas não entendem o problema. (link)

Com alguns meses de atraso, a discussão que vem acontecendo nos Estados Unidos desde o começo do ano chega ao Brasil: Como conciliar a segurança dos usuário da internet e ao mesmo tempo cooperar com as autoridades. Na terra do Tio Sam o caso que gerou essa polêmica foi uma disputa entre o FBI e a Apple.

FBI vs Apple Inc.

mhYai1M

 

No final de 2015, a justiça dos EUA mandou a Apple desbloquear um iPhone que estava em posse do FBI e pertencia a uma pessoa sendo investigada por terrorismo. As autoridades necessitavam do auxílio da Apple, pois os dados no telefone estavam criptografados. A Apple se negou a cumprir a ordem e entrou com um recurso.

A princípio parece ser um caso simples onde uma empresa se coloca acima da justiça, mas problemas técnicos tornam isso uma questão muito mais complicada. Para a Apple conseguir ter acesso aos dados do telefone, ela teria que investir tempo e recursos criando um sistema operacional (iOS) menos seguro – o que é ridículo, pensando que ela gastou anos desenvolvendo todas as tecnologias que protegem o dispositivo. Além disso, após ser programado, o sistema poderia ser utilizado em qualquer iPhone. Isso significa que uma pessoa em posse desse programa poderia acessar os dados de qualquer um dos 700 milhões de iPhones no mundo todo.

O FBI se comprometeu a destruir a cópia do sistema após utiliza-lo, porém o risco de vazamento (mesmo que acidentalmente) é altíssimo. Além disso, se cria um precedente para as autoridades a obrigarem uma empresa a fornecerem produtos com menor segurança para seus usuários. Um prato cheio para governos que espionam os seus cidadãos, como por exemplo, Turquia, China e Estados Unidos.

Em abril de 2016, após muita pressão social e recebendo ponderações inclusive do presidente Obama, o FBI retirou o pedido. Alguns dias depois, eles afirmaram terem conseguido desbloquear o iPhone utilizando ajuda de uma empresa de hackers. O caso foi uma demonstração de como a justiça e as autoridades de investigação não entendem como a tecnologia da informação funciona.

No ramo de segurança de informação, quando você descobre uma vulnerabilidade, você reporta para o criador do software para que ele possa corrigir e outras pessoas não fiquem em risco. O FBI não fez isso, o que mostra que eles não tem qualquer interesse na segurança dos dados dos cidadãos americanos.

O caso brasileiro

Por aqui o caso é muito similar. Um juiz de Sergipe ordenou o Whatsapp a fornecer o histórico de conversas de um usuário investigado por tráfico de drogas. A empresa afirmou não possuir essa informação e o juiz entendeu que ela está se recusando a cumprir um mandado judicial e determinou o bloqueio do acesso ao aplicativo em todo o território brasileiro. [FONTE] [FONTE]

Exatamente como nos EUA a justiça e as autoridades parecem não entender como a internet funciona. O Whatsapp utiliza uma tecnologia conhecida como criptografia ponta-a-ponta. Isso garante que as únicas pessoas com acesso ao conteúdo das mensagens são o rementente e o destinatário. Ninguém mais, nem mesmo o Whatsapp, tem acesso.

Criptografia ponta-a-ponta

A criptografia ponta-a-ponta implementada no aplicativo utiliza do conceito de criptografia assimétrica (ou criptografia de chave pública). Alguns anos atrás fiz um vídeo explicando como ela funciona quando você acessa o site do seu banco. Resumidamente, ela é composta de um par de chaves. Onde uma é mantida em segredo (chave privada) e outra é de conhecimento público (chave pública). Se uma mensagem é criptografada com uma chave, ela só pode ser aberta com a outra.

Se Bob deseja enviar uma mensagem para Alice, ele criptografa a mensagem utilizando a chave pública de Alice. Ao receber a mensagem, Alice utiliza a sua chave privada para ler o seu conteúdo. Como somente Alice tem posse da chave privada, somente ela pode ler a mensagem.

250px-Public_key_encryption.svg
Criptografia assimétrica

O termo ponta-a-ponta, significa que somente as pessoas que devem ter acesso a mensagem possuem as chaves – neste caso você e seu amigo, quando trocam mensagens pelo aplicativo. Essa tecnologia é o futuro da internet e ajuda a reduzir o roubo de informações, quebra de privacidade e vulnerabilidades em softwares.

O Whatsapp não tem e não pretende ter acesso as suas conversas. Além de qualquer mudança no software afetar usuário no mundo todo. Isso é mais do que apenas privacidade para as fofocas no grupo de família. É uma maneira de garantir que os seus dados privados estão seguros e que hackers vão ter uma grande dificuldade em comprometer dispositivos que você possui.

Obrigar uma empresa a tornar seu sistema mais vulnerável e comprometer a segurança milhões de usuários não pode ser o objetivo dos órgãos de investigação.

 


Matheus Cansian é engenheiro mecânico e atualmente trabalha com consultoria em fluidodinâmica computacional para empresas. Conheça mais as soluções CFD da Numer.

Facts about security every developer should know

This article was originally posted on Medium

Until last year I had this idea that security is not a priority when developing software (website and apps included). I mean, I’m just a small developer and probably not a lot of people will ever use what I’m creating, so why bother with security?

After reading about the subject I could understand all the risks I was taking. My goal with this post is to show some facts and motivate you to change your mentality towards security.

Note: I’m using the name hacker loosely on this post. Every time you read hacker, I really meant black hat hacker.

You are a worthwhile target

Much of this disregard with security comes from the assumption that your software or website is so unpopular that hackers will never bother trying to find a vulnerability. Nothing could be further from the truth.

You are running a web server

Your service can be worthless, but your server is not. A hacker could get access to your server for many purposes: Distributing malware, spamming, or even to join a botnet.

You are an easy target

If you are not concerned about security, an attacker don’t need to work hard to find a vulnerability. A hacker could go through a checklist of common vulnerabilities and maybe manage to gain access to your server in a matter of minutes.

Even though your service is not important, your resources are. Always think about the possible motivations for someone to hack you.

Never try to reinvent the wheel

Seriously, don’t! Experts have a hard time figuring out algorithms that you can use and safe ways of implementing it. What makes you think that you can develop something better?

You may think that as soon as the hacker doesn’t understand the implementation, you are safe. This is called “security by obscurity” and it doesn’t work. Your software should be secure even if the attacker know every detail about it. This means, your software should be secure even against you.

Let the security experts develop new ways of securing your software and only use algorithms approved by them and in a way approved by them.

Most of the times vulnerabilities are in the implementation

It’s not only about using certified algorithms. You need to use them in a certified way. Most of the times, algorithms work perfectly, but the way they are implemented, creates a vulnerability.

Recently, we all heard about the Heartbleed bug. Bottom line: There is nothing wrong with the TLS Protocol. This bug was caused by an error of implementation. A developer forgot to verify an user input, and the attacker could exploit this and steal data by overflowing a variable.

Always treat user input as unsafe and do all kind of verification. Take special care when dealing with cryptography and confidential data.

Security should be simple

Complex coding leads to implementation errors. Implementation errors lead to vulnerabilities. Security should be clean and clear.

When implementing a security feature, only add what is necessary and nothing else. When reading your code, you should be able to easily understand every bit of it.

Wrap up

Security is something that every developer should care. It doesn’t matter if your software is never going to be mainstream. Always take precautions.

To understand what should and should not be done, invest a little bit of your time studying security. If you have doubts about some implementation, there are tons of materials in the internet. After a while, you will develop a “sense of danger”. You will understand when you are writing a code that could open vulnerabilities and will then proceed with caution.

In the end you will see that if you follow good development practices, you can greatly reduce the chances of being hacked.

Ideas: Hacker simulator game mechanics

During the course of this year, I’ve been developing a game that is strongly inspired in the Introversion’s Uplink. It still doesn’t have a name, so I’m calling it Hacker Simulator.

You are a hacker in the middle of the 2020’s struggling to get rich and respected. Not much have changed in the past decade. Mobile phones are now an important part of the network, governments and companies are connected to the internet in almost all services that they provide and computers are more secure and easier to use than ever. Using online classifieds you can find opportunities to work with companies by protecting or red-team testing their server, and with individuals who are trying to get some advantage on these companies. The choice is yours!

Since this is the first post, I will try to describe a part of the game that is close to its conclusion: Game Mechanics.

Game Mechanics

The main objective of the game is to gain unauthorized access on devices. The only way to achieve this is by crafting a software that disables the device’s security for a limited amount of time. Even though, each device has different security measures, this means that every software should be crafted on a different fashion.

Software Crafting

A software is composed of a flow chart that states all actions that must be taken, in order to disable the device’s security. It should look like this:

Connect -> Disable Network Monitor -> Disable Firewall -> Break Password (Brute Force) -> Grant Access (5 min) -> Disconnect

Libraries

Each of these actions are called libraries (or libs). They are not readily available at the beginning of the game, but must be bought from online stores. I am still not sure which libs will be available, but I’m expecting to add as many as necessary to avoid the game from getting boring.

Another important thing about libs, is that you cannot run them independently. They are not software. You need to append them to other libs, using the Compiler, to be able to use its functionality.

Compiler

The Compiler is used to craft software. It consists on two panels. To craft a software you must drag elements from the right panel to the left one.

The right panel is a list of all libs that you have available on your computer and the left panel is the flow chart of your software. When you drag an element from the right panel, it automatically adds it to the bottom of the flow chart.

When everything is ready, you can hit the compile button and the compiler will generate a software that executes the actions of each lib in the specified order.

Additional information

These mechanics do not seem challenging at all, but the difficulty resides in the fact that you don’t always know what kind security the device is running (hence you cannot predict which libraries use) and these softwares have a limited amount of time they can stay connected to the server (so you cannot just put everything on a software and use it all the time).

In the future, I will probably write about Probing, which is the technique that you use to gather information on which security the device is using.

A* pathfinding usando navmesh

Estou escrevendo este post pois é um tanto quanto difícil encontrar materiais sobre A* com navmesh. A maioria dos artigos na web são e inglês e descrevem a rotina de uma forma bem genérica e qualitativa. O objetivo deste post é facilitar um pouco a vida dos programadores de jogos que não falam inglês ou que tem uma certa dificuldade com as explicações genéricas da maior parte dos artigos na internet.

Neste post vou descrever passo a passo como funciona a rotina de um A* quando trabalhamos com navmeshes. Para entender o conceito é necessário que você já esteja familiarizado com o A* para grids. Caso ainda não tenha total compreendimento do A*, por favor, leia este artigo para iniciantes antes de continuar. Nas partes com código vou utilizar a linguagem Blitz3D a qual tem uma sintaxe derivada do basic e portanto é de fácil entendimento. De qualquer forma, você pode programar o seu algorítimo na linguagem que preferir.

Antes de começar você já deve ter os seus navmeshes mapeados. Eles podem ser qualquer polígono, com a única condição de ser obrigatoriamente convexo. Eu recomendo fortemente que se utilize triângulos. Apesar de não ser a forma mais rápida de rodar, é de fato, a forma mais fácil de programar. Neste tutorial eu vou utilizar este método. Você pode mapeá-los de inúmeras formas, desde a simplicidade de fazer isso a mão ou criar algorítimos sofisticados para mapear automaticamente (pretendo escrever sobre isso mais tarde). O importante neste tutorial é que a estrutura dos seus navmeshes contenha as posições das três vértices que compõem cada triângulo do seu navmesh. Em B3D você pode guardar esse dados facilmente desta forma:

 Type Triangulo
…….Field Vertice1X#, Vertice1Y
…….Field Vertice2X#, Vertice2Y
…….Field Vertice3X#, Vertice3Y#
End Type
(obs: você pode utilizar BlitzArrays se preferir)

Com todos os triângulos mapeados é hora de abordar o problema. Podemos explicar a problemática através da seguinte imagem:

Seu NavMesh com um ponto inicial e um ponto final

Seu objetivo aqui é simples: Conseguir encontrar o caminho mais curto do ponto inicial até o ponto final, de forma que, o caminho só seja válido se estiver dentro do NavMesh. Para isso, vamos dar uma olhada mais próxima dos pontos inicial e final.

A probabilidade do início ou fim do caminho estarem exatamente sobre a vértice de algum triângulo é praticamente nula. Por este motivo, nós temos que ter uma rotina para descobrir em qual triângulo cada pontos está situado.

Um método fácil é criar uma função chamada PontoEstaNoTriangulo( args ). Você fornece a esta função as coordenadas das três vértices do triângulo juntamente com a coordenada do ponto em questão. Esta função deverá retornar VERDADEIRO se o ponto estiver dentro do triângulo e FALSO caso não esteja. Existe uma maneira bem simples e barata (em termos de processamento) de fazer isso. Utiliza-se produtos vetoriais para verificar se o ponto está dentro da geometria ou não. Este algorítimo está descrito neste artigo (em inglês). Caso não consiga entender o método, por favor, deixe um comentário no post que posso explicar mais detalhadamente. Há outra maneira de realizar está tarefa. Ela envolve calcular a área de alguns triângulos criados por estas vértices e compara-las. Eu fortemente desaconselho está opção. Pode parecer uma solução fácil, mas ela é muito cara em termos de processamento e o limite de casa decimais da variável utilizada pode levar a resultados incorretos. Utilize o algorítimo sugerido acima.

Com a sua função escrita, o que você precisa fazer é testar o ponto de início e o ponto de final com todos os triângulos do seu navmesh até encontrar a quais triângulos eles estão situados. A primeira vista pode parecer uma tarefa pesada de se calcular, no entanto ela só é realizada uma vez durante todo o calculo do caminho. Depois desta analise você pode ter três tipos de resultados e é importante analisar o significado de cada um deles.

  1. Ambos os pontos estão situados no mesmo triângulo
    Este resultado quer dizer que é possível ir em linha reta do ponto inicial ao final (o que com certeza é o menor caminho entre eles). Neste caso você não precisa calcular um caminho e sim apenas retornar uma linha reta como resultado.
  2. Para um ou ambos os pontos não foi encontrado um triângulo
    Isso significa que um ou ambos os pontos estão fora do navmesh. Minha solução neste caso é simplesmente abortar o cálculo e não retornar nenhum caminho. Entretanto, você pode fazer alguma função para lidar com erro como esse (por exemplo: um caminho em linha reta até o navmesh mais próximo e depois calcular o caminho normalmente).
  3. Os pontos estão em triângulo diferentes
    Neste caso você deve calcular o caminho utilizando a metodologia abaixo.

 

Voila! Você encontrou o triângulo do ponto inicial

Sabendo em qual triângulo seu ponto inicial está localizado, você pode adicionado a lista fechada e colocar todos os pontos adjacentes a ele (vértices do triângulo) na lista aberta. Lembre-se de colocar o ponto inicial como pai das vértices na lista aberta. Fazendo este procedimento, você chegará a algo assim:

Pontos adjacentes ao ponto inicial

Para cada ponto enviado para a lista aberta, calcule o custo G e H dele. Você pode encontrar na internet várias formas de calcula-los. Neste caso vou utilizar a distância euclidiana (em linha reta) do ponto até o ponto inicial como o custo G e a distância euclidiana do ponto até o ponto final como custo H. Com certeza não é a melhor solução, mas funciona! Após realizado os cálculos, encontre o ponto que contém o menor valor de F, onde F = G + H.

Para o ponto encontrado repita o procedimento anterior (enviar para a lista fechada, enviar para a lista aberta os pontos adjacentes, calcular os valores de G e H e encontrar o ponto com o menor F). A única questão de atenção aqui é em colocar uma condição para os pontos na lista fechada nunca serem enviados para a lista aberta. Eles já foram analisados e não precisamos analisá-los novamente.

Caso algum ponto que você esteja tentando enviar para a lista aberta já estiver lá, apenas cacule novamente o valor  do custo G. Caso ele seja menor do que o custo atual, substitua na lista. Dica: Na hora de calcular o custo G, não se esqueça que ele é a soma da distância do ponto inicial até a vértice 2 mais a distância da vértice 2 até a vértice a ser calculada.

Pontos adjacentes a vértice 2

Repetindo o processo você saberá que terminou quando você adicionar a lista fechada qualquer uma das vértices do triângulo que contém o ponto final. Quando você chegar nesta situação o seu próximo caminho é apenas uma linha reta da vértice adicionada até o ponto final.

Último ponto calculado

Exatamente como fazemos no algorítimo para grids, devemos realizar uma backtracking  para descobrir o caminho até o ponto. Isso é realizado começando do ponto final e voltando (através dos pontos pais) até o ponto inicial. Depois disso é só retornar o caminho encontrado para o personagem seguir.

Caminho final e backtracking

Você provavelmente irá notar que este algorítimo retorna um caminho encostado as paredes. Este é um fenômeno natural dos navmeshes. Para conserta-lo você pode criar uma outra análise após o caminho ser gerado que faz o seguinte:

Se é possivel ir em linha reta do ponto 1 até o ponto 3. Então, deletar o ponto 2 (pois é inútil).

Utilizando a lógica acima, você terá o caminho mais curto do ponto inicial ao final. Entretanto, isso ainda parece um pouco robótico. Se quiser simular caminhos que pareçam mais humanos, sugiro a leitura do seguinte artigo The AI Systems of Left 4 Dead (em inglês) escrito pelo Michael Booth, onde ele descreve como foram criados alguns dos sistemas de inteligência artificial do Left 4 Dead.

Caminho gerado sem nenhuma otimização

Ficamos por aqui pessoal! Caso ainda tenha alguma duvida, deixe um comentário abaixo que irei responder assim que possível.

Referências

A* pathfinding using navmesh

I wrote this post because it’s really hard to find detailed material about A* with NavMesh, and also most of A* tutorials present either the grid-based algorithm or some vague reference to navmesh. My goal with this post is to provide some clean, ready-to-use information which AI game programmers can use to enhance their pathfinding algorithms.

In this post I will describe step-by-step how to implement a navmesh oriented pathfinding in your game. To understand this concept it’s mandatory that you feel comfortable with the grid-based A* algorithm. If you don`t fully understand the concept of A*, please take your time to read this article for beginners. Also, keep in your mind that when a reference to some code appears here, it will be in Blitz3D. This language is designed for game developing and it’s my favorite for prototyping. It’s also derived from basic so it’s pretty easy to understand.

Before you start, you need to create your navmesh. It can be made of anything, from triangles to polygons. The only constrain is that each individual polygon must be convex. This is useful because it guarantees that any straight line inside a single node is a valid path. Some AAA games (Valve) use rectangles as navmesh node. There are some increased speed with this approach, but I recommend that you (at least for now) stick with triangles. Might not be the most speed-friendly way but it is, by far, the easiest to code.

There are several ways to create your navmesh map, you can try doing it manually or using algorithms that calculate them dynamically (which I intend to explain in some later post) . The important part is that the position of each triangle vertices are mapped. To store you navmesh map you can code a structure just like this:

Type Triangle
…….Field Vertex1X#,  Vertex1Y#
…….Field Vertex2X#,  Vertex2Y#
…….Field Vertex3X#, Vertex3Y#
End Type

With all of your polygons mapped, it’s time to make it work! An example of the problematic could be illustrated by the following example:

A NavMesh and two (Starting and Ending) points

Objective: You need to find the shortest path from START to END, making sure that this path is inside the navmesh.
To achieve this, let’s take a closer look at our starting and ending points.

Normally, your starting/ending point is not on any vertex. So we need to find out in which triangle it is situated.  An easy method to do this is to call a function PointInsideTriangle(args). We provide this function with the triangle vertices and a point and it should returns true if the point is inside the triangle or false otherwise. There are several ways to code this, my favorite one works with cross products. This matematical approach is fast and reliable. Its algorithm is described on this website. There is in fact another way of doing the same thing. It involves computing some triangle areas and comparing them. Though this approach sounds easier, I strongly discourage you from using it. It’s very computing-intensive and the variable decimal precision can lead to errors. Instead use the algorithm described on the website above.

Now that we have you function coded, we must check our starting and ending point against all triangles into the navmesh until we find where they are located. It may sound like a very computing-intensive operation O(n), and sure it is! The good news is that we only need to calculate this once for the entire path. After this analysis you can come up with any of those 3 results. It’s important to handle them carefully.

  1. Both point are located on the same triangle
    Good news! This means that we can use a straight line as our path and for sure this is the shortest way. No further intensive calculations necessary.
  2. One or both points are outside all triangles
    This means that one or both points are outside your navmesh. On this situation I would probably stop this path calculation and return just a null path. But it’s up to you! You can make a code to handle this kind of error.
  3. Both points are located on different triangles
    This means that we should proceed with our path calculation.
Voila! You found the first triangle!

Now that you know on which triangle your starting point is located you can add this point to the closed list and send all the adjacent points to the open list (and keep a record of its parent point – in this case the starting point). The adjacent points in this case are all the triangle vertices. By doing it you will get this:

Adjacent points of the starting point

For each point, calculate the G and H cost. You can find a lot of ways to calculate this on the internet, or just use the distance between the last point (starting point) and the vertex for G and the distance between the vertex and the ending point for H. It`s not the best coefficient but works! After you are done, selected the point with lower F cost (F = G + H).

Adjacent points of V2

Repeat the same process with this point (send its adjacent points to the open list and add the point to the closed list). If any point that you are trying to send to the open list is already there: Just check if the G cost from this new path is better than the former, if true, then change the G cost, and the point parent. Also, when calculating the G cost, remember that it is the G cost to the point V2 plus the Distance between V2 and the point you are calculating.

Last point

You know you are finished, the time that you add to the closed list one of the vertices of the triangle that contains the ending point. To check this, you can find the 3 vertices of the ending triangle and check every time you add a point to the closed list.
When you find this vertex, your next point is just a straight line to the ending point, since you have a convex navmesh and you can draw a straight line between any 2 points inside it.

Backtracking

Just like the algorithm for grids, backtrack  your way to the starting point (using the parent points you recorded) and you will find you path.

You will notice that this algorithm provides a wall-hugging path, since it use the vertices to generate the path. You can fix this by deleting useless points (if you can go from A directly to C without falling off the NavMesh, then the point B is useless and you can delete it).

The next step is to implement it on your game! 

Source code (Blitz3D)

  1. https://github.com/mscansian/b3d-binaryheaps
  2. https://github.com/mscansian/b3d-astar-pathfinding

Navmesh creator

Yesterday I started to wonder how difficult was to implement a A* with NavMesh system. So I started working, first in a NavMesh creator, then in the A* system itself.

My NavMesh Creator loading maps with the PX_MAP (an API to load Valve Hammer `s .map files), and PX_GUI for the menus. The result is shown below:

NavMesh Generator: First Screen
Adding a triangular mesh
Paths
Paths
Same image, but showing the NavMesh only

The concept of this generator is simple: A 3d pointer is inside the world and always attached to a surface. You move this pointer with your mouse and click to add a vertice on its location, and repeat the process. When you have added 3 vertices, the software creates a triangular mesh and store its vertices. Than you keep add new meshes, with the already placed vertices or placing new ones.

Using this application I could create .nav files. This file stores the vertices of every NavMesh in the world, and I use then for the next step: Building an A* Pathfinding.

You can download the NavMeshGenerator 1.0 and its source code.

Showcasing A* with navmesh

If you are looking for a detailed article about how to write your own navmesh pathfinder, click here

In the first post I showed my NavMesh Generator. Now it`s time to wrap everything up and build the pathfinding system.

First, I used a piece of code from the generator to load the map and the NavMesh into my world. Then I worked with some keys functions like:

  • OpenAdjacentPoints – You provide a particular point, and this function send to Open List all the points that are adjacent (can be travelled in a straight line). For example: If you provide a point that is the vertice of a triangle, it returns the next 2 vertices; or if you provide a point that is inside a triangle, it returns all of its vertices.
  • FindTriangle – You provide a point, and this function return the mesh (triangle) that contains this point. Useful for the starting and ending point of your pathfinding, since they are mostly inside a triangule and not on its vertices.
  • CanSeeEachOther – You provide 2 points and the function return true if this points can be connected by a straight line without falling off the NavMesh, or false otherwise.

With those function, it was pretty easy to implement the algorithm. Just send the first point to the Closed List and all his adjacents to the Open List, then select the point with lower f and send his adjacents to the open list, and so on.

Since I used only the vertices of the triangles to generate the path, my path was looking like a wall-hugging. To overcome this obstacle, I just implemented a kind of path optimization. For instance: If you path has 3 points (A, B and C), the algorithm check if you can go from point A directly to point C, without falling off the NavMesh (using the CanSeeEachOther function). If you can, then delete the point B (because it`s useless).

Unfortunately, my function CanSeeEachOther still doesen`t work 100% times. So, while I`m trying to fix it, I will not post the source code of the pathfinding.

Here are some screenshots:

NavMesh without Path-optimization
NavMesh without Path-optimization
NavMesh with Path-optimization - You can see my optimization is not so smart