“Bajo toda arquitectura de información se esconde una estructura de poder” (eslogan ciberpunk).

En sus primeros años de existencia, Internet (su predesora ARPANET) era una red descentralizada de ordenadores que parecía autorregularse por sí misma y en la que gobiernos y corporaciones no tenían cabida (Declaración de independencia del ciberespacio). Hoy en día la situación es muy diferente, y está lejos de ser esa utopía de un Internet libre, hoy en día depende en gran medida de servidores en manos de organizaciones gubernamentales, proveedores de acceso a la red y grandes corporaciones de telecomunicaciones.

El concepto de “descentralización” se escuchó por primera vez nada menos que a mediados del siglo XIX, cuando se hablaba de él como la fuerza que inspiró la Revolución Francesa:

“La descentralización tiene, no solo un valor administrativo, sino también una dimensión cívica, ya que aumenta las oportunidades para que los ciudadanos se interesen en los asuntos públicos, los hace acostumbrarse a usar la libertad. Estas libertades locales, activas y persistentes, nacen como el contrapeso más eficiente contra los reclamos del gobierno central, incluso si estuvieran respaldados por una voluntad colectiva e impersonal” (Alexis de Tocqueville).

La topología de una red por tanto tiene profundas implicaciones en términos de libertad. la infraestructuras digitales determinan como la información puede fluir por sus conexiones entre nodos.

“The Internet treats censorship as a malfunction and routes around it”John Perry Barlow.

El propio Tim Berners-Lee creador de la World Wide Web (basada en el protocolo HTTP) ha puesto en marcha Solid, un proyecto de Internet descentralizado, en el que los usuarios tengan control de sus datos.

Existe también una versión de la Wikipedia en turco usando IPFS para resistir a la posible censura del gobierno, se puede ampliar la información sobre este caso en el artículo “Wikipedia blocked in Turkey”, uno de los objetivos del proyecto IPFS es asegurar el acceso a la información para toda la humanidad (“Uncensorable Wikipedia on IPFS”).

IPFS - InterPlanetary File System

Hace años lei varios artículos sobre IPFS (InterPlanetary File System), me pareció una idea interesante pero adolecía de algunos problemas inherentes a su propio funcionamiento, durante el Hackmeeting del 2019 acudí a un nodo llamado “Cómo montar una web con IPFS” con el propósito de conocer como ha evolucionado y si goza de buena salud.

IPFS es en pocas palabras es un protocolo y una red P2P (peer-to-peer) descentralizada y direccionable por contenido gracias a una función hash (frente a las clásicos enlaces que apuntan a un sitio) para almacenar y compartir información basado en un sistema de archivos distribuidos, el proyecto es de código abierto. En términos sencillos es como un sistema BitTorrent que intercambia objetos Git.

Algunas de sus principales características y potenciales son evidentes, la Web actual se basa en un modelo cliente-servidor, se puede considerar ineficiente ya que múltiples clientes acceden al mismo servidor pudiendo ocasionar problemas de rendimiento o incluso el contenido puede quedar inaccesible si el servidor central cae, la centralización de servidores y proveedores de servicios puede conducir a un mayor control y censura de la información que circula en la red. Esta arquitectura es además susceptible de sufrir ataques DDoS.

En un modelo descentralizado y con la información distribuida se puede obtener porciones de información de múltiples computadoras de forma simultanea. Garantiza la igualdad de acceso a la información en cualquier lugar del mundo.

La resiliencia es la capacidad de un sistema tecnológico de soportar y recuperarse ante desastres y perturbaciones, se estima que la duración media de vida de una Web pueden ser 100 días, transcurrido ese tiempo podemos esperar recibir el famoso mensaje de error HTTP 404, la Web que conocemos es muy frágil, los enlaces dejan de funcionar continuamente, con los contenidos propagados en espejo con IPFS se crean redes resilientes.

Descarga e instalación

$ wget https://dist.ipfs.io/go-ipfs/v0.4.22/go-ipfs_v0.4.22_linux-amd64.tar.gz
$ tar xvfz go-ipfs_v0.4.22_linux-amd64.tar.gz
$ cd go-ipfs
$ ./install.sh

El último comando mueve la aplicación “ipfs” a “/usr/local/bin”.

