<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Con Magor's blog]]></title><description><![CDATA[Entusiasta de la ciberseguridad e
Ingeniero mecánico. Disfruto participar en desafíos de ciberseguridad de
Capturar la Bandera-CTF]]></description><link>https://conmagor.com</link><generator>RSS for Node</generator><lastBuildDate>Sun, 19 Apr 2026 12:23:54 GMT</lastBuildDate><atom:link href="https://conmagor.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Comunicación PLC Mitsubishi - Python | protocolo MC]]></title><description><![CDATA[Se presenta la comunicación vía ethernet de un computador con un PLC Mitsubishi Electric MELSEC-F Series, modelo FX3GE, usando el módulo socket nativo de Python para enviar las solicitudes y recibir la respuesta del PLC, ya que proporciona una comuni...]]></description><link>https://conmagor.com/comunicacion-plc-mitsubishi-python-protocolo-mc</link><guid isPermaLink="true">https://conmagor.com/comunicacion-plc-mitsubishi-python-protocolo-mc</guid><category><![CDATA[Python]]></category><category><![CDATA[socket]]></category><category><![CDATA[PLC]]></category><dc:creator><![CDATA[Miguel Gómez]]></dc:creator><pubDate>Wed, 30 Nov 2022 21:08:20 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1669841913709/v_nKQcofL.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Se presenta la comunicación vía <strong>ethernet</strong> de un computador con un <strong>PLC Mitsubishi Electric MELSEC-F Series</strong>, modelo <strong>FX3GE</strong>, usando el módulo <a target="_blank" href="https://web.archive.org/web/20211122002923/https://realpython.com/python-sockets/">socket</a> nativo de <strong>Python</strong> para enviar las solicitudes y recibir la respuesta del PLC, ya que proporciona una <a target="_blank" href="https://es.wikipedia.org/wiki/Comunicaci%C3%B3n_entre_procesos">comunicación entre procesos-IPC</a>. Se emplea el <strong>protocolo MC con conexión TCP/IP en formato hexadecimal de código ASCII</strong> y se usa <a target="_blank" href="https://www.mitsubishielectric.com/fa/products/cnt/plceng/smerit/gx_works2/index.html">GX Work2</a> para cargar la configuración al PLC.</p>
<blockquote>
<p><strong>Nota</strong>: Este artículo originalmente lo redacté y publiqué el 06/12/2021 mediante <a target="_blank" href="https://telegra.ph/">telegra.ph</a>, pero ya que inicié este proyecto de blog propio en <a target="_blank" href="https://conmagor.com">conmagor.com</a> decidí revivirlo dado que ya casi es el aniversario de la publicación. Aproveché la republicación para realizar algunos ajustes.</p>
</blockquote>
<p>Antes de comenzar con el código, analicemos el problema a que nos enfrentamos: En esencia se requiere enviar un <strong>mensaje</strong>, para ello se necesita de un <strong>emisor</strong>, un <strong>receptor</strong>, un <strong>medio</strong>, y un <a target="_blank" href="https://es.wikipedia.org/wiki/Protocolo_de_comunicaciones">protocolo de comunicación</a>.</p>
<pre><code class="lang-plaintext">    ┌─────────────────┐                           ┌───────────────────┐
    │                 │                           │                   │
    │                 │                           │                   │
    │                 ├───────────────────────────►                   │
    │   Computador    │                           │       PLC         │
    │    (Emisor)     │      Ethernet (Medio)     │    (Receptor)     │
    │                 ◄───────────────────────────┤                   │
    │                 │                           │                   │
    │                 │                           │                   │
    └─────────────────┘                           └───────────────────┘
                                            ¿Protocolo de comunicación?
</code></pre>
<p>A nivel de hardware se requiere del computador, el cable ethernet y el PLC; la referencia del PLC mencionada ya cuenta con un <strong>módulo para conexión ethernet</strong>, por lo tanto, no es necesario incluir uno.</p>
<p>El rango de protocolos de comunicación se limita a los que maneje el PLC, por lo que el siguiente paso es revisar la documentación disponible por el fabricante:</p>
<ul>
<li><a target="_blank" href="https://web.archive.org/web/20211129191648/https://dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy997d38001/jy997d38001e.pdf">Manual de usuario FX3U-ENET-L User's manual</a>. Para conocer el <strong>procedimiento de comunicación</strong> con el que trabaja.</li>
<li><a target="_blank" href="https://web.archive.org/web/20181123101159/http://dl.mitsubishielectric.com/dl/fa/document/manual/school_text/sh080618eng/sh080618enga.pdf">Manual de entrenamiento Ethernet course(Q-series)</a>. Aunque es de la <em>serie Q</em>, se utilizan los protocolos de comunicación que vamos a revisar, aparte de suministrar conceptos importantes.  </li>
</ul>
<h2 id="heading-procedimiento-de-comunicacion">Procedimiento de comunicación</h2>
<p>En ocasiones no se le suele prestar la debida atención a los manuales, y se comienza por hacer pruebas con librerías en distintos lenguajes y código que se encuentra en internet (lo resalto porque así fue como empecé a realizar pruebas, y de hecho encontré el artículo <a target="_blank" href="https://web.archive.org/web/20211129173757/https://www.programmersought.com/article/77333929120/"><em>Mitsubishi PLC communication Python code</em></a>, el cual fue de gran ayuda como marco de referencia, por lo que agradezco al autor).</p>
<p>Pero eventualmente me concentré en los manuales. En el <strong>capítulo 5</strong> del <a target="_blank" href="https://web.archive.org/web/20211129191648/https://dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy997d38001/jy997d38001e.pdf">manual de usuario</a> se identifica que, el módulo de ethernet del PLC soporta:</p>
<ul>
<li>Comunicación usando <em>Fixed buffers</em>.</li>
<li>Comunicación usando el protocolo MC (MELSEC).</li>
<li>Envío/recepción de email.</li>
<li>Conexión MELSOFT.  </li>
</ul>
<p>Pero, en la siguiente nota aclara, que solo los dos primeros permiten solicitudes de datos desde un dispositivo externo:</p>
<blockquote>
<p>The following communication can be performed with an open device on other end.</p>
<ul>
<li>Communication using MC protocol.</li>
<li>Sending/receiving in fixed buffer communication (procedure exists) When receiving communication request data from an external device — Section 5.1 Overview of the Communication Procedure; FX3U-ENET-L User's manual.</li>
</ul>
</blockquote>
<p>Veamos <em>grosso</em> modo las características de estas dos opciones:</p>
<ul>
<li><strong>MC Protocol (MELSEC protocol)</strong>. Permite a cualquier dispositivo externo (nuestro computador personal por ejemplo) leer o escribir datos desde o hacia el PLC, o ejercer control remoto (RUN/STOP) mediante el módulo ethernet; es un modo de comunicación <strong>pasivo</strong>, de tal forma que es el dispositivo externo quien da las ordenes de lectura/escritura, y para ello puede usar cualquier lenguaje de programación que proporcione una <a target="_blank" href="https://es.wikipedia.org/wiki/Comunicaci%C3%B3n_entre_procesos">comunicación entre procesos-IPC</a>.  </li>
<li><strong>Fixed buffer comunication</strong>: Permite al PLC comunicarse con otros PLC o con un dispositivo externo usando los búferes fijos en la memoria búfer del módulo de ethernet, por lo que es una comunicación <strong>activa</strong> y esa es una diferencia con respecto al protocolo MC.  </li>
</ul>
<p>Si desea indagar en cada protocolo, puede revisar la sección <em>2.2 Types of Data Comunication Functions</em> del <a target="_blank" href="https://web.archive.org/web/20181123101159/http://dl.mitsubishielectric.com/dl/fa/document/manual/school_text/sh080618eng/sh080618enga.pdf">manual de entrenamiento</a>.</p>
<p>Para el presente caso, se decide usar el protocolo MC por el control sobre los espacios de memoria y la sencilla configuración del PLC, la cual se va a presentar a continuación, y con ello iniciar el desglose de la estructura de la solicitud que se enviará al PLC.</p>
<h2 id="heading-protocolo-mc">Protocolo MC</h2>
<p>La transmisión de datos en el protocolo MC se realiza en modo <a target="_blank" href="https://es.wikipedia.org/wiki/D%C3%BAplex_(telecomunicaciones)">semidúplex</a> por lo que cuando se esté enviando un mensaje desde el computador, el PLC estará escuchando, y tendremos que esperar hasta recibir una respuesta del PLC antes de poder enviar el siguiente mensaje; la comunicación se puede usar tanto <strong>TCP/IP</strong> como <strong>UDP</strong> y son compatibles tanto en <strong>código binario</strong> como en formato <strong>hexadecimal de código ASCII</strong>.</p>
<pre><code class="lang-plaintext">Lado del portátil    ┌─────────┐           ┌─────────┐
                     │ Mensaje │           │ Mensaje │
─────────────────────┴─────────┼───────────┼─────────┼───────────┬──►
                               │ Respuesta │         │ Respuesta │
