# Inicio

Apuntes sobre criptografía orientados al pentesting.


# Introducción

El encoding / codificación es un medio para convertir datos. Los datos pueden convertirse a otro formato para ser transmitidos, almacenados o comprimidos. Los algoritmos pueden codificar y decodificar estos datos sin ningún tipo de clave.&#x20;

Es fundamental entender que el encoding / codificación no es encriptación. Siempre que alguien pueda determinar las reglas que se aplicaron a los datos originales, puede revertir fácilmente la codificación sin ningún conocimiento adicional, como contraseñas o claves secretas. Por esta razón, la codificación nunca debe usarse en una situación en la que la seguridad y la confidencialidad de los datos son de vital importancia.

{% hint style="info" %}
El propósito del encoding / codificación es transformar y preservar los datos, mientras que el propósito del cifrado / encriptación es mantenerlos en secreto.
{% endhint %}


# Binary

## Descripción

La unidad de datos más pequeña posible se denomina bit y cada bit es un 0 o un 1 binario. Un grupo de cuatro bits se denomina nibble y un grupo de ocho bits se denomina byte.

## Conversiones

Conversión de decimal a binario.

```shell
echo "obase=2 ; <decimal>" | bc
echo "obase=2 ; 10" | bc

bindechexascii --d2b <decimal>
bindechexascii --d2b 10
```

Conversión de binario a decimal.

```shell
echo "ibase=2 ; <binary>" | bc
echo "ibase=2 ; 1010" | bc

bindechexascii --b2d <binary>
bindechexascii --b2d 1010
```


# Hexadecimal (Base16)

## Descripción

Hexadecimal (Base16) comienza con 0 y cuenta hasta 9. Sin embargo, en lugar de insertar el siguiente número a la derecha, se utilizan las primeras seis letras del alfabeto.

```
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
```

Un byte, que son ocho bits, incluye exactamente dos números hexadecimales, es decir, en cada byte hay dos números hexadecimales (4 bits cada uno).

## Conversiones

Conversión de hexadecimal a decimal.

```shell
echo "ibase=16 ; <hexadecimal>" | bc
echo "ibase=16 ; A" | bc

bindechexascii --h2d <hexadecimal>
bindechexascii --h2d A
```

Conversión de decimal a hexadecimal.

```shell
echo "obase=16 ; <decimal>" | bc
echo "obase=16 ; 10" | bc

bindechexascii --d2h <decimal>
bindechexascii --d2h 10
```


# ASCII

## Descripción

American Standard Code for Information Interchange (ASCII) se utiliza para almacenar y procesar caracteres imprimibles y no imprimibles.

ASCII utiliza 7 bits para representar cada carácter. Define 127 códigos, siendo 32 caracteres no imprimibles, de los cuales la mayoría son caracteres de control que tienen efecto sobre cómo se procesa el texto, más otros 95 caracteres imprimibles que les siguen en la numeración (empezando por el carácter de espacio).

```shell
man ascii
```

## Conversiones

Conversión de hexadecimal a ASCII.

```shell
echo <hexadecimal> | xxd -r -p
echo 41 | xxd -r -p

bindechexascii --h2a <hexadecimal>
bindechexascii --h2a 41
```

Conversión de ASCII a hexadecimal.

```shell
echo -n "<ASCII>" | xxd -p
echo -n "A" | xxd -p

bindechexascii --a2h "<ASCII>"
bindechexascii --a2h "A"
```

Conversión de decimal a ASCII.

```shell
printf \\$(printf "%o" <decimal>)
printf \\$(printf "%o" 65)

bindechexascii --d2a <decimal>
bindechexascii --d2a 65
```

Conversión de ASCII a decimal.

```shell
printf "%d\n" \'<ASCII>
printf "%d\n" \'A

bindechexascii --a2d "<ASCII>"
bindechexascii --a2d "A"
```


# Unicode & UTF

## Descripción

Unicode es un estándar que define un número, o punto de código único, para cada carácter. Otra forma de decir esto es que cada carácter se asigna a un valor único. El término Unicode proviene de los tres objetivos perseguidos: universalidad, uniformidad y unicidad.&#x20;

Unicode Transformation Format (UTF) es una forma de codificar estas asignaciones Unicode. Las formas más comunes de UTF son UTF-8, que usa 8 bits o unidades de 1 byte, y UTF-16, que usa 16 bits o unidades de 2 bytes.&#x20;

UTF-8 fue diseñado para ser compatible con ASCII. Los primeros 128 caracteres de Unicode son idénticos a los caracteres ASCII y UTF-8 utiliza un solo byte con los mismos valores binarios para representarlos. Por ejemplo, el caracter `A` (mayúscula) está codificada en UTF-8 como 41 y también está codificada en ASCII Hex como 41.