Ahora iniciamos nuestro nodo IPFS con ipfs init, este comando sólo es necesario ejecutarlo una vez para obtener el par de claves RSA de 2048 bits para asociarlo a nuestro peer (el mio con ID “QmRqbhErGt2vBCjcdtfJTGdkHUULxpvL9nVmXaHvBNFQAZ”) y el fichero de configuración en la ruta de instalación del usuario “/root/.ipfs/config”.

$ ipfs init
initializing IPFS node at /root/.ipfs
generating 2048-bit RSA keypair...done
peer identity: QmRqbhErGt2vBCjcdtfJTGdkHUULxpvL9nVmXaHvBNFQAZ
to get started, enter:

	ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme

El comando ipfs cat muestra el contenido de un objeto IPFS o IPNS, en este caso un fichero readme que viene con la instalación.

$ ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/readme
Hello and Welcome to IPFS!

██╗██████╗ ███████╗███████╗
██║██╔══██╗██╔════╝██╔════╝
██║██████╔╝█████╗  ███████╗
██║██╔═══╝ ██╔══╝  ╚════██║
██║██║     ██║     ███████║
╚═╝╚═╝     ╚═╝     ╚══════╝

If you're seeing this, you have successfully installed
IPFS and are now interfacing with the ipfs merkledag!

 -------------------------------------------------------
| Warning:                                              |
|   This is alpha software. Use at your own discretion! |
|   Much is missing or lacking polish. There are bugs.  |
|   Not yet secure. Read the security notes for more.   |
 -------------------------------------------------------

Check out some of the other files in this directory:

  ./about
  ./help
  ./quick-start     <-- usage examples
  ./readme          <-- this file
  ./security-notes

Para iniciarnos rápidamente podemos ejecutar ipfs cat /ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/quick-start desde la línea de comandos o abrir en el navegador http://localhost:8080/ipfs/QmS4ustL54uo8FzR9455qaxZwuMiUhyvMcX9Ba8nUH4uVv/quick-start.

Para obtener más ayuda se puede usar el comando ipfs help.

Si te preguntas como funciona una red P2P este hilo de Twitter sobre libp2p (sobre la que se apoya IPFS) es interesante.

Cifrado RSA para identificar los nodos en IPFS

RSA (Rivest, Shamir y Adleman) es un sistema criptográfico de clave pública, cada usuario posee dos claves de cifrado: una pública y otra privada, para cifrar el mensaje el emisor usa la clave pública del receptor y una vez que este recibe el mensaje la descifra usando su clave privada. Sería análogo a un buzón de correos, donde todo el mundo puede meter información dentro, pero solamente el dueño puede abrirlo con su llave eliminando la necesidad enviar la clave al destinatario (cifrado simétrico). RSA se basa en la factorización (descomposición de un numero en forma de producto de otros dos) de dos números primos, por poner un ejemplo sencillo el número 15 es el producto de los primos 3*5, pero cuando hablamos de números grandes se convierte en una tarea ardua de computar (hasta que lleguen los ordenadores cuánticos).

Existen muchas Webs que permiten generar pares de claves RSA de 2048 bytes de longitud, este enlace es un buen ejemplo.

En Linux podemos crear un par de claves RSA con el comando ssh-keygen:

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): my-rsa-keys
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in my-rsa-keys.
Your public key has been saved in my-rsa-keys.pub.
The key fingerprint is:
SHA256:N6ys/Cbkg3cxMzN85XLNKLX8q6vVLIabY+WVjENttYs root@diablo
The key's randomart image is:
+---[RSA 2048]----+
|                 |
|                .|
|             . ..|
|         .  + o. |
|       .S +* O...|
|      ..Oo+oXE*. |
|     +  oO.*++o  |
|    ..=.o o=...  |
|     .o*..+ooo.. |
+----[SHA256]-----+

El resultado son dos ficheros, my-rsa-keys con la clave privada y my-rsa-keys.pub con la clave pública.

El ID de un nodo en IPFS es la clave pública y permite que los nodos se busquen, se autentiquen y se comuniquen entre si usando el cifrado RSA.

Este vídeo explica bien como funciona la encriptación de clave pública.

Arrancando el servidor