Lado del PLC                   └───────────┘         └───────────┘
</code></pre>
<h3 id="heading-configuracion-del-plc">Configuración del PLC</h3>
<p>Se configura el PLC con <strong>GX Work2</strong> para la comunicación mediante TCP/IP con el protocolo MC, empleando formato hexadecimal de código ASCII.</p>
<p>Para el ejemplo le asignaré al PLC la dirección IP <code>192.168.15.34</code> y el puerto <code>5000</code>. En la <em>figura 1 y 2</em> se ilustra el paso a paso de la configuración que se cargará al PLC luego de iniciar un nuevo proyecto en GX Work2.</p>
<blockquote>
<p><strong>Nota</strong>: Para el ejemplo presentado, el PLC y el PC estarán conectados directamente con el cable ethernet (o por lo menos a través de un switch de red), es decir, el PLC no estará conectado a un router, por lo que podemos asignarle cualquier dirección dentro del bloque <code>192.168.0.0/16</code>, a excepción de las direcciones IP que ya estén siendo usadas.</p>
</blockquote>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669826130706/HUSpCROYY.png" alt="config_plc.png" class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 1. Configuración del PLC, definición de IP local asignada ( 3 4 5 ) ; del tipo de dado en el que se realizará la comunicación ( 6 ); y se abre la ventana para configurar el protocolo ( 7 ) — Tomado y editado de múltiples imágenes de <a target="_blank" href="https://forums.mrplc.com/">foros Mr.PLC</a>.</em></td></tr>
</tbody>
</table>
</div><div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669826135778/6xGnLgvJb.png" alt="config_plc2.png" class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 2. Se selecciona el protocolo TCP ( 8 ), el MC ( 9 ), y se asigna el puerto <code>5000</code> ( 10 ). — Tomado y editado de múltiples imágenes de <a target="_blank" href="https://forums.mrplc.com/">foros Mr.PLC</a>.</em></td></tr>
</tbody>
</table>
</div><h2 id="heading-configuracion-del-pc">Configuración del PC</h2>
<p>En el computador se requiere:</p>
<ul>
<li><strong>Instalar Python3</strong>, si es usuario de Linux, es probable que la distribución GNU/Linux que utilice ya lo tenga instalado por defecto, pero si está en Windows lo puede descargar desde la <a target="_blank" href="https://www.microsoft.com/store/productId/9PJPW5LDXLZ5">Microsoft Store</a>, o directamente desde la <a target="_blank" href="https://www.python.org/downloads/">web oficial de Python</a>.</li>
<li><strong>Habilitar el puerto de comunicación</strong> para entrada y salida de datos. En Linux se puede seguir la guía de <a target="_blank" href="https://www.digitalocean.com/community/tutorials/opening-a-port-on-linux"><em>Opening a port on Linux</em></a>. Para Windows, en la <strong>configuración avanzada del firewall</strong>, debe agregar 2 REGLAS, una <strong>regla de entrada y una de salida</strong> con la misma configuración: <strong>seleccionar la comunicación TCP</strong> en el puerto que elija (<code>5000</code> para este caso), y seleccionar en <strong>permitir la conexión</strong>, puede seguir la <a target="_blank" href="https://docs.microsoft.com/es-es/sql/reporting-services/report-server/configure-a-firewall-for-report-server-access?view=sql-server-ver15">guía de Microsoft</a>, para el paso a paso.</li>
</ul>
<h2 id="heading-estructura-de-la-solicitud-request">Estructura de la solicitud (<em>request</em>)</h2>
<p>La estructura del mensaje se especifica en la sección <em>9.1.2 Message format and control procedure</em> del <a target="_blank" href="https://web.archive.org/web/20211129191648/https://dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy997d38001/jy997d38001e.pdf">manual de usuario</a>, globalmente consiste en una <strong>cabecera seguida</strong> de los <strong>datos de la aplicación</strong>, para el mensaje se ignora la primera ya que en la cabecera se especifican los datos de configuración de la conexión, TCP o UDP, dirección IP, pero, eso no se escribe directamente en el mensaje, desde la configuración del socket se establece.</p>
<p>En la <em>figura 3</em> se presenta la estructura de la lectura y escritura tanto del mensaje enviado desde el PC, hasta la de la respuesta del PLC.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669825412709/v0-ADf2Fh.png" alt="general_leer_escribir.png" class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 3. Respuesta para lectura y escritura ( 1 ) y ( 2 ) respectivamente. El Área A y B dependerán de los registros que se requieran leer y el Área C de los datos que y dónde se van a escribir. -- Tomado de manual de usuario, sección 9.1 Message Formats and Control Procedures.</em></td></tr>
</tbody>
</table>
</div><p>Para no extenderme, el ejemplo del post se limita solo a lectura del PLC. Con la escritura notará que la principal diferencia radica en agregar los datos a escribir al final de la solicitud del mensaje, y que la respuesta del PLC se limita a indicar si se escribió exitosamente o no.</p>
<h2 id="heading-solicitud-de-lectura">Solicitud de lectura</h2>
<p>Para comprender la lectura y cada parte de los datos del mensaje, voy a partir del ejemplo de la <em>pág. 9-10 del <a target="_blank" href="https://web.archive.org/web/20211129191648/https://dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy997d38001/jy997d38001e.pdf">manual de usuario</a></em>, en el que se leen los registros del relé interno <code>M</code> (el cual son marcas en memoria que se pueden usar durante el programa del PLC) en el rango de <code>M100</code> hasta el <code>M108</code>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669825557201/sOvO4pVZm.PNG" alt="read_ascii.PNG" class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 4. (a) Partes del mensaje para lectura de datos de memoria del PLC en formato ASCII. como ejemplo se leen los registros de relé interno <code>M</code> desde el <code>M100</code> al <code>M108</code>. (b) Estructura de respuesta del PLC. -- Tomado de manual de usuario, sección 9.1.3 Contents of data designation items.</em></td></tr>
</tbody>
</table>
</div><p>En la <em>figura 4</em>, se aprecian las partes de los datos de la aplicación, divida según la función que cumple cada sección de bytes que se especifica en el mensaje. Recordemos que <strong>de aquí en adelante nos referiremos siempre al formato hex de código ASCII</strong>. Pasemos por cada una:</p>
<ol>
<li><p><strong>Subheader</strong> <code>2 bytes</code>. Indica la función que se requiere realizar, leer, escribir, testear, o controlar el PLC; en algunos casos decidir si los datos son bits o <em>words</em> (<code>2 bytes</code>). En la <em>tabla 1</em> se encuentra la pareja de bytes correspondientes de acuerdo con la función, que para <strong>lectura en bits de nuestro ejemplo</strong> es la <code>00</code>. <em>Figura 5. Subheader, funciones disponibles a realizar en el PLC. -- Tomado de manual de usuario, sección 9.2 List of Commands and Functions for The MC protocol.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669825620490/pPzsouDF2.PNG" alt="subheader.PNG" class="image--center mx-auto" /> 
<em>Figura 5. Subheader, funciones disponibles a realizar en el PLC. -- Tomado de manual de usuario, sección 9.2 List of Commands and Functions for The MC protocol.</em></p>
</li>
<li><p><strong>PC number</strong> <code>2 bytes</code>. Valor por diseño fijo en <code>FF</code>.</p>
</li>
<li><p><strong>Monitoring timer</strong> <code>4 bytes</code>. <strong>Periodo máximo de tiempo</strong> que se configura al módulo ethernet de espera para una solicitud y poder regresar un resultado.</p>
<pre><code class="lang-plaintext">0000 &lt; - - - Esperar indefinidamente hasta que el PLC responda
        ┌─────────────┬───────────┬────────────────┐
        │ Hexadecimal │  Decimal  │  Milisegundos  │
        ├─────────────┼───────────┼────────────────┤
        │             │           │                │
        │ 0001 - FFFF │ 1 - 65535 │ 250 - 16383750 │
        │             │           │                │
        ├─────────────┴───────────┴────────────────┤
        │ Recomendación para comunicación de datos │
        ├─────────────┬───────────┬────────────────┤
        │             │           │                │
        │ 0001 - 0028 │   1 - 40  │   250 - 10000  │
        │             │           │                │
        └─────────────┴───────────┴────────────────┘
</code></pre>
<p>Para el ejemplo se usan <code>000A</code> equivalente a <code>2.5 segundos</code>.</p>
</li>
<li><p><strong>Device name</strong> <code>4 bytes</code>. Tipo de registro al que vamos a realizar lectura/escritura, para el ejemplo inicial, se usa el <code>4D20</code> el cual corresponde al <strong>relé interno <code>M</code></strong>. <em>Figura 6. Device name. Código que representan el tipo de registro de memoria que se va a leer/escribir. -- Tomado de manual de usuario, sección 9.3.1 Commands and device range.</em></p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669826387622/NlaVqBHyd.PNG" alt="deviceList.PNG" class="image--center mx-auto" /> 
<em>Figura 6. Device name. Código que representan el tipo de registro de memoria que se va a leer/escribir. | Tomado de manual de usuario, sección 9.3.1 Commands and device range.</em></p>
</li>
<li><p><strong>Head device number</strong> <code>8 bytes</code>. Indica el registro de partida para leer/escribir datos. en el ejemplo se requiere iniciar leyendo en el <code>M100</code>, <code>100</code> decimal son <code>0x64</code> en hex, y rellenamos con ceros el resto de los bytes <code>00000064</code>.</p>
</li>
<li><strong>Number of device points</strong> <code>2 bytes</code>. Número de registros a leer/escribir desde el punto de partida definido en el Head device number, para el ejemplo, leer entre el 64 al 72, corresponde a 8 registros, por lo que se escribe <code>08</code>.<blockquote>
<p><strong>Nota</strong>:  En programación, usualmente un rango de <code>(64, 72)</code> se refiere al 64 incluyente y el 72 excluyente.</p>
</blockquote>
</li>
</ol>
<p>Los últimos dos bytes que están en <code>00</code> hacen la función de <em>padding</em>, es decir, se emplean para completar el último octeto de bytes, y enviar <code>3 octetos &lt;==&gt; 24 bytes</code>. Para el ejemplo quedaría:</p>
<pre><code class="lang-plaintext">msg:= 00FF000A4D20000000640800
</code></pre>
<p>La <strong>respuesta</strong>, también tiene un <strong>subheader</strong> de 2 bytes, seguido de un <strong>código</strong> de <code>2 bytes</code> que indica si la <strong>comunicación</strong> fue <strong>completa</strong> <code>00</code> o <strong>anormal</strong> <code>5B</code>, si es anormal, aparecerán otros <code>2 bytes</code> indicando el código del error ocurrido, como se ilustra en la <em>figura 7</em>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669826497797/qSxIlgVPi.PNG" alt="response.PNG" class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 7. Mensaje de lectura enviado y respuesta normal y anormal en caso de que la comunicación sea exitosa. -- Tomado de manual de usuario, sección 9.1.2 Message format and control procedure.</em></td></tr>
</tbody>
</table>
</div><p>Ya se configuró el PLC y se comprende la estructura del mensaje (eso espero), ¡es hora de probarlo en Python!</p>
<h2 id="heading-codigo">¡Código!</h2>
<p>Se va a enviar el mensaje escribiendo directamente con la estructura hexadecimal previa, pero se puede parsear para tener una entrada de datos cómoda.</p>
<p>Revisando la documentación del módulo <code>socket</code>, para la <a target="_blank" href="https://docs.python.org/3/library/socket.html">creación del socket</a>, se requiere crear el objeto para el cliente que será nuestro PC con la clase <code>socket.socket()</code> y se ingresaran como argumentos:</p>
<ul>
<li>La <strong>dirección de la familia</strong>, que para el caso es <code>IPv4</code> por lo que se usa la constante <a target="_blank" href="https://stackoverflow.com/questions/1593946/what-is-af-inet-and-why-do-i-need-it#1594039">socket.AF_INET</a>.</li>
<li>El <strong>tipo de socket</strong>, se usa el <a target="_blank" href="https://stackoverflow.com/questions/35725732/what-is-the-function-of-sock-stream#35725838">socket.AF_INET</a> ya que la comunicación es TCP/IP.</li>
</ul>
<p>Vamos a solicitar <strong>leer</strong> <strong><em>words</em></strong> con un tiempo máximo de espera de <strong>2.5 segundos</strong> el <strong>registro de datos</strong> <code>D135</code> del PLC, el mensaje queda estructurado como en la <em>figura 8</em>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1669826529283/mMl4bz3WB.png" alt="msg_example.png" class="image--center mx-auto" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 8. Mensaje de lectura enviado y respuesta normal y anormal en caso de que la comunicación sea exitosa. -- Tomado de manual de usuario, sección 9.1.2 Message format and control procedure.</em></td></tr>
</tbody>
</table>
</div><p>Y para corroborarlo desde <strong>GX work2</strong> se puede modificar el registro <code>D135</code>, colocando el valor <code>2328</code>.</p>
<pre><code class="lang-python"><span class="hljs-keyword">import</span> socket

HOST = <span class="hljs-string">'192.168.15.34'</span> ➊
PORT = <span class="hljs-number">5000</span>

client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ➋
client.connect((HOST, PORT)) ➌

msg = <span class="hljs-string">b'01FF000A4420000000870100'</span> ➍
to_send = bytearray(msg)

client.send(to_send) ➎
res = client.recv(<span class="hljs-number">1024</span>)