## Conversiones

Conversión de archivo ASCII a UTF-8.

```shell
iconv -f ASCII -t UTF-8 <file> -o <output-file>
```


# Base64

## Descripción

Base64 convierte cualquier dato binario en una secuencia codificada de caracteres imprimibles, lo que permite transferir estos datos a través de prácticamente cualquier canal y protocolo. Base64 recibe su nombre por el uso de 64 caracteres.

| Índice   | Caracteres                 |
| -------- | -------------------------- |
| 0 al 25  | ABCDEFGHIJKLMNOPQRSTUVWXYZ |
| 26 al 51 | abcdefghijklmnopqrstuvwxyz |
| 52 al 61 | 0123456789                 |
| 62       | +                          |
| 63       | /                          |

El carácter `=` también podría usarse en la representación visual de esta codificación, pero solo al final de una cadena para relleno. Los caracteres `a-z` y `A-Z` se consideran por separado debido a que Base64 distingue entre mayúsculas y minúsculas.

Base64 convierte cada tres bytes de datos binarios en cuatro caracteres Base64. Cada secuencia de tres bytes se denomina bloque. 3x8 bytes de entrada producen 4x6 bytes Base64 de salida. Cuando la entrada es indivisible por seis, se agregan ceros al final de la cadena de entrada para rellenarla, de modo que se vuelva divisible.&#x20;

La salida Base64 contendrá el carácter `=` si el último bloque de entrada fue solo de dos bytes (sin los ceros agregados). Contendrá `==` si el último bloque de entrada fue solo un byte.&#x20;

Las cadenas codificadas en Base64 siempre son más largas que el texto original porque los bytes regulares tienen ocho bits y los caracteres Base64 solo tienen seis bits de datos.

```
* -----------------*---------------*---------------*---------------*
| Texto de entrada |       A       |       A       |       A       |
*------------------*---------------*---------------*---------------*
| ASCII            |       65      |       65      |       65      |
*------------------*---------------*---------------*---------------*
| Bits             |0|1|0|0|0|0|0|1|0|1|0|0|0|0|0|1|0|1|0|0|0|0|0|1|
*------------------*---------------*---------------*---------------*
| Índice Base64    |     16    |     20    |     5     |     1     |
*------------------*-----------*-----------*-----------*-----------*
| Valor Base64     |     Q     |      U    |     F     |     B     |
*------------------*-----------*-----------*-----------*-----------*
```

## Conversiones

Conversión de texto a Base64.

```shell
echo -n "<text>" | base64
echo -n "A" | base64
```

Conversión de Base64 a texto.

```shell
echo -n "<base64>" | base64 -d
echo -n "QQ==" | base64 -d
```

Conversión de archivo a Base64.

```shell
base64 -w 0 <file>
```


# URL encoding

## Descripción

URL encoding funciona reemplazando todos los caracteres de URL prohibidos (especiales) con el signo `%` seguido del valor ASCII hexadecimal del carácter especificado.

## Conversiones

```python
python3 -q
import urllib.parse
urllib.parse.quote("<text>", safe="")
urllib.parse.unquote("<encoded-text>")
```


# Introducción

Hashing es una transformación de datos de entrada de tamaño variable en una salida hexadecimal de tamaño fijo. Esta salida se denomina hash o digest. Lo más trascendental del hashing es que solo funciona en una dirección (unidireccional).&#x20;

Es fácil tomar una entrada arbitraria y producir un hash, pero es difícil tomar un hash y producir la entrada original. Esta propiedad de unidireccionalidad es lo que hace que el hashing sea tan útil.&#x20;

Otra propiedad importante del hashing es que incluso el cambio más pequeño en los datos de entrada puede cambiar en gran medida el hash o digest resultante. Debido a esto, el hashing a menudo se usa para verificar integridad.


# Suma de verificación (checksum)

## Descripción

Las sumas de verificación (checksums) se utilizan para probar la integridad de los datos transmitidos. Si las sumas de verificación calculadas por parte del remitente son las mismas que las calculadas después de la transmisión de datos, significa que los datos transmitidos están intactos.

## Linux/Unix <a href="#validacion-de-integridad-de-archivo-linux-unix" id="validacion-de-integridad-de-archivo-linux-unix"></a>

```shell
# MD5
md5sum <file>
# SHA-1
sha1sum <file>
# SHA-256
sha256sum <file>
# SHA-512
sha512sum <file>
```

Verificación de integridad de archivos.

```shell
echo test1 > test1.txt
echo test2 > test2.txt
echo test3 > test3.txt
md5sum test1.txt test2.txt test3.txt > tests.txt
cat tests.txt
md5sum -c tests.txt
```

Búsqueda de archivo dado una suma de verificación (checksum).