$ ipfs daemon
Initializing daemon...
go-ipfs version: 0.4.22-
Repo version: 7
System version: amd64/linux
Golang version: go1.12.7
Swarm listening on /ip4/127.0.0.1/tcp/4001
Swarm listening on /ip4/172.17.0.1/tcp/4001
Swarm listening on /ip4/192.168.221.103/tcp/4001
Swarm listening on /ip6/::1/tcp/4001
Swarm listening on /p2p-circuit
Swarm announcing /ip4/127.0.0.1/tcp/4001
Swarm announcing /ip4/172.17.0.1/tcp/4001
Swarm announcing /ip4/192.168.221.103/tcp/4001
Swarm announcing /ip6/::1/tcp/4001
API server listening on /ip4/127.0.0.1/tcp/5001
WebUI: http://127.0.0.1:5001/webui
Gateway (readonly) server listening on /ip4/127.0.0.1/tcp/8080
Daemon is ready

En la URL http://127.0.0.1:5001/webui podemos administrar nuestro nodo recién creado.

¿Cómo se almacenan los archivos en IPFS?

Ahora voy a subir un archivo, creo un fichero de texto cualquiera y uso el comando ipfs add que retorna un hash único:

$ echo "hello world!" > hello_world.txt
$ ipfs add hello_world.txt 
added QmeV1kwh3333bsnT6YRfdCRrSgUPngKmAhhTa4RrqYPbKT hello_world.txt
 13 B / 13 B [=======================================================================================================================] 100.00%

Se puede leer el contenido del fichero con el hash con el comando ipfs cat o usando el navegador con http://localhost:8080/ipfs/QmeV1kwh3333bsnT6YRfdCRrSgUPngKmAhhTa4RrqYPbKT:

$ ipfs cat  QmeV1kwh3333bsnT6YRfdCRrSgUPngKmAhhTa4RrqYPbKT
hello world!

Funciones hash y CID (content identifier)

Una función hash (en inglés “picadillo”) recibe un conjunto de datos, aplica un algoritmo matemático y los convierte en una codificación de longitud fija independientemente del tamaño de los datos de entrada (se llama colisión cuando dos entradas distintas generan la misma salida), es muy usado por ejemplo para almacenar una contraseña de acceso de un usuario en una base de datos, cuando el usuario se autentica se pasa su clave por un algoritmo hash como SHA y se compara con el almacenado en la base de datos (esta es la razón por la cual estos servicios no pueden devolverte la contraseña olvidada, porque no la tienen), otro ejemplo típico son archivos subidos a Internet que vienen acompañados de un fichero con el hash MD5 (de 128 bits representada típicamente como un número de 32 símbolos hexadecimales), en este caso se trata de comprobar que el archivo no ha sido alterado cuando lo descargamos a nuestro disco local. Las distribuciones base de Linux suelen traer el comando md5sum con este propósito:

$ cat hello_world.txt 
hello world!

$ md5sum hello_world.txt 
c897d1410af8f2c74fba11b1db511e9e  hello_world.txt

Los hash criptográficos tienen algunas características importantes:

  • Son deterministas - la misma entrada siempre genera el mismo hash de salida.
  • No correlacionado - cualquier cambio en el mensaje genera un hash completamente diferente.
  • Único - Es inviable generar el mismo hash de dos mensajes diferentes.
  • De un sólo sentido - Es prácticamente imposible obtener el conjunto de datos a partir del hash.

En este enlace se pueden probar varios tipos de generadores hash.

Volviendo a IPFS la función hash se usa para identificar el contenido (CID o content identifier), IPFS usa SHA2-256 como hash.

Si cambio el contenido obtengo un valor hash diferente:

$ echo "version 1 of my text" | ipfs add
added QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy QmZtmD2qt6fJot32nabSP3CUjicnypEBz7bHVDhPQt9aAy
 21 B / 21 B [=======================================================================================================================] 100.00%
$ echo "version 2 of my text" | ipfs add
added QmTudJSaoKxtbEnTddJ9vh8hbN84ZLVvD5pNpUaSbxwGoa QmTudJSaoKxtbEnTddJ9vh8hbN84ZLVvD5pNpUaSbxwGoa
 21 B / 21 B [=======================================================================================================================] 100.00

Los hash generados con IPFS siempre empiezan con “Qm”, eso es porque usa un concepto llamado multihashque identifica el algoritmo hash usado en el hash generado y la longitud del resto del contenido. Los carácteres “Qm” indican que IPFS está usando CIDv0 codificado en Base58, en el futuro IPFS preve usar CIDv1b32, en este enlace se puede consultar una tabla con los identificadores.