print(res)
<span class="hljs-string">b'81002328'</span>
</code></pre>
<p>En ➊ se define la IP y el puerto al cual nos comunicaremos (deben ser iguales a los definidos en la configuración del PLC). Luego en ➋ se define el cliente configurado para una comunicación <code>IPv4</code> TCP/IP, con el que se enviarán y recibirán los datos. Posteriormente en ➌ se crea la conexión entre el cliente con la IP y puerto especificado para el PLC. En ➍ se prepara el mensaje en hexadecimal para lectura <code>01FF</code> en el que se va a esperar un máximo de <code>2.5</code> segundos de respuesta <code>000A</code>, al registro de datos <code>D135</code>, donde el código de dispositivo <code>D</code> se declara con <code>4420</code> y la dirección <code>135</code> se escribe en hexadecimal con 8 bytes <code>00000087</code>; solo se va a leer un registro por lo que se agrega <code>01</code>, y para finalizar se completan los 3 octetos con el <em>padding</em> de <code>00</code>. Se finaliza en ➎ enviando el mensaje y esperando respuesta para imprimirla en pantalla y validar que la lectura sea de <code>2328</code> valor previamente escrito en la memoria del PLC desde <strong>Gx Work2</strong></p>
<blockquote>
<p><strong>Nota</strong>: El mensaje debe usar el tipo de dato <code>bytes</code>, por eso se agrega el prefijo <code>b</code> en lugar de almacenarlo como <code>string</code>. ya luego se convierte a un <code>bytearray</code>.
El prefijo de <code>8100</code> en la respuesta indica una comunicación exitosa, y efectivamente el valor de la respuesta es el esperado.</p>
</blockquote>
<h2 id="heading-conclusion">Conclusión</h2>
<p>Se realizó lectura de registros de memoria del PLC Mitsubishi Electric MELSEC-F Series, modelo FX3GE, empleando el protocolo de comunicación MC (MELSEC). El PLC y el equipo se conectaron mediante un switch por ethernet. Se indicó la configuración necesaria del PC y PLC, así como también se detalló la estructura del mensaje de solicitud de lectura con un ejemplo empleando la librería de sockets nativa de Python3.</p>
<blockquote>
<p><em>Mira fuera de la caja, las fronteras se disipan, conexiones nuevas aparecen, y todas ellas participan.</em></p>
</blockquote>
<h2 id="heading-referencias">Referencias</h2>
<h4 id="heading-plc">PLC</h4>
<ul>
<li><a target="_blank" href="https://web.archive.org/web/20211129173757/https://www.programmersought.com/article/77333929120/">Mitsubishi PLC communication python code</a></li>
<li><a target="_blank" href="https://web.archive.org/web/20211122002923/https://realpython.com/python-sockets/">Socket Programming in Python (Guide)</a></li>
<li><a target="_blank" href="https://web.archive.org/web/20211129191648/https://dl.mitsubishielectric.com/dl/fa/document/manual/plc_fx/jy997d38001/jy997d38001e.pdf">Manual de usuario FX3U-ENET-L User's manual</a></li>
<li><a target="_blank" href="https://web.archive.org/web/20181123101159/http://dl.mitsubishielectric.com/dl/fa/document/manual/school_text/sh080618eng/sh080618enga.pdf">Manual de entrenamiento Ethernet course(Q-series)</a></li>
<li><a target="_blank" href="https://www.mitsubishielectric.com/fa/products/cnt/plceng/smerit/gx_works2/index.html">GX Work2</a></li>
<li><a target="_blank" href="https://forums.mrplc.com/">Foros Mr.PLC</a></li>
</ul>
<h4 id="heading-red">Red</h4>
<ul>
<li><a target="_blank" href="https://es.wikipedia.org/wiki/Protocolo_de_comunicaciones">Protocolo de comunicación</a>.</li>
<li><a target="_blank" href="https://es.wikipedia.org/wiki/Comunicaci%C3%B3n_entre_procesos">Comunicación entre procesos-IPC</a></li>
<li><a target="_blank" href="https://es.wikipedia.org/wiki/D%C3%BAplex_(telecomunicaciones)">Semidúplex</a></li>
<li><a target="_blank" href="https://www.digitalocean.com/community/tutorials/opening-a-port-on-linux">Opening a port on Linux</a></li>
<li><a target="_blank" href="https://docs.microsoft.com/es-es/sql/reporting-services/report-server/configure-a-firewall-for-report-server-access?view=sql-server-ver15">Guía de Microsoft</a></li>
</ul>
<h4 id="heading-python">Python</h4>
<ul>
<li><a target="_blank" href="https://www.python.org/downloads/">Web oficial de Python</a></li>
<li><a target="_blank" href="https://www.microsoft.com/store/productId/9PJPW5LDXLZ5">Microsoft Store</a></li>
<li><a target="_blank" href="https://web.archive.org/web/20211122002923/https://realpython.com/python-sockets/">Python Sockets</a></li>
<li><a target="_blank" href="https://docs.python.org/3/library/socket.html">Creación del socket</a></li>
<li><a target="_blank" href="https://stackoverflow.com/questions/1593946/what-is-af-inet-and-why-do-i-need-it#1594039">Socket.AF_INET</a></li>
<li><a target="_blank" href="https://stackoverflow.com/questions/35725732/what-is-the-function-of-sock-stream#35725838">Socket.AF_INET</a></li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Length Extension Attack en SHA-2 Parte 1 - Diseccionando el SHA-512]]></title><description><![CDATA[La Antártida, 28 de febrero de 2042. Transmisión recuperada al 67%, reproduciendo:
 ... la IA llamada Bob fue diseñada para recopilar y almacenar ... mi equipo fue asignado en secreto a esta investigación hace 5 años... Eve logró sesgar a Bob para qu...]]></description><link>https://conmagor.com/length-extension-attack-en-sha-2-parte-1</link><guid isPermaLink="true">https://conmagor.com/length-extension-attack-en-sha-2-parte-1</guid><category><![CDATA[Cryptography]]></category><category><![CDATA[Python 3]]></category><category><![CDATA[cybersecurity]]></category><category><![CDATA[CTF]]></category><category><![CDATA[web]]></category><dc:creator><![CDATA[Miguel Gómez]]></dc:creator><pubDate>Mon, 31 Oct 2022 18:36:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1667238922753/FEoEU5D20.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>La Antártida, 28 de febrero de 2042. Transmisión recuperada al 67%, reproduciendo:</p>
<p> <em>... la IA llamada Bob fue diseñada para recopilar y almacenar ... mi equipo fue asignado en secreto a esta investigación hace 5 años... Eve logró sesgar a Bob para que use un ... de autenticación vulnerable con un sabotaje a los repositorios de código públicos durante el cataclismo de internet del 2037... había un espía en el... atacados... logré escapar solo para enviarte esta transmisión, no hay nadie más en quien confíe, sé que Eve aún no ha logrado obtener el portal de acceso para explotar la vulnerabilidad, de lo contrario no nos habría...</em></p>
<p>Le he tomado gusto a los retos de CTF, así que quise comenzar con una historia.</p>
<p>Esta es una serie de artículos que tienen como objetivo facilitar al lector la comprensión de la vulnerabilidad <strong>Length Extension Attack</strong> cuando no se emplea correctamente el SHA-2 (especificamente el SHA-512) como <a target="_blank" href="https://en.wikipedia.org/wiki/Message_authentication_code">código de autenticación de mensajes</a>; y se dividirá en 2 partes:</p>
<ul>
<li>Parte 1: <strong>Diseccionando el SHA-512</strong>.</li>
<li>Parte 2: <strong>Caso de estudio SHA-512 para autenticar mensajes</strong>.</li>
</ul>
<p>¡Cada artículo se potenciará con scripts de Python3 reproducibles!, a los que se puede acceder en mi <a target="_blank" href="https://github.com/xmagor/magor-posts-resources/tree/main/crypto/length-extension-attack">repositorio de github magor-posts-resources</a>.</p>
<blockquote>
<p>Nota: Los diagramas e imágenes que no tengan la referencia de dónde fueron tomados, es porque son de mi autoría.</p>
</blockquote>
<h2 id="heading-funcionamiento-del-sha-2">Funcionamiento del SHA-2</h2>
<p>El SHA-2 es una familia de 6 <a target="_blank" href="https://es.wikipedia.org/wiki/Funci%C3%B3n_hash_criptogr%C3%A1fica">funciones hash criptográficas</a> publicadas por la National Institute of Standards and tecnology - <a target="_blank" href="https://www.nist.gov/">NIST</a> en su Federal Information Processing Standard - <a target="_blank" href="https://en.wikipedia.org/wiki/Federal_Information_Processing_Standard">FIPS</a> . Las <a target="_blank" href="https://es.wikipedia.org/wiki/Funci%C3%B3n_hash">funciones hash</a> convierten un dato de entrada en una representación condensada denominada <em>message digest</em> o <em>hash</em>, que si cumplen una serie de <a target="_blank" href="https://es.wikipedia.org/wiki/Funci%C3%B3n_hash_criptogr%C3%A1fica#Propiedades">propiedades de seguridad</a> se denominan funciones hash criptográficas y las hace útiles en <a target="_blank" href="https://es.wikipedia.org/wiki/Funci%C3%B3n_hash_criptogr%C3%A1fica#Aplicaciones_de_la_funci%C3%B3n_de_hash_criptograficas">múltiples aplicaciones</a> como almacenamiento de contraseñas y búsqueda en bases de datos.</p>
<p>Las 6 funciones SHA-2 son <strong>SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256</strong> al ser parte de la misma familia, comparte la misma estructura algorítmica, solo varían en los valores y tamaño de las variables con los que trabajan. A continuación, se presenta la estructura general para la familia SHA-2:</p>
<blockquote>
<p>El proceso explicado de esta sección se basa en el <a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">FIPS 180-4 <em>Secure Hash Standard</em> (SHS)</a>. Por lo que parte de la explicación será directamente tomada del estándar.</p>
</blockquote>
<ol>
<li><p><strong>Preprocesamiento: Pad, Parse and initializate</strong>. Se encarga de darle una estructura de bloques (<em>chunks</em>) de igual tamaño al mensaje e inicializa algunas variables, esto se hace en 3 etapas:</p>
<ul>
<li><p>Aplicar un <strong>padding</strong> al mensaje para que la longitud sea múltiplo de <code>512 bits</code> para el SHA-256 o de <code>1024 bits</code> para el SHA-512; El <em>padding</em> usa las reglas del <a target="_blank" href="https://en.wikipedia.org/wiki/Merkle%E2%80%93Damg%C3%A5rd_construction#MD-compliant_padding"><em>Merkle–Damgår-compliant padding</em></a>.</p>
<blockquote>
<p>ya que el objetivo es que se divida en bloques del mismo tamaño, si no se hiciera el <em>padding</em> podría quedar un bloque de tamaño diferente a los otros)</p>
</blockquote>
</li>
<li><p>Aplicar un <strong>parse</strong>, que consiste en dividir el mensaje en <em>chunks</em> de <code>N bits</code> (de <code>512 bits</code> o <code>1024 bits</code> para el SHA-256 o el SHA-512 respectivamente). </p>
</li>
<li>Declarar una serie de constantes \(K_{t}^{\{512\}}\) y los valores hash iniciales \(H^{(0)}\), el tamaño y valores dependerá de la función SHA-2 que se emplee.</li>
</ul>
</li>
<li><strong>Procesamiento de chunks</strong>. En el que se aplican la función de compresión (<em>compression function</em>) y el <em>message schedule</em> mediante operaciones a nivel de bits - <em>bitwise operation</em>. Mas adelante se explicará en detalle.</li>
</ol>
<h2 id="heading-diagrama-de-flujo-de-sha-512">Diagrama de flujo de SHA-512</h2>
<p>Con la descripción general dada previamente, se presenta en la <em>figura 1</em> el diagrama de flujo del algoritmo de hash para el <strong>SHA-512</strong> que se desglosará en el artículo.</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665600126504/Mh86liobW.png" alt="sha512_flowchart.png" />
<em>Figura 1.  Diagrama de flujo de algoritmo SHA-512</em></p>
<p>Con el camino trazado, ahora se va a detallar cada etapa de procesamiento, partiendo como ejemplo, de la siguiente entrada de texto:</p>
<pre><code class="lang-Python"><span class="hljs-meta">&gt;&gt;&gt; </span>msg = <span class="hljs-string">b"Para_encontrarlo_debes_mirar_mas_alla_de_lo_que_ves"</span> <span class="hljs-comment"># bytes</span>
</code></pre>
<blockquote>
<p>Es oportuno resaltar que para efectos prácticos, todas las variables se manejaran a nivel de bytes (por eso en Python3, el <code>msg</code> se inicializa con tipo de dato <code>bytes</code> usando el prefijo <code>b</code> al string). Y por esa misma razón, no se usan tildes ya que <code>bytes can only contain ASCII literal characters.</code></p>
</blockquote>
<h2 id="heading-preprocesamiento-sha-512">Preprocesamiento SHA 512</h2>
<h3 id="heading-padding">Padding</h3>
<p>El mensaje se debe preparar bajo las siguientes reglas (recordando que para SHA-512 se busca procesar bloques de <code>1024b bits</code>).</p>
<h4 id="heading-1-calcular-la-longitud-l-del-mensaje-en-bits">1. Calcular la longitud <code>l</code> del mensaje en bits</h4>
<p>Al final del <em>padding</em> se debe agregar la <strong>longitud del mensaje medida en bits en formato binario de 128 bits</strong>. Y a pesar de que se concatena al final del <em>padding</em>, es nescario calcularla al inicio ya que debe ser la longitud del mensaje de entrada antes de cualquier tratamiento.</p>
<pre><code class="lang-Python">    &gt;&gt;&gt;➊L = len(msg) <span class="hljs-comment"># Longitud del string en número de bytes</span>
    &gt;&gt;&gt; L
    <span class="hljs-number">51</span>
    &gt;&gt;&gt;➋l_bits = L*<span class="hljs-number">8</span>
    &gt;&gt;&gt; l_bits
    <span class="hljs-number">408</span>
    &gt;&gt;&gt;➌len_big_endian = l_bits.to_bytes(<span class="hljs-number">16</span>,<span class="hljs-string">'big'</span>)
    &gt;&gt;&gt; len_big_endian
    <span class="hljs-string">b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x98'</span>