```shell
find / -type f -exec md5sum {} + | tee /tmp/temp.txt | grep <md5-hash>
```

## Windows <a href="#validacion-de-integridad-de-archivo-windows" id="validacion-de-integridad-de-archivo-windows"></a>

```shell
# certutil
## MD5
certutil.exe -hashfile <file> MD5
## SHA-1
certutil.exe -hashfile <file>
## SHA-256
certutil.exe -hashfile <file> SHA256
## SHA-512
certutil.exe -hashfile <file> SHA512

# PowerShell
## MD5
Get-FileHash <file> -Algorithm MD5 | Format-List
## SHA-1
Get-FileHash <file> -Algorithm SHA1 | Format-List
## SHA-256
Get-FileHash <file> | Format-List
## SHA-512
Get-FileHash <file> -Algorithm SHA512 | Format-List
```


# Passwords

## Descripción

Es importante tener en cuenta que, a pesar de la naturaleza unidireccional provista por un algoritmo hash, esto no garantiza que no se pueda recuperar una contraseña dado un hash específico. Un método por el cual podríamos obtener una contraseña dado un hash es mediante el uso de técnicas de fuerza bruta.&#x20;

Dado que no hay forma de revertir el hash a su entrada original, podemos intentar hashear tantas contraseñas diferentes como sea posible utilizando el algoritmo de hash identificado. Comparamos cada hash generado con el que estamos tratando de recuperar y si encontramos una coincidencia, sabremos la contraseña original.

El tiempo en obtener la contraseña dependerá en parte de la fortaleza de la contraseña y el algoritmo de hash utilizado. La fortaleza de una contraseña está dada en función de su longitud y su complejidad. Si queremos hacer una contraseña más fuerte, aumentar su longitud suele tener más utilidad defensiva que aumentar su complejidad. Esto se debe a que cada carácter adicional en la contraseña aumenta exponencialmente el tiempo que lleva aplicar la fuerza bruta. Por el contrario, aumentar el conjunto de caracteres permitidos de una contraseña solo aumenta el tiempo que se tarda en aplicar la fuerza bruta en una cantidad polinomial.

* PIN de 4 caracteres de largo (sólo dígitos 0 al 9)
  * 10^4 = 10.000 intentos
* PIN de 4 caracteres de largo (dígitos 0 al 9 y letras A y B)
  * 12^4 = 20.736 intentos
* PIN de 6 caracteres de largo (sólo dígitos 0 al 9)
  * 10^6 = 1.000.000 intentos

## Linux/Unix

Identificación de tipo de hash.

```shell
hashid <hash>
hash-identifier <hash>
```


# Salt

## Descripción

Un salt es una cadena única generada aleatoriamente que se agrega a cada contraseña como parte del proceso de hashing. Como el salt es único para cada usuario, un atacante tiene que descifrar hashes uno a la vez utilizando el salt respectivo en lugar de calcular un hash una vez y compararlo con cada hash almacenado. Esto hace que descifrar grandes cantidades de hashes sea significativamente más difícil, ya que el tiempo requerido crece en proporción directa a la cantidad de hashes.&#x20;

El salting también permite protegerse contra atacantes que utilicen hashes previamente calculados, como tablas arcoíris (rainbow table) o búsquedas basadas en bases de datos. Además, el salting hace que sea imposible determinar si dos usuarios tienen la misma contraseña sin descifrar los hashes, ya que los diferentes salts darán como resultado hashes diferentes incluso si las contraseñas son las mismas.

Ejemplo de contraseña hasheada sin utilizar salt.

| Descripción | Usuario 1 | Usuario 2 |
| ----------- | :-------: | :-------: |
| Password    |   123456  |   123456  |
| Salt        |     -     |     -     |
| Hash        |  e10adc39 |  e10adc39 |

Ejemplo de contraseña hasheada utilizando salt.

| Descripción | Usuario 1 | Usuario 2 |
| ----------- | :-------: | :-------: |
| Password    |   123456  |   123456  |
| Salt        |    abcd   |    efgh   |
| Hash        |  bc9b5718 |  6bfb3131 |


# Sustitución

## Descripción

El cifrado por sustitución es un método por el que unidades de texto en claro son sustituidas con texto cifrado siguiendo un sistema regular. Las "unidades" pueden ser una sola letra (el caso más común), pares de letras, tríos de letras, mezclas de lo anterior, entre otros. El receptor descifra el texto realizando la sustitución inversa.&#x20;

Los cifrados por sustitución se pueden comparar con los cifrados por transposición. En un cifrado de transposición, las unidades del texto en claro se reorganizan en un orden diferente y, por lo general, bastante complejo, pero las unidades en sí no se modifican. Por el contrario, en un cifrado por sustitución, las unidades del texto en claro se mantienen en la misma ubicación en el texto cifrado, pero las unidades se modifican.