Formato multihash:

<hash-type> - <hash-length> - <hash-digest>

Si quieres explorar CIDs IPFS tiene dos páginas, CID Inspector y CID Info panel in IPLD Explorer donde podemos introducir un CID, yo he probado con el hash generado con el texto echo "Hello World" | ipfs add (“QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u”).

El código hexadecimal 0x12 indica que es sha2-256, el 0x20 indica que es de 256 bits de longitud. En esta Web se puede codificar de base hexadecimal a Base58 y a la inversa, el hash previo “QmWATWQ7fVPP2EFGu71UkfnqhYXDYH566qy47CnJDgvs8u” se codifica como “122074410577111096cd817a3faed78630f2245636beded412d3b212a2e09ba593ca” en hexadecimal.

Un sistema multihash permite además migrar a uno más seguro si la seguridad del actual se ve comprometida.

Merece la pena seguir estos enlaces para profundizar más en los CID de IPFS:

Arbol hash de Merkle y los bloques de datos IPFS

Un árbol hash de Merkle es una estructura de datos en árbol en el que cada nodo que no es una hoja está etiquetado con el hash de sus nodos hijo. Permite que gran número de datos separados puedan ser ligados a un único valor de hash, el hash del nodo raíz del árbol. Actualmente el mayor uso de los árboles de Merkle es hacer seguros los bloques de datos recibidos de otros pares en las redes peer-to-peer, asegurar que estos son recibidos sin daños y sin ser alterados. Además permiten que los datos de un bloque puedan ser entregados por partes

[Fuente]

Un nodo IPFS es un programa que puede buscar, publicar o replicar objetos merkledag

Enlaces para continuar investigando:

Guardar a un archivo subido a IPFS

Usando el comando ipfs get podemos guardar en nuestro disco local un objeto IPFS o IPNS dada una ruta.

Por ejemplo me descargo una carpeta con archivos con ejemplos uso de IPFS:

$ ipfs get QmNZiPk974vDsPmQii3YbrMKfi12KTSNM7XMiYyiea4VYZ

Otros comandos

No voy a mencionar todos los comandos uno a uno, se pueden consultar todos en la documentación oficial.

Podemos ver los pares a los que estamos conectados con ipfs swarm peers.

Para visualizar los archivos que hay en nuestro sistema ipfs pin ls.

Para ver información sobre nuestra conexión ipfs id.

Subir un directorio

$ ipfs add -r my-site/
added QmVKqSnEchxyAxg2ueb94f4n5zB2s3buaEw7qCKxrqb9Ta my-site/hqdefault.jpg
added QmTYhbvgMSwTutF5dQndSQPj9cgMsWKjaHkXWJgKaRAmvW my-site/index.html
added QmPfiZTm1f3Aap77eyDpCDXPwwUE58ctSUfrxYnrcaTBvn my-site
 11.51 KiB / 11.51 KiB [=============================================================================================================] 100.00%

La Web ya es accesible en el nodo local http://localhost:8080/ipfs/QmPfiZTm1f3Aap77eyDpCDXPwwUE58ctSUfrxYnrcaTBvn/ como en uno externo referenciando por su hash (IPFS direcciona por contenido gracias a los hashes) https://ipfs.io/ipfs/QmPfiZTm1f3Aap77eyDpCDXPwwUE58ctSUfrxYnrcaTBvn/.

IPNS, gestión de nombres para IPFS

La clave para publicar una Web con IPFS es IPNS, es un protocolo parecido al que usan los DNS que redirige un ID única al hash correspondiente en ese momento.

Registramos el hash de la web actual en IPNS:

$ ipfs name publish QmPfiZTm1f3Aap77eyDpCDXPwwUE58ctSUfrxYnrcaTBvn

Published to QmRqbhErGt2vBCjcdtfJTGdkHUULxpvL9nVmXaHvBNFQAZ: /ipfs/QmPfiZTm1f3Aap77eyDpCDXPwwUE58ctSUfrxYnrcaTBvn

El hash IPNS puede publicarse por la red, ya que siempre apuntará a la última versión de la web, para acceder usamos el protocolo IPNS http://localhost:8080/ipns/QmRqbhErGt2vBCjcdtfJTGdkHUULxpvL9nVmXaHvBNFQAZ/.

En cualquier momento podemos comprobar a que dirección IPFS apunta el hash IPNS con ipfs name resolve.