</code></pre>
<p>Para el msg de ejemplo, <code>L</code> almacena en ➊ el número de bytes que luego en ➋ se convierte a número de bits ; posteriormente el número de bits (<code>408</code> para el caso de ejemplo) se debe transformar en su representación de bytes con el <em>padding</em> de ceros en ➌, el <em>padding</em> de ceros es necesario ya que el algoritmo indica que se debe representar en un binario de <code>128 bits</code> (<code>16 bytes</code>). El método <code>int.to_bytes(length, byteorder)</code> recibe dos argumentos <code>length</code> indica la cantidad de bytes con los que se requiere representar el número, si se usan mas de los necesarios se colocaran bytes nulos <code>\x00</code>; y <code>byteorder</code> indica el sistema de ordenado que se usará para "leer los bytes" definiendo <code>big</code> si el byte más significativo es el byte del comienzo <em>big-endian</em>, o <code>little</code> si el byte más significativo es el último byte <em>little-endian</em>.</p>
<p>Es importante destacar que directamente no indicamos bits, ya que la mínima unidad con la que se puede trabajar es el byte, por eso en ➌ la longitud que se usa es <code>16 bytes</code> (<code>128 bits/8</code>).</p>
<blockquote>
<ul>
<li>En Python3, para escribir un byte en formato hexadecimal dentro de comillas se usa la estructura <code>'\x&lt;2-digit hex number&gt;'</code>. Pero es posible declarar una variable con <code>variable = 0x60</code> por ejemplo y almacenará el equivalente en entero base 10.</li>
<li>La notación <em>big-endian</em> es a la que quizá se está más acostumbrado ya que un número en base 2 se lee en esa notación (de derecha a izquierda el valor va de menor a mayor), para profundizar en el tema pueden leer <a target="_blank" href="https://devopedia.org/byte-ordering">Byte ordering</a></li>
</ul>
</blockquote>
<p>Por el momento se va a reservar la variable <code>len_big_endian</code>, para usarala más adelante.</p>
<h4 id="heading-2-concatenar-el-bit-1-al-final-del-mensaje">2. Concatenar el bit <code>1</code> al final del mensaje</h4>
<p>Como se resaltó en el paso anterior, no es posible agregar solamente un bit <code>1</code>, ya que las instrucciones que llegan al procesador están agrupadas en en octetos de bits, así que para agregar ese único bit <code>1</code>, se debe usar el byte <code>10000000</code> que en hexadecimal es <code>0x80</code> (128 base 10) ; de esta manera, realmente se concatena el bit <code>1</code> y 7 bits <code>0</code>.</p>
<pre><code class="lang-Python">msg_pad = msg + <span class="hljs-string">b"\x80"</span>
</code></pre>
<p>En la <em>figura 2</em> se aprecia el comienzo de la estructura de bloque de <code>1024 bits</code> que se busca realizar.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665686663016/Lo7LYXI-1.png" alt="msg_preprocessing_1.png" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 2.  Se concatena <code>0x80</code> para agregar en binario <code>10000000</code></em></td></tr>
</tbody>
</table>
</div><h4 id="heading-3-concatenar-k-bits-0">3. Concatenar <code>k</code> bits "0"</h4>
<p>Donde <code>k</code> es el valor más pequeño que cumple con: $$l + 1 + k \equiv 896 \bmod 1024$$Donde:</p>
<ul>
<li>\(l\) es la longitud del mensaje en bits.</li>
<li>1 es el bit que se concatena al mensaje.</li>
<li>\(k\) es el número de bits <code>0</code> que se concatenan luego del bit <code>1</code>.</li>
</ul>
<blockquote>
<p>En esencia, lo que dice la ecuación es que se quieren agregar <code>k</code> veces el bit <code>0</code> para rellenar el bloque, teniendo en cuenta de que al principio del bloque irá una porción del <code>msg</code>, que se agrega el byte <code>0x80</code> y que al final se debe agregar la longitud del mensaje con un tamaño de <code>128 bits</code>.</p>
</blockquote>
<p>En <a target="_blank" href="https://es.wikipedia.org/wiki/Aritm%C3%A9tica_modular">aritmética modular</a>  la ecuación presentada indica que \((l + 1 + k)\) y \(896\)  son <a target="_blank" href="https://web.archive.org/web/20111125042616/http://www.cimm.ucr.ac.cr/da/files/sec1art1-12.pdf">congruentes</a> según el módulo \(1024\). y que sean congruentes quiere decir que tanto 896 como  \((l + 1 + k)\) deben dejar el mismo resto si se dividen entre \(1024\) bajo una <a target="_blank" href="https://es.wikipedia.org/wiki/Divisi%C3%B3n_eucl%C3%ADdea">división euclídea</a> , en otras palabras,  que \(896\) es el residuo de la división entre \((l + 1 + k)/1024\).</p>
<blockquote>
<p>La <strong>división euclídea</strong> es la <em>división con resto</em>, que mantienen los números en el conjunto de los enteros, diferente a la <strong>división exacta</strong>, que los maneja en el conjunto de los números reales.</p>
</blockquote>
<p>Bien, ahora el <em>padding</em> (es decir, calcular <code>k</code>) se puede implementar de múltiples maneras, les presentaré la que escogí por su belleza matemática.</p>
<p>Note que \(896 + 128 = 1024\),  justo los 128 bits necesarios para concatenar la longitud del mensaje calculado en el <a class="post-section-overview" href="#Padding">paso 1 del padding</a>, y gracias a que la relación de congruencia mencionada previamente satisface todas las condiciones de una <a target="_blank" href="https://es.wikipedia.org/wiki/Relaci%C3%B3n_de_equivalencia">relación de equivalencia</a> se cumple la siguiente propiedad:</p>
<blockquote>
<p>Si \(a \equiv b \bmod N\)  entonces se cumple que  \((a + z) \equiv (b + z) \bmod N\) para cualquier entero \(z\). Lo que significa que se puede sumar el mismo valor a ambos lados de la igualdad sin alterar la relación.</p>
</blockquote>
<p>Aplicando la propiedad se suma \(128\) en cada lado:  $$(l + 1 + k + 128) \equiv (896 + 128) \bmod 1024$$Ahora se resta \(k\) en ambos lados: $$(l + 1 + 128) \equiv 1024 - k \bmod 1024$$Y, según la relación euclídea, el \(1024 -k\) es el resto de la divisón de \((l+1+128)/1024\). En Python se puede re escribir con el operador módulo <code>%</code> como una igualdad:$$(l + 1 + 128 ) \% 1024 = 1024 - k$$
Se despeja \(k\): $$k = 1024 - (l + 1 + 128 ) \% 1024$$Se podría pensar que la ecuación está lista para escribirse en Python, pero <strong>cuidado</strong>, hay un detalle que no puede pasar desapercibido. Recuerde que la ecuación está planteada en número de bits y que en teoría solo se concatena el bit 1 y por eso solo se suma \(+1\), pero nosotros no agregamos realmente el bit <code>1</code> sino el byte <code>0x80</code>, es decir agregamos 8 bits. Realizando esa corrección la ecuación queda: $$k = 1024 - (l + 8 + 128 ) \% 1024$$
En el código de Python escribo la ecuación convirtiéndola a bytes:</p>
<pre><code class="lang-Python">    K = <span class="hljs-number">128</span> - (L + <span class="hljs-number">1</span> + <span class="hljs-number">16</span>)%<span class="hljs-number">128</span> <span class="hljs-comment"># 128 - (51 + 1 + 16)%128 = 60</span>

    msg_pad = msg + <span class="hljs-string">b"\x80"</span> + <span class="hljs-string">b"\x00"</span>*K
</code></pre>
<blockquote>
<p>Para aquellos que inician en el mundo de la aritmética modular, recomiendo ver la serie de videos del canal de <a target="_blank" href="https://www.youtube.com/watch?v=-ZwAFmaR_sA">Lemnismath</a>.</p>
</blockquote>
<h4 id="heading-4-concatenar-la-longitud-del-mensaje">4. Concatenar la longitud del mensaje</h4>
<p>Escrito en binario en bloque de 128 bits que ya se procesó en el <a class="post-section-overview" href="#Padding">paso 1 del padding</a>. Resulta:</p>
<pre><code class="lang-Python">msg_pad = msg + <span class="hljs-string">b"\x80"</span> + <span class="hljs-string">b"\x00"</span>*K + len_big_endian
</code></pre>
<p>Con el proceso de <em>padding</em> finalizado el mensaje luce como se presenta en la <em>figura 3</em>.</p>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665337226939/Uq0ELbX-w.png" alt="msg_preprocesed.png" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 3.  Proceso completo de padding: concatenar <code>0x80</code>, \(k\) veces <code>0x00</code> y la longitud del mensaje en un binario de 128 bits </em></td></tr>
</tbody>
</table>
</div><p>Lo escribo en monoespaciado por si se requiere copiar:</p>
<pre><code class="lang-Python"><span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad
<span class="hljs-string">b'Para_encontrarlo_debes_mirar_mas_alla_de_lo_que_ves\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x98'</span>
</code></pre>
<p>Y recolecto todo el proceso de <em>padding</em> en una función de Python:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">padding</span>(<span class="hljs-params">msg: bytes</span>) -&gt; bytes:</span>

    <span class="hljs-comment"># Cálculo de longitud, midiendo el número de bits usados en base decimal</span>
    L = len(msg) <span class="hljs-comment"># 51 bytes</span>
    l_bits = L*<span class="hljs-number">8</span> <span class="hljs-comment"># 408 bits</span>

    len_big_endian = l_bits.to_bytes(<span class="hljs-number">16</span>,<span class="hljs-string">'big'</span>)
    K = <span class="hljs-number">128</span> - (L + <span class="hljs-number">1</span> + <span class="hljs-number">16</span>)%<span class="hljs-number">128</span> <span class="hljs-comment"># 128 - (51 + 1 + 16)%128 = 60</span>

    msg_pad = msg + <span class="hljs-string">b"\x80"</span> + <span class="hljs-string">b"\x00"</span>*K + len_big_endian

    <span class="hljs-keyword">return</span> msg_pad