Existen diversos tipos de cifrados por sustitución. Si el cifrado opera sobre letras individuales, se denomina cifrado de sustitución simple; si opera sobre grupos de letras se denomina, poligráfico. Se dice que un cifrado es monoalfabético si usa una sustitución fija para todo el mensaje, mientras que se dice que es polialfabético si usa diferentes sustituciones en diferentes momentos del mensaje. Un tipo especial de cifrado polialfabético son los homófonos, en los que una unidad del texto en claro es sustituida por una de entre varias posibilidades existentes.

## Sustitución simple

### Monoalfabético

#### ROT13

Sustituye cada letra por la letra que está trece posiciones por delante en el alfabeto.

```shell
echo "<text>" | tr 'A-Za-z' 'N-ZA-Mn-za-m'
```


# Simétrico

## Descripción

Los cifrados de clave simétrica usan la misma clave para cifrar el texto en claro (texto sin cifrar) en texto cifrado y para descifrar el texto cifrado de nuevo en texto en claro.&#x20;

La clave, en la práctica, representa un secreto compartido entre dos o más partes que puede ser utilizada para mantener un vínculo de información privada.&#x20;

El requisito de que ambas partes tengan acceso a la clave es uno de los principales inconvenientes del cifrado de clave simétrica. Si esta clave se hiciera pública, cualquiera que la tuviera podría descifrar la información que se intercambió entre las partes. Esto hace que el cifrado de clave simétrica dependa en gran parte de mantener continuamente en secreto la clave.

## Blowfish

```shell
# Encriptar / cifrar
echo "<text>" > blowfish.txt
gpg -c --output blowfish.gpg --cipher-algo blowfish blowfish.txt

# Desencriptar / descifrar
gpg --decrypt blowfish.gpg
```

## Advanced Encryption Standard (AES)

```shell
# Encriptar / cifrar
echo "<text>" > aes256.txt
gpg -c --output aes256.gpg --cipher-algo aes256 aes256.txt

# Desencriptar / descifrar
gpg --decrypt aes256.gpg
```


# Asimétrico

## Descripción

Los cifrados asimétricos, también conocidos como cifrados de clave pública, se caracterizan por utilizar dos claves, una clave pública y otra privada. Cabe señalar que ambas claves están conectadas entre sí, siendo la clave pública la responsable del cifrado y la clave privada del descifrado. El destinatario genera ambas claves y comunica solo la clave pública al emisor del mensaje quien, por su parte, tiene ahora la opción de cifrar el mensaje utilizando la clave pública del destinatario.

Imaginemos que Alice quiere enviar un mensaje cifrado a Bob. Antes de que Alice envíe el mensaje, Bob generará un par de claves asimétricas. Este par de claves consta de dos claves, una clave pública, que Bob puede distribuir libre y ampliamente, y una clave privada, que Bob debe mantener en total confidencialidad.

Bob envía su clave pública a Alice. No necesita preocuparse por la seguridad del canal de comunicación, porque el secreto no es un requisito para las claves públicas. Una vez que Alice tenga la clave pública de Bob, estará lista para cifrar su mensaje y lo hará usando la clave pública de Bob. Alice envía el mensaje a Bob y Bob ahora puede usar su clave privada para descifrarlo.

{% hint style="info" %}
Clave o llave es equivalente. Existiendo por tanto clave o llave privada y clave o llave pública.
{% endhint %}

## GNU Privacy Guard (GPG)

```shell
# Generar un par de claves pública y privada
gpg --gen-key

# Exportar clave pública 
gpg --output example-public.asc --armor --export <uid>

# Encriptar / cifrar
echo "<text>" > asymmetric.txt
gpg --output asymmetric.gpg --recipient <uid> --encrypt asymmetric.txt

# Desencriptar / descifrar
gpg --decrypt asymmetric.gpg
```

## OpenSSL

Generar un par de claves RSA.

```sh
# Generar un par de claves RSA (2048 bit)
openssl genrsa -out key.pem 2048
## clave privada
cat key.pem
## clave publica (visualizar)
openssl rsa -in key.pem -pubout
## clave publica (guardar en archivo)
openssl rsa -in key.pem -pubout > key_pub.pem
```

Encriptar y desencriptar.

```sh
# Generar un par de claves RSA (2048 bit)
openssl genrsa -out key.pem 2048
openssl rsa -in key.pem -pubout > key_pub.pem

# Encriptar / cifrar
echo "<text>" > asymmetric.txt
openssl pkeyutl -encrypt -inkey key_pub.pem -pubin -in asymmetric.txt -out asymmetric.enc

# Desencriptar / descifrar
openssl pkeyutl -decrypt -inkey key.pem -in asymmetric.enc > decrypted.txt
```