$ ipfs name resolve QmRqbhErGt2vBCjcdtfJTGdkHUULxpvL9nVmXaHvBNFQAZ

/ipfs/QmPfiZTm1f3Aap77eyDpCDXPwwUE58ctSUfrxYnrcaTBvn

Para actualizar el contenido simplemente se vuelve a repetir el paso de ipfs name publish. IPFS automáticamente modificará la redirección de IPNS.

Aún así, ir dándole a la gente un hash IPNS es demasiado complicado. Afortunadamente, podemos usar el DNS (sistema de nombres de dominio) tradicional para indicar una ruta IPNS y así, como veremos, facilitar bastante las cosas. IPNS usa el registro DNS TXT

Enlaces:

Gateways IPFS

Las puertas de enlace IPFS permiten a los usuarios acceder a contenidos sin necesidad de ejecutar un nodo local.

Podemos comprobar el estado de algunas puertas de enlace IPFS aquí https://ipfs.github.io/public-gateway-checker/, nuestro nodo local también tiene un servidor HTTP con el mismo propósito.

Enlaces:

IPFS Companion

IPFS Companion es una extensión para navegadores (add-on Firefox) que facilita el acceso a recursos IPFS

Mensajeria pubsub

ipfs pubsub es un desarrollo experimental de un broker de mensajería, hay que habilitarlo en el arranque del nodo:

$ ipfs daemon --enable-pubsub-experiment

Con ipfs pubsub ls se obtiene la lista de tópicos a los que estamos suscribidos.

Anonimato

No es anónimo pero podemos usar combinado con Tor, también existe lo que se conoce P2P anónimo).

Instalación de Tor:

$ sudo apt install tor

Funciona como un proxy que redirige el tráfico (127.0.0.1:9050), para Firefox existe una extensión “Proxy Switcher and Manager” para configurarlo de forma sencilla, para probar que funciona está Web lo comprueba https://check.torproject.org/, se puede comprobar con cualquier Web que te diga tu IP como cambia usando o no Tor, además probablemente situe el origen de la conexión en cualquier otro país del que realmente estas.

Conclusiones

No se puede proteger el contenido, si vamos a usar una base datos embebida deberiamos pensar el cifrarla como mínimo.

Para compartir la información con otros peers es necesario que tu computadora este conectada a la red, si se distribuie por muchos pares es más fácil que el contenido sea accesible si no estamos conectados.

[Fuente]

Sin embargo cuando usamos el modelo clásico cliente-servidor la situación no mejora precisamente, la imagen de arriba es una foto del primer servidor Web HTTP (la computadora de Tim Berners-Lee’s en el CERN), el texto de la pegatina lo dice todo “This machine is a server, do not power it down!!” (Fuente: “HTTP is obsolete. It’s time for the distributed, permanent web”).

Las Webs hasta el momento son estáticas.

Resistente a ataques de denegación de servicio.

Enlaces externos

El portal oficial IPFS es el mejor sitio por donde empezar.

Existe una comunidad en IRC, para GNU/Linux se puede usar Irssi por línea de comandos o XChat con ventanas.

El servidor es irc.freenode.org/6667 y existen dos canales /join #ipfs y /join #ipfs-dev, una ayuda con los comandos IRC en el siguiente enlace “IRC basics guide | Opensource.com”.

Tutoriales && información general sobre IPFS:

Noticias relacionadas:

Aplicaciones:

  • ipfs/js-ipfs: IPFS implementation in JavaScript https://js.ipfs.io.
  • github.com “ipfs-shipyard/ipfs-desktop”: An unobtrusive and user-friendly desktop application for IPFS on Windows, Mac and Linux. https://ipfs.io.
  • “Orion”: Orion is an easy to use IPFS Desktop client. It helps sharing content on the public peer to peer network without any command line or technical knowledge.
  • “ZeroNet”: Es una red de internet descentralizada, donde los usuarios de conectan a través del protocolo p2p (par a par). Está desarrollada en python y su licencia se acoge al modelo de software libre.
  • “Solid”: Project led by Prof. Tim Berners-Lee. Building decentralized social applications based on Linked Data principles. Solid is modular and extensible and it relies as much as possible on existing W3C standards and protocols.

En la actualidad, Filecoin es un ejemplo de la implementación de un marketplace de almacenamiento tipo p2p construido con IPFS.