</code></pre>
<p>Para solventar las dudas que se puedan presentar, dejo algunos casos con diferentes longitudes de mensaje, tanto ejecutandolo con Python como con una representación visual en la <em>figura 4</em>.</p>
<blockquote>
<p>Para facilitar el control de la longitud del mensaje, repito la letra <code>H</code>  un número <code>n</code> de veces</p>
</blockquote>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad = padding(<span class="hljs-string">b'H'</span>*<span class="hljs-number">108</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad
<span class="hljs-string">b'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03`'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad = padding(<span class="hljs-string">b'H'</span>*<span class="hljs-number">209</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad
<span class="hljs-string">b'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x06\x88'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad = padding(<span class="hljs-string">b'H'</span>*<span class="hljs-number">251</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad
<span class="hljs-string">b'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x07\xd8'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad = padding(<span class="hljs-string">b'H'</span>*<span class="hljs-number">390</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_pad
<span class="hljs-string">b'HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH\x80\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x0c0'</span>
</code></pre>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665594942388/vE65gim2E.png" alt="ejemplos_padding.png" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 4.  Ejemplos de padding para diferentes longitudes de mensajes</em></td></tr>
</tbody>
</table>
</div><blockquote>
<p>Note que en Python3 cuando un hexadecimal tiene una representación de carácter imprimible, se verá el carácter en lugar del hexadecimal, como ocurre en el último ejemplo que al final queda <code>\x0c0</code>, esto es equivalente a <code>b'\x0c\x30'</code> pero el <code>b'\x30'</code> se representa con <code>0</code> por su equivalencia en <a target="_blank" href="https://www.asciitable.com/">ASCII</a>. </p>
</blockquote>
<h3 id="heading-parssing">Parssing</h3>
<p>Si el proceso de <em>padding</em> quedó bien hecho, se debe poder dividir el mensaje en \(N\) bloques de exactamente 1024 bits (128 bytes).</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">parssing</span>(<span class="hljs-params">msg_pad: bytes</span>) -&gt; list:</span>

    M = []
  ➊ <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>, len(msg_pad), <span class="hljs-number">128</span>):
      ➋ M_i = msg_pad[i:i+<span class="hljs-number">128</span>]
        M.append(M_i)

    <span class="hljs-keyword">return</span> M
</code></pre>
<p>El bucle ➊ se realiza en saltos de <code>128 bytes</code>, de tal manera que cada i-ésimo bloque o <em>chunk</em> ➋ se agregará a la lista <code>M</code> para ser procesado en la siguiente etapa.</p>
<blockquote>
<p>Presento este paso con el objetivo de dar claridad al algoritmo, una vez se comprenda, se verá que podría prescindirse y realizarce directamente en el procesamiento.</p>
</blockquote>
<h3 id="heading-initialize">Initialize</h3>
<p>Consiste en inicializar 8 valores hash con datos de <strong>64 bits (8 bytes)</strong>
$$
\begin{gather}
    H^{(0)}_0 = 6a09e667f3bcc908 \\
    H^{(0)}_1 = bb67ae8584caa73b \\
    H^{(0)}_2 = 3c6ef372fe94f82b \\
    H^{(0)}_3 = a54ff53a5f1d36f1 \\
    H^{(0)}_4 = 510e527fade682d1 \\
    H^{(0)}_5 = 9b05688c2b3e6c1f \\
    H^{(0)}_6 = 1f83d9abfb41bd6b \\
    H^{(0)}_7 = 5be0cd19137e2179 \\
\end{gather}
$$
<strong>Los valores surgen de representar en hexadecimal los primeros 64 bits de las partes fraccionarias de las raíces cuadradas de los primeros 8 números primos.</strong></p>
<p>Para comprender el enunciado anterior, lo voy a desglosar desde el final al inicio e iré mostrando el ejemplo con el primer valor del hash \(H^{(0)}_0\).</p>
<p>Dice que tome los <strong>primeros 8 números primos</strong>, para el \(H^{(0)}_0\)  correspondría el primer primo <code>2</code>:</p>
<p>Luego dice, <strong>saque la raíz cuadrada y tome solo la parte fraccionaria</strong> (números a la derecha de la coma), es decir:
$$
\begin{gather}
\sqrt(2) = 1.4142135... \\
fractional_{part} = 0.4142135...
\end{gather}
$$</p>
<p>Comencemos realizando ese proceso en Python3:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span><span class="hljs-keyword">import</span> decimal
&gt;&gt;&gt;➊<span class="hljs-number">2</span>**(<span class="hljs-number">1</span>/<span class="hljs-number">2</span>) <span class="hljs-comment"># or import math ; math.sqrt(2)</span>
<span class="hljs-number">1.414213562373095</span>
&gt;&gt;&gt;➋decimal.getcontext().prec 
<span class="hljs-number">28</span>
&gt;&gt;&gt;➌prime = decimal.Decimal(<span class="hljs-number">2</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>prime
Decimal(<span class="hljs-string">'2'</span>)
&gt;&gt;&gt;➍square_root = prime.sqrt()
<span class="hljs-meta">&gt;&gt;&gt; </span>square_root
Decimal(<span class="hljs-string">'1.414213562373095048801688724'</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>whole_part = int(square_root)
&gt;&gt;&gt;➎fractional_part = square_root - whole_part
<span class="hljs-meta">&gt;&gt;&gt; </span>fractional_part
Decimal(<span class="hljs-string">'0.414213562373095048801688724'</span>)
</code></pre>
<p>Utilizo el <a target="_blank" href="https://docs.python.org/3/library/decimal.html">módulo decimal</a> con el objetivo de tener mayor precisión en el manejo de números de punto flotante. Por defecto <code>decimal</code> maneja una precisión a nivel de 28 decimales ➋ en contraste con ➊ de 15 decimales. Se define <code>2</code> como un objeto de la clase <code>decimal.Decimal</code> ➌, la clase tiene el método de raíz cuadrada incorporado ➍, luego se elimina la parte entera ➎ para quedar únicamente con la parte fraccionaria.</p>
<p>Ahora retomando el enunciado, dice que <strong>tome los primeros 64 bits de la parte fraccionaria y represéntelos en formato hexadecimal</strong>, analice que lo que piden es convertir la parte decimal de un número base 10 a base 16, para ello recomiendo leer <a target="_blank" href="https://www.omnicalculator.com/math/binary-fraction">conversión de parte decimal base 10 a base 2</a>. </p>
<blockquote>
<p>El método de conversión entre diferentes bases es equivalente, Solo varía el tamaño con el que se hacen las multiplicaciones o divisiones, para base 16, reemplace el 2 que aparezca por 16 (y cuando obtenga un numero entre 10 - 15, reemplácelo por letras entre A - F)</p>
</blockquote>
<p>Un resumen del algoritmo a realizar es:</p>
<ol>
<li>Tomar la parte fraccionaria del número real.</li>
<li>Multiplicar la parte fraccionaria por la base del sistema de numeración a convertir (16 en este caso) y restarle la parte entera, para obtener nuevamente solo la parte fraccionaría.</li>
<li>Si la parte entera está entre 10-15 mapéela entre A-F. La parte entera sustraída es ahora parte del valor hexadecimal.</li>
<li>Ir al paso 1 hasta completar la cantidad de números hex que se requiere representar.</li>
</ol>
<p>A continuación presento un paso a paso de ejemplo para convertir los primeros 3 bytes de la parte fraccionaria de <code>0.41421</code> base 10 a base 16.</p>
<pre><code class="lang-python"><span class="hljs-string">'''
    0.41421 x 16 =  6.62736 -&gt;  6 -&gt; 6
    0.62736 x 16 = 10.03776 -&gt; 10 -&gt; 6a   # 10 se mapea en 'a'
    0.03776 x 16 =  0.60416 -&gt;  0 -&gt; 6a0
    0.60416 x 16 =  9.66656 -&gt;  9 -&gt; 6a09
    0.66656 x 16 = 10.66496 -&gt; 10 -&gt; 6a09a 
    0.66496 x 16 = 10.63936 -&gt; 10 -&gt; 6a09aa
'''</span>
</code></pre>
<blockquote>
<p>Tenga en cuenta que el paso 4 habla de <strong>cantidad de números hex</strong>, y una pareja de hexadecimales representa un byte. Requerimos 64 bits que equivale a 8 bytes, por lo que se requieren 8 parejas de hexadecimales, es decir <strong>longitud de 16 valores hexadecimales</strong></p>
</blockquote>
<p>Una vez comprendido el proceso de conversión se puede definir una función <code>decimalPart_to_hex()</code> que se encargue de retornar un <code>string</code> con la representación hexadecimal a partir de ingresar la parte fraccionaria:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">decimalPart_to_hex</span>(<span class="hljs-params">➊value: decimal.Decimal, length: int</span>) -&gt; str:</span>
    new = value*<span class="hljs-number">16</span>
  ➋ whole = int(new)
    fractional_part = new - whole
    length += <span class="hljs-number">-1</span>
    <span class="hljs-keyword">if</span> length &gt;= <span class="hljs-number">0</span>:
        <span class="hljs-keyword">return</span> ➌ hex(whole)[<span class="hljs-number">2</span>:] + ➍decimalPart_to_hex(fractional_part, length)
    <span class="hljs-keyword">else</span>:
        <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>
</code></pre>
<p>Aplico el <a target="_blank" href="https://es.wikipedia.org/wiki/Recursi%C3%B3n_(ciencias_de_computaci%C3%B3n)">algoritmo de recursión</a> para realizar la conversión. En él se va a ir multiplicando la parte fraccionaría ➊ por la base (16 en este caso)  y almacenar la parte entera ➋ que será un valor entre <code>0-15</code>, por lo que al usar <code>hex(N)</code> se mapea entre <code>0-F</code> ➌, y se incluye dentro del <code>return</code> con el llamado a la misma función con la nueva parte fraccionaría ➍, y para evitar que siga indefinidamente la variable <code>length</code> se usa para ir contando el número de veces que se llama la recursión.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>H_0 = decimalPart_to_hex(fractional_part, <span class="hljs-number">16</span>)
<span class="hljs-meta">&gt;&gt;&gt; </span>H_0
<span class="hljs-string">'6a09e667f3bcc908'</span>
</code></pre>
<p>Al ejecutar la función se define la <code>length</code> en <code>16</code> ya que requerimos 8 bytes (64 bits) y cada pareja de valores hexadecimales es un byte.</p>
<blockquote>
<p>Se podría haber realizado un algoritmo iterativo en lugar de uno recursivo, solo utilicé el recursivo para variar, pero usualmente se prefieren los iterativos sobre los recursivos.
¿Qué pasaría si no se limitara la conversión de un número irracional a otro sistema de numeración?, pues, así como un número irracional como el <code>sqrt(2)</code> tiene infinitos decimales, !la conversión nunca pararía!, es por eso que se debe especificar el límite al decir <em>los primeros 64 bits de la parte fraccionaria</em>.</p>
</blockquote>
<p>En Python se almacenan los 8 valores de inicialización de hash en una tupla:</p>
<pre><code class="lang-python">H_0 =(
    <span class="hljs-number">0x6a09e667f3bcc908</span>, <span class="hljs-comment"># H_0_0</span>
    <span class="hljs-number">0xbb67ae8584caa73b</span>, <span class="hljs-comment"># H_0_1</span>
    <span class="hljs-number">0x3c6ef372fe94f82b</span>, <span class="hljs-comment"># H_0_2</span>
    <span class="hljs-number">0xa54ff53a5f1d36f1</span>, <span class="hljs-comment"># H_0_3</span>
    <span class="hljs-number">0x510e527fade682d1</span>, <span class="hljs-comment"># H_0_4</span>
    <span class="hljs-number">0x9b05688c2b3e6c1f</span>, <span class="hljs-comment"># H_0_5</span>
    <span class="hljs-number">0x1f83d9abfb41bd6b</span>, <span class="hljs-comment"># H_0_6</span>
    <span class="hljs-number">0x5be0cd19137e2179</span>, <span class="hljs-comment"># H_0_7</span>
)
</code></pre>
<blockquote>
<p>Curiosidad sobre la inicialización: <a target="_blank" href="https://crypto.stackexchange.com/questions/75322/how-to-compute-initial-buffer-of-sha-512#75323">how to compute initial buffer of sha 512</a>.
<strong>La inicialización será crucial para cuando se realice el <em>Length extension attack</em></strong>.</p>
</blockquote>
<p>Adicional a los valores hash que se inicializan, existen 80 constantes \(K_{0}^{\{512\}}, K_1^{\{512\}}, ..., K\_79^{\{512\}} \) de 64 bits <em>word</em>. Estos valores surgen de representar en hexadecimal los primeros 64 bits de las partes fraccionarias de las <strong>raíces cúbicas</strong> de los primeros 80 números primos.</p>
<pre><code class="lang-python">K = (
    <span class="hljs-number">0x428a2f98d728ae22</span>, <span class="hljs-number">0x7137449123ef65cd</span>, <span class="hljs-number">0xb5c0fbcfec4d3b2f</span>, <span class="hljs-number">0xe9b5dba58189dbbc</span>,  
    <span class="hljs-number">0x3956c25bf348b538</span>, <span class="hljs-number">0x59f111f1b605d019</span>, <span class="hljs-number">0x923f82a4af194f9b</span>, <span class="hljs-number">0xab1c5ed5da6d8118</span>,
    <span class="hljs-number">0xd807aa98a3030242</span>, <span class="hljs-number">0x12835b0145706fbe</span>, <span class="hljs-number">0x243185be4ee4b28c</span>, <span class="hljs-number">0x550c7dc3d5ffb4e2</span>,
    <span class="hljs-number">0x72be5d74f27b896f</span>, <span class="hljs-number">0x80deb1fe3b1696b1</span>, <span class="hljs-number">0x9bdc06a725c71235</span>, <span class="hljs-number">0xc19bf174cf692694</span>, 
    <span class="hljs-number">0xe49b69c19ef14ad2</span>, <span class="hljs-number">0xefbe4786384f25e3</span>, <span class="hljs-number">0x0fc19dc68b8cd5b5</span>, <span class="hljs-number">0x240ca1cc77ac9c65</span>, 
    <span class="hljs-number">0x2de92c6f592b0275</span>, <span class="hljs-number">0x4a7484aa6ea6e483</span>, <span class="hljs-number">0x5cb0a9dcbd41fbd4</span>, <span class="hljs-number">0x76f988da831153b5</span>, 
    <span class="hljs-number">0x983e5152ee66dfab</span>, <span class="hljs-number">0xa831c66d2db43210</span>, <span class="hljs-number">0xb00327c898fb213f</span>, <span class="hljs-number">0xbf597fc7beef0ee4</span>, 
    <span class="hljs-number">0xc6e00bf33da88fc2</span>, <span class="hljs-number">0xd5a79147930aa725</span>, <span class="hljs-number">0x06ca6351e003826f</span>, <span class="hljs-number">0x142929670a0e6e70</span>, 
    <span class="hljs-number">0x27b70a8546d22ffc</span>, <span class="hljs-number">0x2e1b21385c26c926</span>, <span class="hljs-number">0x4d2c6dfc5ac42aed</span>, <span class="hljs-number">0x53380d139d95b3df</span>, 
    <span class="hljs-number">0x650a73548baf63de</span>, <span class="hljs-number">0x766a0abb3c77b2a8</span>, <span class="hljs-number">0x81c2c92e47edaee6</span>, <span class="hljs-number">0x92722c851482353b</span>, 
    <span class="hljs-number">0xa2bfe8a14cf10364</span>, <span class="hljs-number">0xa81a664bbc423001</span>, <span class="hljs-number">0xc24b8b70d0f89791</span>, <span class="hljs-number">0xc76c51a30654be30</span>, 
    <span class="hljs-number">0xd192e819d6ef5218</span>, <span class="hljs-number">0xd69906245565a910</span>, <span class="hljs-number">0xf40e35855771202a</span>, <span class="hljs-number">0x106aa07032bbd1b8</span>,
    <span class="hljs-number">0x19a4c116b8d2d0c8</span>, <span class="hljs-number">0x1e376c085141ab53</span>, <span class="hljs-number">0x2748774cdf8eeb99</span>, <span class="hljs-number">0x34b0bcb5e19b48a8</span>,
    <span class="hljs-number">0x391c0cb3c5c95a63</span>, <span class="hljs-number">0x4ed8aa4ae3418acb</span>, <span class="hljs-number">0x5b9cca4f7763e373</span>, <span class="hljs-number">0x682e6ff3d6b2b8a3</span>,
    <span class="hljs-number">0x748f82ee5defb2fc</span>, <span class="hljs-number">0x78a5636f43172f60</span>, <span class="hljs-number">0x84c87814a1f0ab72</span>, <span class="hljs-number">0x8cc702081a6439ec</span>,
    <span class="hljs-number">0x90befffa23631e28</span>, <span class="hljs-number">0xa4506cebde82bde9</span>, <span class="hljs-number">0xbef9a3f7b2c67915</span>, <span class="hljs-number">0xc67178f2e372532b</span>,
    <span class="hljs-number">0xca273eceea26619c</span>, <span class="hljs-number">0xd186b8c721c0c207</span>, <span class="hljs-number">0xeada7dd6cde0eb1e</span>, <span class="hljs-number">0xf57d4f7fee6ed178</span>,
    <span class="hljs-number">0x06f067aa72176fba</span>, <span class="hljs-number">0x0a637dc5a2c898a6</span>, <span class="hljs-number">0x113f9804bef90dae</span>, <span class="hljs-number">0x1b710b35131c471b</span>,
    <span class="hljs-number">0x28db77f523047d84</span>, <span class="hljs-number">0x32caab7b40c72493</span>, <span class="hljs-number">0x3c9ebe0a15c9bebc</span>, <span class="hljs-number">0x431d67c49c100d4c</span>,
    <span class="hljs-number">0x4cc5d4becb3e42b6</span>, <span class="hljs-number">0x597f299cfc657e2a</span>, <span class="hljs-number">0x5fcb6fab3ad6faec</span>, <span class="hljs-number">0x6c44198c4a475817</span>,
    )
</code></pre>
<p>Intente aplicar el proceso presentado para los valores hash en el cálculo de los valores de la constante <code>K</code>. Note que las diferencias con respecto al \(H^{(0)}\) son que ya no se usan las raíces cuadradas sino las cúbicas y que en lugar de tomar solo los primeros 8 primos se toman los primeros 80.</p>
<p>Con esto se finalizan los preparativos para el procesamiento de cada bloque.</p>
<h2 id="heading-procesamiento-sha-512">Procesamiento SHA-512</h2>
<p>La fase de procesamiento de <em>chunks</em> consiste en emplear una serie de <strong>funciones</strong> definidas a partir de varias <strong>operaciones</strong> aplicadas a un conjunto de <strong>variables</strong>. </p>
<p>Ya que eso es todo el procesamiento, vale la pena separar una sección para definir cada una.</p>
<h3 id="heading-definiciones">Definiciones</h3>
<h4 id="heading-variables">Variables</h4>
<ul>
<li><strong>Chunks number \(N\)</strong>. Número de bloques en el mensaje luego del <em>padding</em>.</li>
<li><strong>Constans \(K_t\)</strong> . \(K_{0}^{\{512\}}, K_1^{\{512\}}, ..., K\_79^{\{512\}} \). 80 constantes cada una es tipo <code>word</code> de <code>64 bits</code>.</li>
<li><strong>Message Block \(M^{(i)}\)</strong>.  i-éssimo Message Block \(M^{(1)}\) ,  \(M^{(2)}\) , ... ,  \(M^{(N)}\) cada uno de de los bloques (<em>chunks</em>) de mensajes que serán procesados, cada uno de <code>1024 bits</code>.</li>
<li><strong>Message Schedule \(W_t\)</strong>. t-ésimo message schedule \(W^{(1)}_t, W^{(2)}_t, ..., W^{(N)}_t\)  cada uno de tipo <code>word</code> de <code>64 bits</code>. con <code>t</code> en el rango \(0 \leq t \leq 79\).</li>
<li><strong>Working variables</strong>. \(a, b, c, d, e, f, g, h\) cada una de tipo <code>word</code> de <code>64 bits</code>.</li>
<li><strong>Hash value</strong>:  \(H^{(i)}_0, H^{(i)}_1, ... , H^{(i)}_7\) i-ésimo valor, va desde el <a class="post-section-overview" href="#Initialize">inicializado previamente</a> en (0) hasta el (N) que será el hash final. Cada uno es de tipo <code>word</code> de <code>64 bits</code> y al concatenarlos se representa el hash.</li>
<li><strong>Temporary Words</strong>: \(T_1\) y \(T_2\) ambos de tipo <code>word</code> de <code>64 bits</code>.</li>
</ul>
<blockquote>
<p>El símbolo <code>{512}</code> indica que el tamaño de la variable es de <code>512 bits</code>.</p>
</blockquote>
<h4 id="heading-operaciones">Operaciones</h4>
<p>A continuación, se presentan las operaciones aplicadas bit a bit que se emplearán (<a target="_blank" href="https://wiki.python.org/moin/%20BitwiseOperators">bitwise operators</a>):</p>
<ul>
<li>\(\land\) <code>a &amp; b</code>. AND.</li>
<li>\(\lor\) <code>a | b</code>. OR.</li>
<li>\(\neg\) <code>a ~ b</code>. Complemento (negación).</li>
<li>\(\oplus\) <code>a ^ b</code>. XOR.</li>
<li>\(\ll\) <code>a &lt;&lt; b</code>. Desplazamiento a la izquierda <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Left_shift"><em>left-shift</em></a>.</li>
<li>\(\gg\) <code>a &gt;&gt; b</code>. Desplazamiento a la derecha <a target="_blank" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Right_shift"><em>rigth-shift</em></a>.</li>
<li>\(+\). <code>(a + b)%2**w</code>. Toda suma se realiza aplicando al final el módulo de \(2^{w}\), donde <code>w</code> es el número de bits de la variable.</li>
<li>\(ROTL^n(x)\) <code>(x &lt;&lt; n) | (x &gt;&gt; (w - n))</code>. Desplazamiento a la izquierda circular de <code>n</code> bits <em>(circular left shift)</em> donde <code>x</code> es tipo <em>word</em> the <code>w</code> bits, <code>n</code> es un entero \(0 \leq n &lt; w\). Se define como: $$ROTL^n(x) = (x \ll n) \lor (x \gg w - n)$$ </li>
<li>\(ROTR^n(x)\) <code>(x &gt;&gt; n) | (x &gt;&gt; (w - n))</code>. Desplazamiento a la derecha circular de <code>n</code> bits <em>(circular right shift)</em>  donde <code>x</code> es tipo <em>word</em> the <code>w</code> bits, <code>n</code> es un entero \(0 \leq n &lt; w\). Se define como: $$ROTR^n(x) = (x \gg n) \lor (x \ll w - n)$$</li>
<li>\(SHR^n(x)\) <code>x &gt;&gt; n</code>.  Desplazamiento a la izquierda  <em>left-shift</em> de <code>n</code> bits. donde <code>x</code> es tipo <em>word</em> the <code>w</code> bits, <code>n</code> es un entero \(0 \leq n &lt; w\).  Se define como: $$SHR^n(x) = x \gg n$$  </li>
</ul>
<blockquote>
<ul>
<li>Usualmente la suma modular <code>(a + b) % 2**w</code> se encontrará como la <em>bitwise operation</em> <code>(a + b) &amp; 0xFFFFFFFF</code> si <code>w=32bits</code> y como <code>(a + b) &amp; 0xFFFFFFFFFFFFFFFF</code> si es <code>w=64bits</code>.</li>
<li>Para SHA-512 el tamaño de las variables es de <code>64 bits</code> por lo que <code>w</code> en <code>ROTL</code> y <code>ROTR</code> se reemplaza directamente por <code>64</code>.</li>
</ul>
</blockquote>
<h4 id="heading-funciones">Funciones</h4>
<p>Se definen las siguientes funciones a partir de las operaciones ya definidas:</p>
<ul>
<li>\(Ch(x,y,z) = (x \land y) \oplus (\neg x \land z)\)</li>
<li>\(Maj(x,y,z) = (x \land y) \oplus (x \land z) \oplus (y \land z)\)</li>
<li>\(\sum_0^{{512}}(x) =  ROTR^{28}(x) \oplus ROTR^{34}(x) \oplus ROTR^{39}(x)\)</li>
<li>\(\sum_1^{{512}}(x) =  ROTR^{14}(x) \oplus ROTR^{18}(x) \oplus ROTR^{41}(x)\)</li>
<li>\(\sigma_0^{{512}}(x) = ROTR^1(x) \oplus ROTR^8(x) \oplus SHR^7(x)\)</li>
<li>\(\sigma_1^{{512}}(x) = ROTR^{19}(x) \oplus ROTR^{61}(x) \oplus SHR^6(x)\)</li>
</ul>
<p>Con el ánimo de mejorar la comprensión del código cuando se realice el cálculo de hash, declararé todas las funciones y operaciones con <a target="_blank" href="https://www.w3schools.com/python/python_lambda.asp">funciones lambda de Python</a>:</p>
<pre><code class="lang-python">ROTL = <span class="hljs-keyword">lambda</span> x, n: (x &lt;&lt; n) | (x &gt;&gt; (<span class="hljs-number">64</span> - n))
ROTR = <span class="hljs-keyword">lambda</span> x, n: (x &gt;&gt; n) | (x &lt;&lt; (<span class="hljs-number">64</span> - n))
SHR = <span class="hljs-keyword">lambda</span> x, n: x &gt;&gt; n
mod_add = <span class="hljs-keyword">lambda</span> x: x % <span class="hljs-number">2</span>**<span class="hljs-number">64</span>

Ch = <span class="hljs-keyword">lambda</span> x, y, z : (x &amp; y) ^ (~x &amp; z)
Maj = <span class="hljs-keyword">lambda</span> x, y, z : (x &amp; y) ^ (x &amp; z) ^ (y &amp; z)
sum_0 = <span class="hljs-keyword">lambda</span> x : ROTR(x, <span class="hljs-number">28</span>) ^ ROTR(x, <span class="hljs-number">34</span>) ^ ROTR(x, <span class="hljs-number">39</span>)
sum_1 = <span class="hljs-keyword">lambda</span> x : ROTR(x, <span class="hljs-number">14</span>) ^ ROTR(x, <span class="hljs-number">18</span>) ^ ROTR(x, <span class="hljs-number">41</span>)
sigma_0 = <span class="hljs-keyword">lambda</span> x : ROTR(x, <span class="hljs-number">1</span>) ^ ROTR(x, <span class="hljs-number">8</span>) ^ SHR(x, <span class="hljs-number">7</span>)
sigma_1 = <span class="hljs-keyword">lambda</span> x : ROTR(x, <span class="hljs-number">19</span>) ^ ROTR(x, <span class="hljs-number">61</span>) ^ SHR(x, <span class="hljs-number">6</span>)
</code></pre>
<h3 id="heading-calculo-de-hash">Cálculo de Hash</h3>
<p> A continuación, se enumeran los pasos a a realizar para cada bloque de mensaje \(M^{(i)}\)</p>
<h4 id="heading-1-preparar-el-message-schedule-wt">1. Preparar el <em>message schedule</em> \(W_t\)</h4>
<p>EL <em>message schedule</em> es un array de 80 elementos tipo <em>word</em> de <code>64 bits</code> \(0 \leq t \leq 79\) y se define similar a una <a target="_blank" href="https://es.wikipedia.org/wiki/Funci%C3%B3n_definida_a_trozos">función definida por partes</a> :</p>

<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665592221187/XS2OKNPtF.png" alt="message_schedule.png" /></p>
<blockquote>
<p>Cuando aparece <code>t-2</code> o <code>t+7</code> , se refiere  a  2 posiciones antes o a 7 posiciones después del t-ésimo elemento respectivamente.</p>
</blockquote>
<p>La definición anterior quiere decir que en en los primeros 16 elementos se almacena el <em>messsage block</em> o <em>chunk</em>. En la <em>figura 5</em> se representa este proceso.</p>
<blockquote>
<p>Recuerde que cada elemento del array almacena un tipo <code>word</code> de <code>64 bits</code> , 16 elementos de 64bits serían <code>64bits*16 = 1024bits</code> y <code>1024 bits</code> es el tamaño del <em>message block</em></p>
</blockquote>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665534528203/cbztrujiA.png" alt="wt_0_15.png" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 5.  Se agrupa el chunck <code>M_i</code> del mensaje (para el ejemplo solo hay un chunk) en octetos de bytes para alamacenarlo en los primeors 16 elementos del array de \(W_t\)</em></td></tr>
</tbody>
</table>
</div><p>Veamos cómo se puede representar en Python, a partir de la lista completa de bloques de mensajes  que se definió en la etapa de <a class="post-section-overview" href="#Parssing">Parssing</a> y fue declarada como <code>M</code>:</p>
<pre><code class="lang-python">➊H = list(H_0)

<span class="hljs-keyword">for</span> M_i <span class="hljs-keyword">in</span> M:
    <span class="hljs-comment"># Step 1 ----------------------------------------------------</span>

   ➋w = [<span class="hljs-number">0</span> <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">80</span>)]
   ➌w[:<span class="hljs-number">16</span>] = [ 
        int.from_bytes(M_i[i:i+<span class="hljs-number">8</span>], <span class="hljs-string">'big'</span>) 
        <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>,len(M_i),<span class="hljs-number">8</span>)
    ]

    <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> range(<span class="hljs-number">16</span>,<span class="hljs-number">80</span>):
      ➍w[t] = mod_add(
            sigma_1(w[t<span class="hljs-number">-2</span>]) + w[t<span class="hljs-number">-7</span>] + sigma_0(w[t<span class="hljs-number">-15</span>]) + w[t<span class="hljs-number">-16</span>]
        )
</code></pre>
<p>Se define la variable <code>H</code> ➊ necesaria para inicializar las <em>working variables</em>. Se inicializa el <em>message schedule</em> con una lista de 80 ceros ➋. Ahora, es imporante tener en mente el tamaño de los datos dentro de cada variable. Un elemento dentro de <code>M_i</code> es de <code>8 bits (1 byte)</code> y cada elemento de <code>w</code> debe ser de <code>64 bits (8 bytes)</code> , por lo tanto <strong>en un elemento de <code>w</code> se almacenan 8 elementos de <code>M_i</code></strong> (como se aprecia en la <em>figura 5</em>). En ese orden de ideas, en ➌ se almacena los <code>1024 bits</code> (<code>128 bytes</code>) del <em>chunk</em>  <code>M_i</code> empaquetados en 8 bytes por cada elemento de  <code>w</code> , ocupando un total de 16 elementos de <code>w</code> (<code>16*8bytes = 128bytes</code>). Posteriormente en ➍ se definen los valores de cada elemento de <code>w</code> entre \(16 \leq t \leq 79\).</p>
<p>Recuerde que para el SHA-512 toda suma debe realizarse con el módulo de \(2^{64}\), por eso en la operación matemática se encierra entre la función definida previamente <code>mod_add()</code>.</p>
<p>Al finalizar esta etapa, el <em>message schedule</em> resulta:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>w = 
[<span class="hljs-number">5792036358313045603</span>, <span class="hljs-number">8029483220258155631</span>, <span class="hljs-number">6873730404557479789</span>, <span class="hljs-number">7598242665182617971</span>, <span class="hljs-number">6872893719089996901</span>, <span class="hljs-number">6875993186804000095</span>, <span class="hljs-number">8531352062716280832</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">408</span>, <span class="hljs-number">2911571691693936358</span>, <span class="hljs-number">3599803890956546956</span>, <span class="hljs-number">7541715550729207361</span>, <span class="hljs-number">14763430595941586223</span>, <span class="hljs-number">12312816151770750367</span>, <span class="hljs-number">12221682926778623852</span>, <span class="hljs-number">5065764605691471852</span>, <span class="hljs-number">9444882222117987553</span>, <span class="hljs-number">15673123931426500046</span>, <span class="hljs-number">3941027188781235209</span>, <span class="hljs-number">14389396689712119193</span>, <span class="hljs-number">2139564214514873782</span>, <span class="hljs-number">14610487654926014051</span>, <span class="hljs-number">15679082303173250267</span>, <span class="hljs-number">8864052261723828435</span>, <span class="hljs-number">12832137541508966715</span>, <span class="hljs-number">11218412837963075850</span>, <span class="hljs-number">8564761913537379313</span>, <span class="hljs-number">1995267673534508094</span>, <span class="hljs-number">9473927269912204893</span>, <span class="hljs-number">10815907873009744948</span>, <span class="hljs-number">17844192423246078642</span>, <span class="hljs-number">13726635304036556379</span>, <span class="hljs-number">17077913186545515888</span>, <span class="hljs-number">18241471263070543080</span>, <span class="hljs-number">1877929430572687587</span>, <span class="hljs-number">17691916832615320201</span>, <span class="hljs-number">3968507111924603135</span>, <span class="hljs-number">16122024224616967401</span>, <span class="hljs-number">12787763067175072500</span>, <span class="hljs-number">2226289459605279125</span>, <span class="hljs-number">18219338217107309453</span>, <span class="hljs-number">17733145255601345618</span>, <span class="hljs-number">7897476126423227698</span>, <span class="hljs-number">17406592524453969575</span>, <span class="hljs-number">13891853509198693113</span>, <span class="hljs-number">1221032305862058346</span>, <span class="hljs-number">5303190446724297546</span>, <span class="hljs-number">2805658293275771255</span>, <span class="hljs-number">2754100344892797835</span>, <span class="hljs-number">9850149294321940400</span>, <span class="hljs-number">408632191292797017</span>, <span class="hljs-number">14727669876953957793</span>, <span class="hljs-number">11747409623811856090</span>, <span class="hljs-number">8023752552519758681</span>, <span class="hljs-number">15791508814739320106</span>, <span class="hljs-number">15892588487913833078</span>, <span class="hljs-number">18274926912844589231</span>, <span class="hljs-number">14380282967716036150</span>, <span class="hljs-number">3091346308650631290</span>, <span class="hljs-number">15928723970613978624</span>, <span class="hljs-number">3026232147351673458</span>, <span class="hljs-number">717573406951658796</span>, <span class="hljs-number">5068373460565810904</span>, <span class="hljs-number">15144568462656454078</span>, <span class="hljs-number">5475194329958706105</span>, <span class="hljs-number">1518406966454733837</span>, <span class="hljs-number">5523058003328669248</span>, <span class="hljs-number">4760157115369456577</span>, <span class="hljs-number">1291837423923193297</span>, <span class="hljs-number">12518490877969124772</span>, <span class="hljs-number">3028727687397583669</span>, <span class="hljs-number">13846493182456048854</span>, <span class="hljs-number">15906529927879894119</span>]
</code></pre>
<p>Y si se verifica al convertir de <code>int</code> a <code>bytes</code> el primer elemento de la lista, se encuentra que son los primeros <code>8 bytes</code> del <em>chunk</em> :</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>w[<span class="hljs-number">0</span>]
<span class="hljs-number">5792036358313045603</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>w[<span class="hljs-number">0</span>].to_bytes(<span class="hljs-number">8</span>, <span class="hljs-string">'big'</span>)
<span class="hljs-string">b'Para_enc'</span>
</code></pre>
<h4 id="heading-2-inicializar-las-8-working-variables">2. Inicializar las 8 <em>Working variables</em></h4>
<p>Se inicializan las 8 <em>working variables</em> <code>a,b,c,d,e,f,g</code> y <code>h</code> a partir del i-ésimo hash \(H^{(i)}_0, H^{(i)}_1, ... , H^{(i)}_7\) que se calculan al finalizar cada iteración. En la primera iteración ya que no hay un calculo previo se usa el hash  \(H^{(0)}\) <a class="post-section-overview" href="#initialize">inicializado previamente</a>.</p>
<pre><code class="lang-python">a, b, c, d, e, f, g, h = H
</code></pre>
<h4 id="heading-3-calcular-variables-temporales-y-redefinir-working-variables-80-veces">3. Calcular variables temporales y redefinir <em>Working variables</em> 80 veces</h4>
<p>$$
\begin{gather}
T_1 = h + \sum_1^{\{512\}}(e) + Ch(e,f,g) + K_t^{\{512\}} + W_t \\
T_2 =  \sum_0^{\{512\}}(a) + Maj(a,b,c)
\end{gather}
$$</p>
<p>Esta estapa es bastante directa, solo hay que tener presente que toda ecuación con una suma debe ir acompañada de la función <code>mod_add()</code> para que se aplique la suma modular.</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> range(<span class="hljs-number">80</span>):
    T_1 = mod_add(h + sum_1(e) + Ch(e, f, g) +K[t] + w[t])
    T_2 = mod_add(sum_0(a) + Maj(a, b, c))

    h = g
    g = f
    f = e
    e = mod_add(d + T_1)
    d = c
    c = b
    b = a
    a = mod_add(T_1 + T_2)
</code></pre>
<h4 id="heading-4-calcular-el-i-esimo-valor-del-hash-intermedio">4. Calcular el i-ésimo valor del hash intermedio</h4>
<p>Consiste en actualizar el valor del i-ésimo hash, es decir, la lista <code>H</code> la cual en la primera iteración tiene el mismo valor de  \(H^{(0)}\). La forma de actualizar cada elemento de <code>H</code> consiste en sumar al valor previo una de las <em>working variables</em> según la posición a la que corresponda:
$$
\begin{gather}
   H^{(i)}_0 = a + H^{(i-1)}_0 \\
   H^{(i)}_1 = b + H^{(i-1)}_1 \\
   H^{(i)}_2 = c + H^{(i-1)}_2 \\
   H^{(i)}_3 = d + H^{(i-1)}_3 \\
   H^{(i)}_4 = a + H^{(i-1)}_4 \\
   H^{(i)}_5 = b + H^{(i-1)}_5 \\
   H^{(i)}_6 = c + H^{(i-1)}_6 \\
   H^{(i)}_7 = d + H^{(i-1)}_7 
\end{gather}
$$</p>
<pre><code class="lang-python"><span class="hljs-keyword">for</span> i, val <span class="hljs-keyword">in</span> enumerate([a, b, c, d, e, f, g, h]):
    H[i] = mod_add(H[i] + val)
</code></pre>
<p>Tome un momento para analizar el funcionamiento del hash <code>H</code> con la siguiente descripción de la <em>figura 6</em>: </p>
<ul>
<li>Cada iteración representa el procesamiento de uno de los <em>chunks</em> en los que está dividido el mensaje luego del <em>padding</em> y <em>parssing</em>.</li>
<li>Al inicio de la primera iteración el valor de <code>H</code> es igual a \(H^{(0)}\), y al finalizar se actualiza este valor al sumarle las <em>working variables</em>.</li>
<li>El nuevo valor de <code>H</code> al finalizar la primera iteración será el que se use para la siguiente iteración (es decir, para procesar el siguiente <em>chunk</em>).</li>
<li>Y ¿qué pasa en el último <em>chunk</em>?. El valor del hash final será igual al de <code>H</code> al finalizar la última iteración.</li>
</ul>
<div class="hn-table">
<table>
<thead>
<tr>
<td><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1665586213609/9m5PNQkjD.png" alt="Flujo_hash.png" /></td></tr>
</thead>
<tbody>
<tr>
<td><em>Figura 6. Flujo de hash <code>H</code> en cada iteración del procesamiento. ¿Qué pasaría si el hash final se usara posteriormente como hash inicial en un nuevo procesamiento? </em></td></tr>
</tbody>
</table>
</div><p>Ahora compacto todo el procesamiento de <em>chunks</em> dentro de la función <code>chunkProcess()</code>.</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">chunkProcess</span>(<span class="hljs-params">M: list</span>) -&gt; bytes :</span>

    H = list(H_0)
    <span class="hljs-keyword">for</span> M_i <span class="hljs-keyword">in</span> M:
        <span class="hljs-comment"># Step 1 ----------------------------------------------------</span>
        w = [<span class="hljs-number">0</span> <span class="hljs-keyword">for</span> _ <span class="hljs-keyword">in</span> range(<span class="hljs-number">80</span>)]
        w[:<span class="hljs-number">16</span>] = [ 
            int.from_bytes(M_i[i:i+<span class="hljs-number">8</span>], <span class="hljs-string">'big'</span>) 
            <span class="hljs-keyword">for</span> i <span class="hljs-keyword">in</span> range(<span class="hljs-number">0</span>,len(M_i),<span class="hljs-number">8</span>)
        ]

        <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> range(<span class="hljs-number">16</span>,<span class="hljs-number">80</span>):
            w[t] = mod_add(
                sigma_1(w[t<span class="hljs-number">-2</span>]) + w[t<span class="hljs-number">-7</span>] + sigma_0(w[t<span class="hljs-number">-15</span>]) + w[t<span class="hljs-number">-16</span>]
            )

        <span class="hljs-comment"># Step 2 ----------------------------------------------------</span>
        a, b, c, d, e, f, g, h = H

        <span class="hljs-comment"># Step 3 ----------------------------------------------------</span>
        <span class="hljs-keyword">for</span> t <span class="hljs-keyword">in</span> range(<span class="hljs-number">80</span>):
            T_1 = mod_add(h + sum_1(e) + Ch(e, f, g) +K[t] + w[t])
            T_2 = mod_add(sum_0(a) + Maj(a, b, c))

            h = g
            g = f
            f = e
            e = mod_add(d + T_1)
            d = c
            c = b
            b = a
            a = mod_add(T_1 + T_2)

        <span class="hljs-comment"># Step 4 ----------------------------------------------------</span>
        <span class="hljs-keyword">for</span> i, val <span class="hljs-keyword">in</span> enumerate([a, b, c, d, e, f, g, h]):
            H[i] = mod_add(H[i] + val)

    <span class="hljs-keyword">return</span> H
</code></pre>
<p>Luego de la ejecución <code>H</code> resulta:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>H = chunkProcess(M)
<span class="hljs-meta">&gt;&gt;&gt; </span>H
[<span class="hljs-number">11776468079915641988</span>, <span class="hljs-number">17808183282443026845</span>, <span class="hljs-number">11099696865277071668</span>, <span class="hljs-number">1174027064773869192</span>, <span class="hljs-number">2297846786359901650</span>, <span class="hljs-number">14842508190960772371</span>, <span class="hljs-number">7035755112111959691</span>, <span class="hljs-number">5973417008618735621</span>]
</code></pre>
<p>Ya solo falta convertir cada elemento de la lista a hexadecimal y concatenarlos:</p>
<pre><code class="lang-python"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hexdigest</span>(<span class="hljs-params">H:list</span>) -&gt; str:</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>.join(map(<span class="hljs-keyword">lambda</span> x: <span class="hljs-string">f"<span class="hljs-subst">{hex(x)[<span class="hljs-number">2</span>:]:<span class="hljs-number">0</span>&gt;<span class="hljs-number">16</span>}</span>"</span>, H))
</code></pre>
<p>Para ello, defino la función <code>hexdigest()</code> donde se usa <code>map()</code> para aplicar la función <code>lambda</code> a cada elemento de <code>H</code>, y en la función <code>lambda</code> se convierte a hexadecimal cada elemento y se le remueve el <code>0x</code>, para al final concatenar todo en un string con <code>''.join()</code>.</p>
<p>Tal vez se esté preguntando el porqué se usa la estructura <a target="_blank" href="https://saralgyaan.com/posts/f-string-in-python-usage-guide/">f-strings</a>. <code>f'{valor:0&gt;16}'</code>. Se usa porque hay casos en los que la conversión a hexadecimal resulta comenzando con <code>0</code>, por ejemplo, si uno de los valores del hash fuera <code>151085024878499711</code> el primer byte de izquierda a derecha sería el <code>0x02</code>, pero Python ignora el <code>0</code> ya que es un cero a la izquierda:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>int_2_hex = hex(<span class="hljs-number">151085024878499711</span>)[<span class="hljs-number">2</span>:]
<span class="hljs-meta">&gt;&gt;&gt; </span>int_to_hex
<span class="hljs-string">'218c30796c3977f'</span>
<span class="hljs-meta">&gt;&gt;&gt; </span>len(int_to_hex)
<span class="hljs-number">15</span>
&gt;&gt;&gt;➊ <span class="hljs-string">f"<span class="hljs-subst">{int_to_hex:<span class="hljs-number">0</span>&gt;<span class="hljs-number">16</span>}</span>"</span>
<span class="hljs-string">'0218c30796c3977f'</span>
</code></pre>
<p>Entonces para asegurar que cada byte sea escrito con una pareja de valores hexadecimales, se agrega un <em>padding</em> con el <code>f-string</code> ➊ . La estructura <code>{[variable]:[pad][symbol][n]}</code> indica que a la <code>[variable]</code> se le agregará un <em>padding</em> con el carácter definido en <code>[pad]</code> para asegurar que la longitud total del <em>string</em> sea igual a <code>[n]</code>, y con el <code>[symbol]</code> se define si se quiere realizar el <em>padding</em> a la izquierda, derecha o centro.</p>
<p>Y !listo!, ya se obtiene el hash SHA-512 del mensaje en formato hexadecimal:</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>hexdigest(H)
<span class="hljs-string">'a36e6b5304192c84f7236057f511019d9a0a0b7d815b5134104afb65288a7e881fe3977a49413dd2cdfb2e8f8a0ae51361a405ff58126e8b52e5d71eedff0805'</span>
</code></pre>
<p>Ahora para darle estructura a las funciones de todo el algoritmo, las agrupé como métodos en la clase <code>sha512()</code></p>
<pre><code class="lang-python"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">sha512</span>():</span>

  ➊ <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">__init__</span>(<span class="hljs-params">self, msg, H_0 = H_0</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
        self.msg = msg
        self.msg_pad = <span class="hljs-string">b''</span>
        self.M = []
        self.H = list(H_0)

      ➋ self.padding()
        self.parssing()
        self.chunkProcess()


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">padding</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
          <span class="hljs-comment"># ...SNIP...</span>


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">parssing</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-keyword">None</span>:</span>
          <span class="hljs-comment"># ...SNIP...</span>


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">chunkProcess</span>(<span class="hljs-params">self</span>) -&gt; <span class="hljs-keyword">None</span> :</span>
          <span class="hljs-comment"># ...SNIP...</span>


    <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">hexdigest</span>(<span class="hljs-params">self</span>) -&gt; str:</span>
        <span class="hljs-keyword">return</span> <span class="hljs-string">''</span>.join(map(<span class="hljs-keyword">lambda</span> x: <span class="hljs-string">f"<span class="hljs-subst">{hex(x)[<span class="hljs-number">2</span>:]:<span class="hljs-number">0</span>&gt;<span class="hljs-number">16</span>}</span>"</span>, self.H))
</code></pre>
<p>Se usa el constructor de clase <code>__init__</code> ➊ para definir los parámetros que requiere la clase: <code>msg</code> y <code>H_0</code> ( <code>H_0</code>  lo definí con el valor por defecto de la inicialización); las variables principales de cada etapa de procesamiento <code>msg_pad</code>, <code>M</code> y <code>H</code> ; y ejecutar todo el preprocesamiento y procesamiento ➋. Los cambios que se realizan a nivel de funciones principalmente consisten en reemplazar las variables definidas en ➊ en todos los métodos.</p>
<blockquote>
<p>Note que para el algoritmo, <code>H_0</code> no es necesario que sea un parámetro de entrada en el constructor <code>__init__</code> porque en esencia es una constante. Pero ya se verá la utilidad de jugar con ese valor cuando se comprenda la <code>length extension attack</code> 👀.</p>
</blockquote>
<h2 id="heading-validacion">Validación</h2>
<p>Sin importar el lenguaje en el que se implemente el algoritmo, debe retornar el mismo valor hash para el mismo mensaje de entrada. Por lo tanto, se puede verificar que se aplicó correctamente, al comparar el hash resultante con el que retorna el módulo de Python <a target="_blank" href="https://docs.python.org/3/library/hashlib.html"><code>hashlib</code> </a> o desde la terminal el comando <a target="_blank" href="https://linuxhint.com/sha512-linux/"><code>sha512sum</code></a>.</p>
<pre><code class="lang-python"><span class="hljs-meta">&gt;&gt;&gt; </span>msg = <span class="hljs-string">b"Para_encontrarlo_debes_mirar_mas_alla_de_lo_que_ves"</span>
&gt;&gt;&gt;➊msg_hash = sha512(msg)
<span class="hljs-meta">&gt;&gt;&gt; </span>msg_hash_hex = msg_hash.hexdigest()
&gt;&gt;&gt;➋msg_hash_hex
<span class="hljs-string">'a36e6b5304192c84f7236057f511019d9a0a0b7d815b5134104afb65288a7e881fe3977a49413dd2cdfb2e8f8a0ae51361a405ff58126e8b52e5d71eedff0805'</span>
&gt;&gt;&gt;➌standard_hash = hashlib.sha512(msg)
<span class="hljs-meta">&gt;&gt;&gt; </span>standard_hash_hex = standard_hash.hexdigest()
&gt;&gt;&gt;➍standard_hash_hex
<span class="hljs-string">'a36e6b5304192c84f7236057f511019d9a0a0b7d815b5134104afb65288a7e881fe3977a49413dd2cdfb2e8f8a0ae51361a405ff58126e8b52e5d71eedff0805'</span>
&gt;&gt;&gt;➎msg_hash_hex == standard_hash_hex
<span class="hljs-literal">True</span>
</code></pre>
<p>Primero se calcula el SHA-512 con la clase que definí durante el transcurso del artículo ➊ y se imprime el hash resultante ➋. Luego se usa el módulo <code>hashlib</code> para calcular el hash SHA-512 del mismo mensaje ➌ (se tuvo que haber instalado e importado previamente <code>import hashlib</code>) y se imprime el valor en ➍. Finalmente comparamos que son iguales ➎.</p>
<p>Al ejecutar el comando <code>sha512sum</code> en la terminal de <code>bash</code>, se obtiene el mismo resultado:</p>
<pre><code class="lang-shell">$ echo -n "Para_encontrarlo_debes_mirar_mas_alla_de_lo_que_ves" | sha512sum
a36e6b5304192c84f7236057f511019d9a0a0b7d815b5134104afb65288a7e881fe3977a49413dd2cdfb2e8f8a0ae51361a405ff58126e8b52e5d71eedff0805  -
</code></pre>
<h2 id="heading-conclusion">Conclusión</h2>
<p>Se presentó en detalle el algoritmo SHA-512 perteneciente a la familia SHA-2, se implementó en Python3, se contrastó el resultado con el módulo de Python <code>hashlib</code> y con el comando de terminal <code>sha512sum</code>. El artículo en sí mismo es el preludio para la siguiente entrega que se enfocará en el <em>length extension attack</em>. Si lo requiere, puede acceder a los códigos presentados en mi <a target="_blank" href="https://github.com/xmagor/magor-posts-resources/tree/main/crypto/length-extension-attack">repositorio de github magor-posts-resources</a>.</p>
<hr />
<blockquote>
<p>En ida y sin regreso, 
como el tiempo quedas preso.
Eres algo que fue y nunca volverá,
pero que si vuelve a suceder a ti te hallarán.</p>
</blockquote>
<hr />
<h2 id="heading-referencias">Referencias</h2>
<ul>
<li><a target="_blank" href="https://es.wikipedia.org/wiki/Funci%C3%B3n_hash_criptogr%C3%A1fica">Función hash criptográfica</a></li>
<li><a target="_blank" href="https://medium.com/@zaid960928/cryptography-explaining-sha-512-ad896365a0c1">Cryptography explaining SHA 512</a></li>
<li><a target="_blank" href="https://en.wikipedia.org/wiki/SHA-2">SHA-2</a></li>
<li><a target="_blank" href="https://crypto.stackexchange.com/questions/22956/what-is-the-length-field-in-sha-512-padding#34117">What is the length field in SHA 512 padding</a></li>
<li><a target="_blank" href="https://csrc.nist.gov/csrc/media/publications/fips/180/2/archive/2002-08-01/documents/fips180-2.pdf">FIPS 180-2 Secure Hash Standard (SHS) </a></li>
<li><a target="_blank" href="https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.180-4.pdf">FIPS 180-4 Secure Hash Standard (SHS)</a></li>
<li><a target="_blank" href="https://www.simplilearn.com/tutorials/cyber-security-tutorial/sha-256-algorithm">SHA 256 algorithm</a></li>
<li><a target="_blank" href="https://medium.com/@domspaulo/python-implementation-of-sha-256-from-scratch-924f660c5d57">Python implementation of SHA 256 from scratch</a></li>
<li><a target="_blank" href="https://crypto.stackexchange.com/questions/10829/why-initialize-sha1-with-specific-buffer/10857#10857">Why inititalizate SHA1 with specific buffer</a></li>
<li><a target="_blank" href="https://docs.python.org/3/library/hashlib.html">Hashlib</a></li>
<li><a target="_blank" href="https://linuxhint.com/sha512-linux/">sha512sum</a></li>
<li><a target="_blank" href="https://medium.com/swlh/the-mathematics-of-bitcoin-74ebf6cefbb0">The mathematics of bitcoin</a></li>
<li><a target="_blank" href="https://iq.opengenus.org/rotation-of-bits-using-bitwise-operators/">Rotation of bits using bitwise operators</a></li>
<li><a target="_blank" href="https://web.archive.org/web/20130526224224/https://csrc.nist.gov/groups/STM/cavp/documents/shs/sha256-384-512.pdf">Descriptions of SHA-256, SHA-384, and SHA-512</a> from <a target="_blank" href="https://en.wikipedia.org/wiki/National_Institute_of_Standards_and_Technology">NIST</a></li>
<li><a target="_blank" href="https://stackoverflow.com/questions/4324335/first-64-bits-of-the-fractional-part-of-the-square-root-of-2#4324376">First 64 bits of the fractional part of the square root of 2</a></li>
</ul>
]]></content:encoded></item></channel></rss>