Menú

Mostrar Mensajes

Esta sección te permite ver todos los mensajes escritos por este usuario. Ten en cuenta que sólo puedes ver los mensajes escritos en zonas a las que tienes acceso en este momento.

Mostrar Mensajes Menú

Temas - AlbertoBSD

#46
Migrar una funcion de un lenguaje a otro no debería de ser problema, sin embargo estoy algo atorado con los resultado que me arroja una vez migrado.

En teoria deberia de ser el mismo resultado en ambos casos, sin embargo no es asi.

Codigo en C (Original sin depuracion)

#include<stdio.h>

unsigned short CRC(unsigned char *s, int len, unsigned short crcval);

int main() {
unsigned char *test = "\x01\x55\x00\x00";
printf("CRC: %u\n",CRC(test,4,0));
return 0;
}

unsigned short CRC(unsigned char *s, int len, unsigned short crcval) {
register unsigned c,q;
for (; len; len--) {
c = *s++;
q = (crcval ^ c) & 017;
crcval = (crcval >> 4) ^ (q * 010201);
q = (crcval ^ (c >> 4)) & 017;
crcval = (crcval >> 4) ^ (q * 010201);
}
return (crcval);
}


Codigo en C (Con depuracion)


#include<stdio.h>

unsigned short CRC(unsigned char *s, int len, unsigned short crcval);

int main() {
unsigned char *test = "\x01\x55\x00\x00";
printf("CRC: %u\n",CRC(test,4,0));
return 0;
}

unsigned short CRC(unsigned char *s, int len, unsigned short crcval) {
register unsigned c,q;
printf("Depurando CRC\n");
for (; len; len--) {
printf("len: %i\n",len);
c = *s++;
printf("c: %u\n",c);
q = (crcval ^ c) & 017;
printf("q: %u\n",q);
crcval = (crcval >> 4) ^ (q * 010201);
printf("crcval: %u\n",crcval);
q = (crcval ^ (c >> 4)) & 017;
printf("q: %u\n",q);
crcval = (crcval >> 4) ^ (q * 010201);
printf("crcval: %u\n",crcval);
}
return (crcval);


Salida del codigo en C para el ejemplo Dado:


Depurando CRC
len: 4
c: 1
q: 1
crcval: 4225
q: 1
crcval: 4489
len: 3
c: 85
q: 12
crcval: 50964
q: 1
crcval: 7408
len: 2
c: 0
q: 0
crcval: 463
q: 15
crcval: 63379
len: 1
c: 0
q: 3
crcval: 16122
q: 10
crcval: 42725
CRC: 42725


Codigo en C#

Código (csharp) [Seleccionar]

static void Main(string[] args)
{
byte[] test = new byte[] { 0x01,0x55,0x00,0x00 };
Console.WriteLine("CRC: "+CRC(test,test.Length,0));
}

public static ushort CRC(byte[] s,int len,ushort crcval) {
ulong c, q;
uint i = 0;
while(len > 0)
{
Console.WriteLine("len: "+len);
c = s[i];
Console.WriteLine("c: " + c);
q = (crcval ^ c) & 017;
Console.WriteLine("q: " + q);
crcval = (ushort)(((uint)crcval >> 4) ^ (q * 010201));
Console.WriteLine("crcval: " + crcval);
q = (crcval ^ (c >> 4)) & 017;
Console.WriteLine("q: " + q);
crcval = (ushort)(((uint)crcval >> 4) ^ (q * 010201));
Console.WriteLine("crcval: " + crcval);
len--;
i++;
}
return crcval;
}



Salida del programa en C#


len: 4
c: 1
q: 1
crcval: 10201
q: 17
crcval: 42772
len: 3
c: 85
q: 1
crcval: 11688
q: 1
crcval: 9475
len: 2
c: 0
q: 1
crcval: 9609
q: 1
crcval: 9601
len: 1
c: 0
q: 1
crcval: 9601
q: 1
crcval: 9601
9601


El problema creo que se encuentra en la conversion de variables de 16 bits a 32 bits, pero e tratado de reasignar los valores con ANDS ( & 0xffff) para que queden de 16 bits y ni aun asi funciona.

Alguna ayuda.

Saludos!
#47
Alguno conoce un buen metodo para Sniffear una comunicación Serian entre dos dispositivos mediante puerto RS232?  :huh: :huh:

El punto esta en que estoy realizando Ingeniería Inversa en el protocolo de comunicacion que utilizan 2 dispositivos que se comunican mediante cable serie.

Primero intente utilizar mi computadora como dispositivo intermedio leer todos los datos que manda el HostA y escribirlos hacia el HostB y viceversa.

El programa lo escribi en C# y parecia funcionar bien, vi parte de la comunicación entre los equipos pero llega un punto en el que al parcer por tiempo no se sincroniza bien la comunicación entre ellos y NO SE Comportan los dispositivos de la manera esperada, segun me entere el tiempo de respuesta entre ambos dispositivos no debe de superar los 20 milisegundos entre ellos. Vi el tiempo que tardaba en leer y escribir la información y este supera los 40 milisegundos.

Intente un  programa en C puro y parece ir mas rápido, pero ahora leo información de mas.
Ejemplo.

En el programa en C# leia un byte del host A al host B con valor de 100 y posteriormente leia una respuesta del host B hacia el host A con otro valor X

Y ahora con el programa de C leo hasta 5 bytes continuos con valor 100 cuando realmente conozco de antemano que solo debe de ser un byte con valor 100 seguido de la respuesta.

Alguna sugerencia con otro metodo de snifeo?

Saludos!
#48
Bueno realmente esto me tiene harto.

Tengo unos dias buscando una solucion para realizar la funcion sleep en javascript y que funcione en  Internet Explorer.

Mi solucion anterior fue usar promesas y funciona de maravilla, pero el detalle que tengo unos patrones que no salen de la edad de piedra y siguen usando Internet Explorer, no quieren usar Chrome por nada del mundo.

Solución anterior:

Código (javascript) [Seleccionar]

function sleep(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}


Funciona al 100 en Crome y otros navegadores mas actualizados pero no sirve ni en Internet Explorer 11. Marca error por que no reconoce las parabras para await y async y no reconoce la sintaxis de => para el resolve....

Ahora tome de stack overflow el siguiente código.

https://stackoverflow.com/questions/36016327/how-to-make-promises-work-in-ie11

y NO FUNCIONA

Código (javascript) [Seleccionar]

function sleep(ms) {
    tiempo = ms;
    return new Promise(function(resolve) {
        setTimeout(function() {
            resolve("result");
        }, tiempo);
    });
}



Este si reconoce la sintaxis de la funcione, pero de todos modos sigue marcando error en los async y await.

Ya intente, genera una peticion async = false al Servidor para que el servidor realizare el tiempo de espera, pero no es respetado por los navegadores.

Tambien he intentado y NO FUNCIONA

Código (javascript) [Seleccionar]

      function sleep(delay) {
        var start = new Date().getTime();
        while (new Date().getTime() < start + delay);
      }


Tomado de: https://eureka.ykyuen.info/2011/02/20/javascript-sleep-function/

Alguno de ustedes tiene algo de experiencia con esto.

Saludos!
#49
Conozco el tipo de datos que se están cifrando, y el método de cifrado, tengo acceso a la salida cifrada.

El dato que se esta cifrando es un numero secuencial de 128 bits.

Esto es primero es 1, luego es 2 y asi... aunque no conoco el estado actual de este numero podria ser 1000, 100000  o 8439948 o cualquier otro numero.

La llave es aleatoria y aun que no conozco cual es esta llave, se o creo que esta misma llave es usada para cifrar el siguiente numero. Comento que creo por que no estoy seguro si internamente el algoritmo la cambie.

El Cifrado es rijndael (AES) a 128 bits en modo ECB.

Tengo acceso a una muestra de 65536 Bloques de 128 bits cifrados y los mismos corresponden a los numeros en secuencia de uno en uno.

Alguna idea de conseguir la llave?

Saludos!



#50
Criptografía / Crackear GELI [Infeasible]
14 Septiembre 2017, 19:07 PM
Antes de empezar tengo que comentar que este método es infeasible.

El método podría tardar toda la vida, incluso podría terminarse el universo y no tener la llave para descifrar la Llave maestra para descifrar el disco duro.

Hace unos días publique un post sobre Extraer la información[2]
de cifrado (Metadata Usada por Geli[1]). El post sirve solo para extraer información de metadata para su posterior análisis, de hecho el comando

#geli dump ada0p2

Realiza la misma salida, sin embargo con el programa podemos tener en memoria una copia de la clave cifrada para tratar de crackearla.

Ahora Comento que el programa es infeasible por lo mismo que tardaríamos una eternidad en crackear la clave, posiblemente cuando la clave sea encontrada por mera suerte el disco duro a descifrar ya no exista.

Sin embargo como no he visto ninguna herramienta publica he decidido programar mi propio crack para Discos Duros cifrados con geli.

Métodos de crackeo:


  • Fuerza Bruta a la passphrase mediante diccionario
  • Fuerza Bruta a la clave cifrada


Fuerza Bruta a la passphrase mediante diccionario

La primera opción es incluso mas tardada, pero puede ser que tengamos mas suerte si es que la passphrase escogida por el Sysadmin esta en nuestro diccionario, sin embargo si la palabra no esta en el diccionario es imposible.

En este caso la única limitante es:

Iterations: 218830

En ese caso tarda como 2 segundos en mi equipo realizar el key derivation con esa cantidad de iteraciones. Sin embargo la ultima instalación de FreeBSD que hice, incremente ese numero de iteraciones a 10485760 y tarda aproximadamente u 41 veces mas en realizar el key derivation.

Entonces en un ataque por diccionario tendriamos que pasar nuestra passphrare y derivarla X cantidad de veces, lo cual seria rapido para un X pequeño pero muy tardado para un X muy grande como el mencionado.

Recomendación  para los sysadmin que utilizen este método de cifrado o un cifrado similar, no elegir una clave que se encuentre en algun diccionario, y si pueden configurar el numero de iteracciones, configuren uno muy alto para que sea desalentador tratar de crackear por este medio.

Fuerza Bruta a la clave cifrada

Este metodo tiene como ventaja que se salta la parte de las iteraciones y como desventaja es que prueba todas las combinaciones posibles.

Sin embargo la probabilidad de que encuentre la clave en los primeros años de ejecución son NULAS, sin embargo a largooooo plazo va a terminar encontrado la llave para descifrar la clave maestra para descifrar el disco duro.

El metodo utiliza un archivo para salvar el progreso actual y poder reanudarlo en cualquier otro momento.

En cada iteracion del programa se realizan 2 pruebas para descifrar la clave.



  • Una clave de 64 Bytes que incrementa de uno en uno en cada ciclo
  • Una clave de 64 bytes de un buffer aleatorio

Una clave de 64 Bytes que incrementa de uno en uno.

Esta es la parte que nos da la certeza de que en algun momento podremos encontrar nuestra clave para descifrar ya que probamos todas las combinaciones posibles.

Una clave de 64 bytes de un buffer aleatorio

Posiblemente una perdidad de tiempo, pero si tenemos la suerte de que el buffer aleatorio coincida con la clave para descifrar la clave maestra. entonces podriamos tener la clave antes de tiempo.

Esta ultima parte se puede omitir y incrementariamos nuestro tiempo de finalizacion a un poco menos de la mitad del actual.

Infeasibilidad del metodo

La llave para descifrar la llave maestra es de 64 bytes de longitud, NO 64 Bits, 64 BYTES de longitud (64*8 bits)

Imaginemos el siguiente numero:

13407807929942597099574024998205846127479365820592393377723561443721764030073546976801874298166903427690031858186486050853753882811946569946433649006084095


Un numero decimal de 155 digitos

Entonces por cada prueba que realize nuestro programa tenemos la posibilidad de 1 en Ese numero de que sea nuestra clave de decifrado.

Para los curiosos esta seria la forma de leer el numero de posibilidades

13407   quintovigecillones
,807929 cuatorvigecillones
,942597 trivigecillones
,099574 duovigecillones
,024998 unvigecillones
,205846 vigecillones
,127479 nonidecillones
,365820 octidecillones
,592393 septodecillones
,377723 sextodecillones
,561443 quintodecillones
,721764 cuatordecillones
,030073 tridecillones
,546976 Duodecillones
,801874 Undecillones
,298166 Decillones
,903427 Nonillones
,690031 Octillones
,858186 Septillones
,486050 Sextillones
,853753 Quintillones
,882811 Cuatrillones
,946569 Trillones
,946433 Billones
,649006 Millones
,084095


Aunque tengo dudas de la pronunciacion apartir de los decillones.

El codigo para crackear por fuerza bruta esta en:

https://github.com/albertobsd/geli_metadata/blob/master/crackgeli.c


Si alguien quiere probrar tengo en mi firma un Reto para crackear

Crackeame si puedes Wallet.dat

Saludos!




[1] Extraer informacion de Cifrado
https://foro.elhacker.net/criptografia/extraer_informacion_de_cifrado_en_discoduro_de_freebsd-t474262.0.html

[2] Man page of Eli: https://www.freebsd.org/cgi/man.cgi?query=geli&apropos=0&sektion=8&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
#51
Si estamos usando FreeBSD y queremos cifrar todo nuestro disco duro no duden en preguntar sus dudas.

El comando geli para inicializar la criptografia en nuestro disco duro es el siguiente:

geli init -a hmac/sha256 -b -e AES-XTS -l 256 -s 4096 -i 524288 -B /tmp/USBTEMP/backup_metadata.eli -K /tmp/USBTEMP/da1p1.key da1p1

Obviamente hablamos de una instalacion nueva. No se puede en una instalacion preexistente, a no ser que vallamos a mover toda nuestra informaacion  de un disco duro sin cifrar a algun disco duro cifrado.

Previamente necesitamos crear un archivo "llave" de manera aleatoria con DD

dd if=/dev/random of=/tmp/USBTEMP/da1p1.key bs=4096 iseek=128 count=32

Esto nos genera un archivo de 128 Kilobytes (bs=4096 * count=32) de informacion aleatoria, pasandole este archivo a geli, necesitaremos este archivo cada vez que iniciemos nuestro ordenador, y mas nos vale tener al menos otras 3 copias de seguridad de dicho archivo.

Sumado al archivo en la memoria USB para poder cargar nuestro sistema tendremos:


  • Disco Duro cirado con  AES-XTS y una clave de 256 bits
  • Autenticacion de sectores del disco usando hmac/sha256
  • La Autenticacion con hmac/sha256 Envita que nos ataquen usando Replay
  • Peticion de passphrase Antes de montar el Disco Duro principal
  • El passphare es juntado con el salt y nuestro archivo de 128 Kilobytes y derivado 524288 veces para poder descifrar la clave maestra previamente cifrada y guardada en la metadata

La unica desventaja que le veo a esta implementacion es:


  • Disminucion del Performance al momento de Leer/Escribir informacion en el disco ya que todo es cifrado.
  • Lo anterior pordria ser mitigado Teniendo algun Hardware acelarador para operaciones criptograficas y un Disco Duro de Estado solido.
  • Disminucion de Capacidad de almacenamiento, Dado que estamos usando un sistema de Autenticacion, este necesita guardar los checksum de cada sector de disco para determinar que no han sido modificados por terceros
  • Ejemplo de lo Anterior un Disco Duro de 22 Gigabytes termina con capacidad de 19 GB. Pierde al rededor de 14% de Almacenamiento dedicado para la Autenticacion de la información

Saludos!


Source: https://albertobsd.blogspot.mx/2017/09/recomendacion-para-disco-duro-cifrado.html
#52
Extraer informacion de Cifrado en DiscoDuro de FreeBSD

FreeBSD ofrece la opcion de cifrar completamente el disco duro. La principal herramienta es Geli[2].

Para ver la información sobre el cifrado del disco, OJO no la información cifrada, sino la información relacionada con el tipo y modo de cifrado usado para el disco duro en cuestion, es necesario primero obtener acceso fisco al disco, una en otra instalación con FreeBSD podemos extraer el sector que tiene la meta-data a analizar, este sector del disco duro (512 Bytes) se encuentra en el ultimo sector de la particion cifrada.

Si no sabemos cual particion es la particion cifrada podemos extraer el ultimo sector de todas la particiones de el disco duro.

Ejemplo:

Discoduro a analizar /dev/da1

Si listamos /dev/da1* podremos ver que tiene 2 particiones para este caso en particular

# ls /dev/da1*
/dev/da1p1
/dev/da1p2

Para extraer la informacion tenemos que usar el comando dd.

Tambien necesitamos saber cuanto espacio tiene el disco duro

# geom disk list
o
# gpart list

Ejemplo de salida:

Providers:
1. Name: da1p1
   Mediasize: 20401094656 (19G)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 32768
   Mode: r1w1e1
   rawtype: 7
   length: 20401094656
   offset: 0
   type: freebsd-ufs
   index: 1
   end: 39845887
   start: 0
2. Name: da1p2
   Mediasize: 1073708032 (1.0G)
   Sectorsize: 512
   Stripesize: 0
   Stripeoffset: 3221258240
   Mode: r1w1e0
   rawtype: 1
   length: 1073708032
   offset: 20401094656
   type: freebsd-swap
   index: 2
   end: 41942973
   start: 39845888


Para este ejemplo la particion tiene 20401094656 con lo cual si dividimos entre 512 nos da un total 39845888 Sectores con lo cual el ultimo sector valido es 39845887 que el que tenemos que leer, entonces el comando para extraer dicho sector es:

# dd if=/dev/da1p1 of=./sector.backup bs=512 iseek=39845887 count=1

Si nuestros calculos fueron acertados tendremos un archivo llamado sector.backup de 512 bytes.

El contenido de ese archivo puede variar mucho dependiendo del estado previo del disco duro.

Si el disco duro esta cifrado con mediante geli el archivo empezara con la siguiente leyenda:

GEOM::ELI, lo restante es informacion en binario con el siguiente orden

struct g_eli_metadata {
char  md_magic[16]; /* Magic value. */
uint32_t md_version;  /* Version number. */
uint32_t md_flags;  /* Additional flags. */
uint16_t md_ealgo;  /* Encryption algorithm. */
uint16_t md_keylen;  /* Key length. */
uint16_t md_aalgo;  /* Authentication algorithm. */
uint64_t md_provsize; /* Provider's size. */
uint32_t md_sectorsize; /* Sector size. */
uint8_t  md_keys; /* Available keys. */
int32_t  md_iterations; /* Number of iterations for PKCS#5v2. */
uint8_t  md_salt[G_ELI_SALTLEN]; /* Salt. */
   /* Encrypted master key (IV-key, Data-key, HMAC). */
uint8_t  md_mkeys[G_ELI_MAXMKEYS * G_ELI_MKEYLEN];
u_char  md_hash[16]; /* MD5 hash. */

} __packed;

Me tome la molestia de Generar una herramienta en C que lee la informacion y le pasa las funciones existentes en el codigo fuente de geli para organizar el buffer acorde al formato de la estructura.

El programa puede ser visto en mi cuenta de github[3] si lo compilamos y ejecutamos pasandole como parametro el archivo de 512 bytes tendremos una salida similar a la siguiente [Algunos datos fuero cambiados]:

albertobsd@XHGC-VMBox:~ % ./eli_metadata sector.backup
Magic: GEOM::ELI
Version: 7
Flags: 2
E ALGO: 22
Key Length: 128
A Algo: 0
P Size: 23622320128
Sector Size: 4096
Avaible Keys: 1
Iterations: 218830
Salt: E8CF4BB53DA62DC60B8CAD36119D62B806D95524828286533728C4045E319DBBA1486522EA0454887E1094AD3FAFA0295E9350F1259AAC4B791D42A02F3A6BF2
Master Key: 3F4E170DAFF6539E9301EEF2840ED233BA3B84D02EB96
3AEBB0CA1EED891034A85A3BB325F7B09398706944DFE84CE4748D2C4F0E1FEA4FD601CC18A922ADE51C9D7DC740292A979153B744FC49F47956E24E23D64BFF854F04E3AD41C39215D834DF5E317FF9C1661D9B3300E40D85CE4C270BF57DD1AA82489A97F6741A119AF25D1987ED584E1585FD7ADAE7406D9119AC7AEE654DA2B9C28D2D39599593E1B751BAE614C921E814660E240D18B7650477E935941299F7D34C91350BD289902B7F7DF23D7523C1B6FC0AB33CAB3AF07E5EA0E97835EF13F31B1F56004A552F074951D8B490FEA605D449E2AEA774574BDFEE9153392E4084DF934FCA40638B676A868E3BAB8CA0E0A1912B348C645F74BCA3AB7D697053DD25107981086284F687D1D5EF1DA16280EE7CD0920A92CDAFAF7970D084C4C344FAB3117D0993A591AA43B1D09BE6D5AFB12C82C375BD980AC60F7E0A65C146F8E54E1D84FA0D73933EC26341E5B1D11BA14AF8FA3990F834C4FA39BEF17EECCE206670E5E854B

MD5: BD5DA8BAE0C0C6AAC7503769A3CE9110


Datos interesantes de la salida:

E ALGO: 22

Podemos ver en
/usr/src/sys/opencrypto/cryptodev.h

#define CRYPTO_AES_XTS  22

Que esta cifrado usando AES_XTS que segun [4] es el estandar recomenado para el cifrado de disco.


Key Length: 128

El cifrado usa una Llave de 128 bits, se podria configurar a 256 para un mejor cifrado.

A Algo: 0

El sistema no tiene Autenticacion, esto quiere decir que no se tiene forma de saber si la informacion que leemos del disco a sido modificada o sobreescirta por terceros, esto tambien da lugar a un ataque tipo replay para poder calcular la clave maestra

Avaible Keys: 1

El sistema solo tiene una llave maestra lo cual si se nos olvida nuestra "passphrase" o se nos pierden nuestras llaves tendremos muy pocas (NULAS) posibilidades de recuperar nuestra informacion

Iterations: 218830

Nuestra "passphrase" junto con el Salt y nuestros Keyfiles si existen es derivada 218830 veces mediante pkcs5v2_genkey en g_eli.c y el resultado de esta operacion se usa para descifrar la llave encripada en.

Master Key: 3F4E170DAFF6539E9301EEF2840ED233BA3B84D02EB96
3AEBB0CA1EED891034A85A3BB325F7B09398706944DFE84CE4748D2C4F0E1FEA4FD601CC18A922ADE51C9D7DC740292A979153B744FC49F47956E24E23D64BFF854F04E3AD41C39215D834DF5E317FF9C1661D9B3300E40D85CE4C270BF57DD1AA82489A97F6741A119AF25D1987ED584E1585FD7ADAE7406D9119AC7AEE654DA2B9C28D2D39599593E1B751BAE614C921E814660E240D18B7650477E935941299F7D34C91350BD289902B7F7DF23D7523C1B6FC0AB33CAB3AF07E5EA0E97835EF13F31B1F56004A552F074951D8B490FEA605D449E2AEA774574BDFEE9153392E4084DF934FCA40638B676A868E3BAB8CA0E0A1912B348C645F74BCA3AB7D697053DD25107981086284F687D1D5EF1DA16280EE7CD0920A92CDAFAF7970D084C4C344FAB3117D0993A591AA43B1D09BE6D5AFB12C82C375BD980AC60F7E0A65C146F8E54E1D84FA0D73933EC26341E5B1D11BA14AF8FA3990F834C4FA39BEF17EECCE206670E5E854B

El archivo termina con un MD5 Checksum de los valores en binario previamente mostrados, solo para validar que la información sea correcta.

Si es posible usar la información contenida en el archivo para Atacar por fuerza bruta y obtener la Clave Maestra decifrada pero en computacionalmente casi imposible de realizar.

[1] Original Post: https://albertobsd.blogspot.mx/2017/09/extraer-informacion-de-cifrado-en.html
[2] Man page of Eli: https://www.freebsd.org/cgi/man.cgi?query=geli&apropos=0&sektion=8&manpath=FreeBSD+11.1-RELEASE&arch=default&format=html
[3] Herramienta Utilizada: https://github.com/albertobsd/geli_metadata
[4] https://en.wikipedia.org/wiki/Disk_encryption_theory
#53
Dejen de usar rand() en C/C++ o los van a HACKEAR  :silbar:

Obviamente nadie usa la funcion rand() en programas del mundo real, ¿o si?

No se si colocar esto aqui o en criptografia o hacking. El tema trata de atacar una implementacion DEBIL de numeros random.

El ataque no es complejo, para el ejemplo mostrado pero muestra el peligro de las aplicaciones que usan numeros aleatorios debiles o predecibles.

Hace mas de una año en el foro publique un pequeño codigo del Juego Piedra Papel y Tijera: [Aporte] Piedra Pape y Tijera - Mini-Autómata + Ejercicio [1]

En ese ejemplo como originalmente lo hice para un video tutorial use por comodidad la funcion rand() que viene por defecto en las librerias estandar de muchas implementaciones y para no meter a los que se estan iniciando en temas de seguridad complejos, decidi usar esa funcion sabiendo que no es tan segura. Sin embargo no me habia dado cuenta de la gravedad de los numeros arrojados por rand aun inicializando con la semilla del tiempo. En cualquier caso lo numeros que arroja se pueden calcular usando la misma funcion rand()  :xD

En un entorno donde no se tiene acceso al codigo fuente de un programa, es posible (dependiendo de lo que el programa realize) tratar de adivinar que procesos internos realiza el programa en especial cuando involucra numeros aleatorios.

Veamos el ejemplo del piedra papel y tijera:

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>

char *cadenas[] = {"Piedra","Papel","Tijera"};

//0 empate
//1 Pierde Usuario
//2 Gana Usuario
//Filas Computadora
//Columas Usuario

char tabla_resultados[3][3] =
{
{0,2,1},
{1,0,2},
{2,1,0}
};

char *resultado[] = {"Empate","Gana la COMPUTADORA","Gana el USUARIO"};

int main() {
char buffer[10];
char *error = NULL;
bool entrar = true;
bool jugado = false;
int usuario = 0;
int computadora = 0;
srand(time(NULL));
do {
computadora = rand() % 3;
do { //Entramos en este ciclo hasta que el usuario juege o decida salir para no afectar el valor rand del ejemplo
printf("1) Piedra\n");
printf("2) Papel\n");
printf("3) Tijera\n\n");
printf("S) Salir\n\n");
printf("Seleccione una opcion:");
fgets(buffer,5,stdin);
usuario = (int) strtol(buffer,&error,10);
if(error[0] == 's' || error[0] == 'S') {
entrar = false;
jugado = true;
}
else{
if(usuario <=3 && usuario >= 1){
usuario--; //Le restamos uno al input para poder usarlo en una tabla de estados con index 0
jugado = true;
printf("Usuario %s vs Computadora %s\n",cadenas[usuario],cadenas[computadora]);
printf("Resultado: %s\n",resultado[tabla_resultados[computadora][usuario]]);
}
else {
printf("Seleccione una opcion correcta\n");
jugado = false;
}
}
}while(!jugado);
}while(entrar);
}



Veamos las partes importantes:

srand(time(NULL));

Se inicializa el random con la semilla del tiempo como lo haria cual quier persona que esta aprendiendo a programar con numeros aleatorios.
El codigo mostrado lo escribi para compilarlo con GCC pero deberia de funcionar en otros compiladores de C sin muchos cambios.

computadora = rand() % 3;

La computadora usa funcion rand() y le aplica modulo al resultado para obtener valores validos del 0 al 2.

Pues bien para ejemplo es todo lo que necesitamos saber. Bajo la premisa de que el/los programas usan la semilla del tiempo actual en Segundos desde el primero de enero de 1970 [2]

Entonces en otro programa de C podemos buscar todas las semillas de tiempo en un rango determinado y obtener primeras salida de cada una de ellas.

Ejemplo tomemos la fecha de hoy en el formato devuelto por la funcion time(), desde [3] lo podemos obtener para hoy es:

1503838078

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>

int main() {
int i = 0;
int resultado = 0;
srand(1503838078);
while(i < 10) {
resultado = rand() % 3;
printf("Resultado: %i\n",resultado);
i++;
}
}



Salida


% ./testrand
Resultado: 2
Resultado: 0
Resultado: 0
Resultado: 1
Resultado: 1
Resultado: 1
Resultado: 2
Resultado: 0
Resultado: 0
Resultado: 1

% ./testrand
Resultado: 2
Resultado: 0
Resultado: 0
Resultado: 1
Resultado: 1
Resultado: 1
Resultado: 2
Resultado: 0
Resultado: 0
Resultado: 1


Como vemos la salida del programa es la misma en ambas ocasiones aunque se ejecuta con segundos de diferencia, posiblemente esto le paso a alguien que uso rand sin inicializar el srand, pero no le dio importancia.

¿Ahora que?

El hecho es que podemos reinicializar srand en cualqueir momento del codigo y la salida de rand va a ser la correspondiente a cada semilla ejemplo:

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>

int main() {
int i = 0;
int resultado = 0;
srand(1503838078);
while(i < 5) {
resultado = rand() % 3;
printf("Resultado: %i\n",resultado);
i++;
}
srand(1503838079);
i = 0;
while(i < 5) {
resultado = rand() % 3;
printf("Resultado: %i\n",resultado);
i++;
}
srand(1503838078);
i = 0;
while(i < 5) {
resultado = rand() % 3;
printf("Resultado: %i\n",resultado);
i++;
}
}



Noten el cambio de srand de 1503838078 -> 1503838079 -> 1503838078 por lo cual la primeras 5 salidas van a ser iguales a las 15 ultimas


Salida


% ./hackrand
Resultado: 2
Resultado: 0
Resultado: 0
Resultado: 1
Resultado: 1
Resultado: 0
Resultado: 2
Resultado: 0
Resultado: 2
Resultado: 1
Resultado: 2
Resultado: 0
Resultado: 0
Resultado: 1
Resultado: 1


Ya con esta salida sabemos que podemos calcular cualquier salida de rand() en cualquier momento conociendo o calculando la semilla inicial

Pues bien es momento de ganarle al Piedra papel y tijera perdiendo  solo los primeros 2 o 3 juegos y en base a estos tratar de calcular cual fue la semilla utilizada.

Hice un programa que que te muestra las salidas de rand ya con X modulo de las semillas +/- 10 al tiempo actual y apartir de ahi elijes cual semilla continuar viendo Y asi sabremos que jugada va a hacer la computadora  antes de tiempo y poderle ganar:

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<time.h>


int main(int argc, char **argv) {
bool entrar,continuar,seleccione;
char buffer[10];
char *error = NULL;
unsigned int tiempo = 0;
unsigned int base = 0;
int numero = 0;
int resultado = 0,i = 0,j = 0;
int divisor = 0;
if(argc == 2) {
divisor = (int )strtol(argv[1],&error,10);
if(error[0] == 0) {
tiempo = time(NULL);
printf("Valor actual del tiempo %u\n",tiempo);
printf("Calculando modulos en +/- 10\n");
base = tiempo -10;
j = 0;
while( ( base + j) < (tiempo +10)) {
srand(base + j);
printf("Opcion %i:",j+1);
i = 0;
while(i < 10) {
resultado = rand() % divisor;
printf(" %i,",resultado);
i++;
}
printf("\n");
j++;
}
printf("Opcion S: Salir\n");
do {
seleccione = false;
printf("Seleccione una opcion:");
fgets(buffer,5,stdin);
numero = (int)strtol(buffer,&error,10);
if(error[0] == 's' || error[0] == 'S') {
entrar = false;
}
else {
if(numero >= 1 && numero <= 20) {
continuar = true;
numero--; //Restamos para compensar el +1 en el menu
srand(base + numero);
i = 0;
while(i < 10) {
resultado = rand();
i++;
}
printf("Numeros siguientes en la secuencia seleccionada\n");
do {
i = 0;
while(i < 5) {
resultado = rand() % divisor;
printf("%i, ",resultado);
i++;
}
printf("\n");
printf("+) Imprimir mas numeros\n");
printf("S) Salir\n\n");
printf("Seleccione: ");
fgets(buffer,5,stdin);
switch(buffer[0]) {
case 's':
case 'S':
continuar = false;
break;
case '+':
continuar = true;
break;
}
}while(continuar);
}
else {
seleccione = true;
}
}
}while(seleccione);
}
}
else {
printf("Usar: %s <divisor>\n",argv[0]);
}
}


Ejecitamos el programa para forcebrutear el srand con el parametro del modulo que estan aplicando:

% ./crack_rand.exe 3
Valor actual del tiempo 1503839464
Calculando modulos en +/- 10
Opcion 1: 2, 0, 0, 0, 0, 1, 2, 1, 0, 1,
Opcion 2: 2, 0, 0, 1, 1, 1, 0, 2, 1, 0,
Opcion 3: 2, 0, 1, 2, 2, 0, 2, 0, 0, 2,
Opcion 4: 0, 2, 0, 0, 0, 0, 1, 1, 1, 1,
Opcion 5: 0, 2, 0, 1, 1, 0, 0, 1, 1, 2,
Opcion 6: 0, 2, 2, 2, 2, 0, 1, 2, 1, 1,
Opcion 7: 0, 2, 2, 0, 0, 2, 2, 0, 1, 0,
Opcion 8: 1, 1, 1, 1, 0, 2, 1, 1, 1, 2,
Opcion 9: 1, 1, 2, 2, 2, 0, 2, 0, 2, 1,
Opcion 10: 1, 1, 1, 0, 2, 0, 1, 1, 2, 2,
Opcion 11: 1, 0, 1, 1, 0, 2, 2, 2, 2, 1,
Opcion 12: 2, 1, 0, 0, 1, 2, 1, 2, 2, 0,
Opcion 13: 2, 0, 0, 0, 2, 2, 2, 0, 2, 2,
Opcion 14: 2, 2, 0, 1, 0, 1, 1, 1, 2, 0,
Opcion 15: 2, 0, 0, 0, 0, 1, 0, 2, 0, 1,
Opcion 16: 0, 2, 0, 1, 2, 1, 2, 2, 2, 0,
Opcion 17: 0, 2, 2, 1, 2, 2, 0, 0, 0, 2,
Opcion 18: 0, 2, 2, 0, 0, 1, 1, 1, 2, 1,
Opcion 19: 1, 1, 1, 1, 2, 1, 0, 2, 0, 0,
Opcion 20: 1, 1, 2, 1, 2, 1, 1, 1, 2, 2,
Opcion S: Salir
Seleccione una opcion:


Ejecutamos el progrma de priedra papel o tijera y si bien muchas veces no tenemos acceso al codigo fuente, hay cosas que se pueden determinar  con un poco de imaginacion y conocimientos de programacion.

% ./ppt
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:1
Usuario Piedra vs Computadora Piedra
Resultado: Empate
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:1
Usuario Piedra vs Computadora Tijera
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:1
Usuario Piedra vs Computadora Tijera
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:1
Usuario Piedra vs Computadora Piedra
Resultado: Empate
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:2
Usuario Papel vs Computadora Piedra
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:3
Usuario Tijera vs Computadora Papel
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:3
Usuario Tijera vs Computadora Papel
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:3
Usuario Tijera vs Computadora Papel
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:1
Usuario Piedra vs Computadora Tijera
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:3
Usuario Tijera vs Computadora Papel
Resultado: Gana el USUARIO
1) Piedra
2) Papel
3) Tijera

S) Salir

Seleccione una opcion:



Despues de los primeros intentos del programa: podemos darnos cuenta que la secuencia que se esta jugando es la 7 o la 18 del ejemplo


Opcion 7: 0, 2, 2, 0, 0, 2, 2, 0, 1, 0,
Opcion 18: 0, 2, 2, 0, 0, 1, 1, 1, 2, 1,


Y vemos que en los ultimos juegos Gane todos los piedra papel tijera que jugue.

Si bien es cierto que sin el codigo fuente o binario decompilado no es podible saber la cantidad de veces que se llama a la funcion rand antes de que realmente inicie el programa, si es posible calcular  incluso darnos cuenta de que podemos tener una base de datos o programa que calcule los modulos adecuados y tarde o temprano sabremos que semilla se utilizo para el caso de srand

Espero que dejen de usar srand y rand, buscando alguna funcion mas segura, si estan en Linux o un sistema libre, tendran siempre un /dev/random con bastantes numeros aleatorios muy dificiles de predecir.


¿Que alcance tiene esto?

Existen maquinas de juego electronico (bingo,loteria, balckjack) que utilizan funciones aleatorias y podria ser posible que alguna utilize rand() % X para algunos de sus calculos. Digo estas maquinas por que es probable que sus programadores se preocupen menos por la calidad de numeros generado, en maquinas de azar solo importa que los numeros sean uniformes (Todos con la misma probabilidad de salir) esto con el objetivo de calcular tablas de pagos adecuadas para la probabilidad de cada maquina.

Y pues temas se seguridad informatica como la generacion de passwords y otros usos de los numeros PseudoAlearorios, es recomendable buscar fuentes no predecibles de estos.

[1] https://foro.elhacker.net/programacion_cc/aporte_piedra_pape_y_tijera_miniautomata_ejercicio-t454850.0.html
[2] https://www.freebsd.org/cgi/man.cgi?query=time&sektion=3
[3] https://www.epochconverter.com/
#54
Criptografía / Intel Secure Key RNG ¿Seguro?
26 Agosto 2017, 16:42 PM
Un poco de Background antes de empezar.

¿Que es un RNG?

Segun Wikipedia[1]: Random Number Generation, es el proceso de crear una secuencia de numeros o simbolos que no deben de ser predecibles.

Importancia de numeros Aleatorios

Para entender la importancia de los numeros aleatorios tenemos que preguntarnos ¿Donde utilizamos numeros Aleatorios?

Segun Schneier B. (2000)  Yarrow-160: Notes on the Design and Analysis of the Yarrow Cryptographic Pseudorandom Number Generator recuperado de [2]

Los numeros Aleatorios en Criptografia son usados por


  • Sesiones y llaves de mensajes para algoritmos de cifrado simetrico como tripe-Des Blowsh
  • Como semillas para rutinas que generan valores matematicos como numeros primos muy grandes para RSA
  • Saltos de password para frustrar ataques por fuerza bruta fuera de linea
  • Vectores de Inicializacion (IV) para bloques de algoritmos de cidrado (AES CBC, ECB etc)
  • Valores Aleatorios para Firmas Digitales de Cifrado como  DSA
  • Desafios Aleatorios en protocolos de Autenticacion como Kerberos
  • "Nonces" para protocolos y garantizar que cada ejecucion es unicia SSL

Me tome la molestia de traducir y agregar toda la lista para ejemplificar que el uso de numeros aleatorios es muy basto y mas comun de lo que piensan, cada que entran a una pagina web con SSL activado se generan numeros aleatorios.

Ahora ya con este Background sobre los RNG y el uso de numeros aleatorios en cryptogradia es posible  entrar en el Tema del Post

¿Que es el "Intel Secure Key RNG"?

Si bien por el nombre podriamos pensar que alguna especie de Llave USB o alguna pienza sofisticada de Hardware, pues estamos en un error!!
El mencionado Intel Secure Key RNG no es nada mas que una Instruccion nueva para procesadores modernos de Intel la cual nos devuelve valores aleatorios Generados directamente por el procesador [3]

Esto es Genial ya que en teoria le quita la Carga al Sistema Operativo de Generar Numeros Aleatorios utilizando algoritmos pesados
¿O no?

Pues bien dada la desconfianza que existe hacia cualquier implentacion del tipo privado, debido a debilidades y/o backdoors documentados. Los sistemas operativos modernos no toman estos "sources" de numeros aleatorios para servirlos directamente a las aplicaciones que soliciten numeros aleatorios, sino que los pasan atraves de algun algoritmo adicional y finalmente sirven sus propios numeros generados.

Esto lo hacen con el objetivo de elimiar cualquier rastro de backdoor que pueda existir.

La instruccion rdrand es usada por sistemas como Linux[4] y FreeBSD[5]  entre otros para  sus plataformas de Intel. Y como se menciono no la usan como valor directo, si no como uno de tantos origenes de Entropia para sus algoritmos de /dev/random

Personalmente he trabajado con el Kernel de FreeBSD y he visto en el codigo[6] el uso de la instruccion rdrand.

Entonces que formas tenemos para analizar si la salida directa de rdrand es segura.

Repasemos las caracteristicas que debe tener un RNG, segun [3]

  • Cada valor nuevo debe de ser estadisticamente independiente del anterior
  • La distribucion de todos los numeros generados debe de ser Uniforme
  • La secuencia debe de ser impredecible

Entonces para la comparacion usare varias muestras de 1MB del Disposivo random estandar del sistema, Para este ejemplo /dev/random de FreeBSD 11.1 RELEASE contra varias muestras de 1MB de la salida devuelta directamente por rdrand.

Para hacer esto lo mas amigable posible desarrolle un modulo para el kernel de FreeBSD [7] que al igual que /dev/random, nos genera un device /dev/rdrand que nos devuelve un stream de numeros aleartorios pero en esta ocacion tomados directamente de la instruccion rdrand para procesadores Ivy Bridge.

Codigo para generar un archivo de muestra:


dd if=/dev/random of=~/random.test count=1 bs=1M
dd if=/dev/rdrand of=~/rdrand.test count=1 bs=1M


Asi mismo desarrolle un programa que lee un archivo y cuenta el numero de veces que aparece cada valor en dicho archivo:


Salida del primer archivo
Abriendo ./random.test
Valor 0: 4161
Valor 1: 4307
Valor 2: 3964
Valor 3: 4124
Valor 4: 4076
Valor 5: 4032
Valor 6: 4031
Valor 7: 4152
Valor 8: 4146
Valor 9: 4078
Valor 10: 4155
Valor 11: 4121
Valor 12: 4144
Valor 13: 4117
Valor 14: 4180
Valor 15: 3984
Valor 16: 4113
Valor 17: 4188
Valor 18: 4069
Valor 19: 4127
Valor 20: 3980
Valor 21: 4019
Valor 22: 3959
Valor 23: 4067
Valor 24: 4054
Valor 25: 4124
Valor 26: 4123
Valor 27: 4070
Valor 28: 4151
Valor 29: 4178
Valor 30: 4115
Valor 31: 4117
Valor 32: 4119
Valor 33: 4090
Valor 34: 4120
Valor 35: 4126
Valor 36: 4053
Valor 37: 4055
Valor 38: 4084
Valor 39: 4048
Valor 40: 4137
Valor 41: 4125
Valor 42: 4029
Valor 43: 4060
Valor 44: 4077
Valor 45: 4128
Valor 46: 4205
Valor 47: 3959
Valor 48: 4082
Valor 49: 4019
Valor 50: 4034
Valor 51: 4107
Valor 52: 4125
Valor 53: 4112
Valor 54: 4050
Valor 55: 4011
Valor 56: 4087
Valor 57: 4071
Valor 58: 4039
Valor 59: 4095
Valor 60: 4093
Valor 61: 4088
Valor 62: 4091
Valor 63: 4006
Valor 64: 4081
Valor 65: 4047
Valor 66: 4102
Valor 67: 4138
Valor 68: 4106
Valor 69: 4019
Valor 70: 4167
Valor 71: 4118
Valor 72: 4145
Valor 73: 4216
Valor 74: 4129
Valor 75: 4210
Valor 76: 4188
Valor 77: 4079
Valor 78: 4130
Valor 79: 4156
Valor 80: 4129
Valor 81: 4075
Valor 82: 4069
Valor 83: 4097
Valor 84: 4113
Valor 85: 4034
Valor 86: 4107
Valor 87: 3944
Valor 88: 4084
Valor 89: 4310
Valor 90: 4082
Valor 91: 4075
Valor 92: 4110
Valor 93: 4113
Valor 94: 4063
Valor 95: 4133
Valor 96: 4207
Valor 97: 4031
Valor 98: 4166
Valor 99: 4009
Valor 100: 4249
Valor 101: 4076
Valor 102: 4155
Valor 103: 4051
Valor 104: 4052
Valor 105: 4115
Valor 106: 4157
Valor 107: 4013
Valor 108: 4093
Valor 109: 4076
Valor 110: 4126
Valor 111: 4156
Valor 112: 4099
Valor 113: 4079
Valor 114: 4049
Valor 115: 4125
Valor 116: 4018
Valor 117: 3990
Valor 118: 4014
Valor 119: 4114
Valor 120: 4058
Valor 121: 4086
Valor 122: 4016
Valor 123: 4034
Valor 124: 3991
Valor 125: 4044
Valor 126: 4224
Valor 127: 4047
Valor 128: 4189
Valor 129: 4160
Valor 130: 4056
Valor 131: 4073
Valor 132: 4009
Valor 133: 4154
Valor 134: 4163
Valor 135: 4130
Valor 136: 4108
Valor 137: 4226
Valor 138: 4099
Valor 139: 4198
Valor 140: 4004
Valor 141: 4037
Valor 142: 4139
Valor 143: 4129
Valor 144: 4085
Valor 145: 4211
Valor 146: 4036
Valor 147: 4010
Valor 148: 4136
Valor 149: 4167
Valor 150: 4135
Valor 151: 4100
Valor 152: 4061
Valor 153: 4115
Valor 154: 4022
Valor 155: 4074
Valor 156: 4164
Valor 157: 3978
Valor 158: 3999
Valor 159: 4041
Valor 160: 4094
Valor 161: 4003
Valor 162: 4008
Valor 163: 4063
Valor 164: 4200
Valor 165: 4202
Valor 166: 4192
Valor 167: 3978
Valor 168: 4120
Valor 169: 4133
Valor 170: 4204
Valor 171: 4176
Valor 172: 4100
Valor 173: 4092
Valor 174: 4109
Valor 175: 4071
Valor 176: 4091
Valor 177: 4067
Valor 178: 4044
Valor 179: 4070
Valor 180: 4024
Valor 181: 4012
Valor 182: 4130
Valor 183: 4062
Valor 184: 4096
Valor 185: 4092
Valor 186: 4110
Valor 187: 4031
Valor 188: 3931
Valor 189: 4065
Valor 190: 4156
Valor 191: 4167
Valor 192: 4033
Valor 193: 4176
Valor 194: 4000
Valor 195: 4174
Valor 196: 4054
Valor 197: 4126
Valor 198: 4121
Valor 199: 4089
Valor 200: 4154
Valor 201: 4192
Valor 202: 4087
Valor 203: 4164
Valor 204: 4176
Valor 205: 4134
Valor 206: 4082
Valor 207: 4103
Valor 208: 4234
Valor 209: 4022
Valor 210: 3978
Valor 211: 4188
Valor 212: 4104
Valor 213: 4168
Valor 214: 4005
Valor 215: 4065
Valor 216: 4118
Valor 217: 4102
Valor 218: 4108
Valor 219: 4077
Valor 220: 4094
Valor 221: 3951
Valor 222: 4078
Valor 223: 4005
Valor 224: 4012
Valor 225: 4131
Valor 226: 4190
Valor 227: 4058
Valor 228: 4036
Valor 229: 4111
Valor 230: 4137
Valor 231: 4000
Valor 232: 4175
Valor 233: 4164
Valor 234: 4253
Valor 235: 4067
Valor 236: 4081
Valor 237: 4037
Valor 238: 4116
Valor 239: 4155
Valor 240: 4137
Valor 241: 4025
Valor 242: 4052
Valor 243: 4140
Valor 244: 4132
Valor 245: 4115
Valor 246: 4063
Valor 247: 3924
Valor 248: 4174
Valor 249: 4098
Valor 250: 4115
Valor 251: 4105
Valor 252: 4083
Valor 253: 4138
Valor 254: 4152
Valor 255: 4098


Salida del segundo archivo

Abriendo ./rdrand.test
Valor 0: 4043
Valor 1: 4055
Valor 2: 4191
Valor 3: 4058
Valor 4: 4125
Valor 5: 4087
Valor 6: 4090
Valor 7: 4150
Valor 8: 4007
Valor 9: 4139
Valor 10: 4027
Valor 11: 4054
Valor 12: 4059
Valor 13: 4167
Valor 14: 4024
Valor 15: 4115
Valor 16: 4045
Valor 17: 4135
Valor 18: 4007
Valor 19: 3980
Valor 20: 4169
Valor 21: 4131
Valor 22: 3997
Valor 23: 4051
Valor 24: 4223
Valor 25: 4110
Valor 26: 4185
Valor 27: 4109
Valor 28: 4052
Valor 29: 4093
Valor 30: 4108
Valor 31: 4163
Valor 32: 4119
Valor 33: 4129
Valor 34: 4180
Valor 35: 4061
Valor 36: 4010
Valor 37: 4082
Valor 38: 4104
Valor 39: 4116
Valor 40: 4080
Valor 41: 4191
Valor 42: 4061
Valor 43: 4103
Valor 44: 4249
Valor 45: 4165
Valor 46: 4043
Valor 47: 4187
Valor 48: 4121
Valor 49: 4141
Valor 50: 4113
Valor 51: 4093
Valor 52: 4177
Valor 53: 3970
Valor 54: 4195
Valor 55: 4156
Valor 56: 4065
Valor 57: 4171
Valor 58: 4113
Valor 59: 4041
Valor 60: 4128
Valor 61: 4189
Valor 62: 4067
Valor 63: 4102
Valor 64: 4063
Valor 65: 4143
Valor 66: 4041
Valor 67: 4029
Valor 68: 4085
Valor 69: 4074
Valor 70: 4053
Valor 71: 4160
Valor 72: 4130
Valor 73: 4179
Valor 74: 4154
Valor 75: 4060
Valor 76: 4073
Valor 77: 4086
Valor 78: 4137
Valor 79: 4107
Valor 80: 4053
Valor 81: 4172
Valor 82: 4120
Valor 83: 4072
Valor 84: 3953
Valor 85: 4116
Valor 86: 4042
Valor 87: 4218
Valor 88: 4082
Valor 89: 3955
Valor 90: 4034
Valor 91: 4055
Valor 92: 4120
Valor 93: 4102
Valor 94: 3953
Valor 95: 4098
Valor 96: 4004
Valor 97: 3993
Valor 98: 4163
Valor 99: 3977
Valor 100: 4118
Valor 101: 4233
Valor 102: 4081
Valor 103: 4158
Valor 104: 4067
Valor 105: 4046
Valor 106: 4099
Valor 107: 4102
Valor 108: 4096
Valor 109: 4117
Valor 110: 4046
Valor 111: 4060
Valor 112: 4114
Valor 113: 4015
Valor 114: 4090
Valor 115: 4040
Valor 116: 4160
Valor 117: 4126
Valor 118: 4119
Valor 119: 4129
Valor 120: 4075
Valor 121: 4026
Valor 122: 4000
Valor 123: 4088
Valor 124: 4144
Valor 125: 4182
Valor 126: 4119
Valor 127: 4076
Valor 128: 4068
Valor 129: 4142
Valor 130: 4042
Valor 131: 4038
Valor 132: 4110
Valor 133: 4125
Valor 134: 3985
Valor 135: 4216
Valor 136: 4018
Valor 137: 4113
Valor 138: 4046
Valor 139: 4149
Valor 140: 4063
Valor 141: 4050
Valor 142: 4132
Valor 143: 4108
Valor 144: 4036
Valor 145: 4028
Valor 146: 4153
Valor 147: 4179
Valor 148: 4139
Valor 149: 4072
Valor 150: 4168
Valor 151: 4009
Valor 152: 4095
Valor 153: 4115
Valor 154: 4041
Valor 155: 3954
Valor 156: 4092
Valor 157: 4093
Valor 158: 4035
Valor 159: 4096
Valor 160: 4033
Valor 161: 4133
Valor 162: 3989
Valor 163: 4203
Valor 164: 4048
Valor 165: 4152
Valor 166: 4103
Valor 167: 4195
Valor 168: 4105
Valor 169: 4082
Valor 170: 4046
Valor 171: 4018
Valor 172: 4267
Valor 173: 4201
Valor 174: 4209
Valor 175: 4100
Valor 176: 4009
Valor 177: 3983
Valor 178: 4135
Valor 179: 4168
Valor 180: 4068
Valor 181: 4044
Valor 182: 4013
Valor 183: 3994
Valor 184: 4071
Valor 185: 4062
Valor 186: 4152
Valor 187: 4044
Valor 188: 4078
Valor 189: 4141
Valor 190: 4033
Valor 191: 4133
Valor 192: 4064
Valor 193: 4158
Valor 194: 3962
Valor 195: 4145
Valor 196: 4119
Valor 197: 4040
Valor 198: 3981
Valor 199: 4173
Valor 200: 4025
Valor 201: 4090
Valor 202: 4067
Valor 203: 4049
Valor 204: 4106
Valor 205: 4232
Valor 206: 3987
Valor 207: 4053
Valor 208: 4121
Valor 209: 4177
Valor 210: 4214
Valor 211: 4053
Valor 212: 4095
Valor 213: 4127
Valor 214: 4082
Valor 215: 4109
Valor 216: 4107
Valor 217: 4181
Valor 218: 4224
Valor 219: 4142
Valor 220: 4112
Valor 221: 4165
Valor 222: 4121
Valor 223: 4088
Valor 224: 4073
Valor 225: 3984
Valor 226: 4112
Valor 227: 4054
Valor 228: 4151
Valor 229: 4120
Valor 230: 4040
Valor 231: 4129
Valor 232: 4099
Valor 233: 4085
Valor 234: 4078
Valor 235: 4149
Valor 236: 4101
Valor 237: 3985
Valor 238: 3999
Valor 239: 4085
Valor 240: 4138
Valor 241: 4300
Valor 242: 4078
Valor 243: 4265
Valor 244: 4194
Valor 245: 4027
Valor 246: 4130
Valor 247: 4225
Valor 248: 4111
Valor 249: 4102
Valor 250: 4046
Valor 251: 4059
Valor 252: 3974
Valor 253: 4096
Valor 254: 4155
Valor 255: 4089


A simple vista parece que ambas salidas tienen una distribucion uniforme de los valores, con esto comprobamos la segunda propiedad de los RNG "La distribucion de todos los numeros generados debe de ser Uniforme"

Falta validar las otras 2 propiedades pero de momento es suficiente.

¿Entonces podemos decir que el Intel Secure Key RNG es Seguro?

No de momento con las pruebas hechas no hay manera de afirmar que sea seguro o inseguro.

Sin embargo las concluciones mencionadas en[10] comentan que la instroduccion de rdrand en los sistemas mejora y simplifica la generacion de numeros aleatorios ademas recomiendan usarlo junto con otros sources de entropia.




Referencias
[1] https://en.wikipedia.org/wiki/Random_number_generation
[2] https://www.schneier.com/academic/paperfiles/paper-yarrow.pdf
[3] https://software.intel.com/sites/default/files/m/d/4/1/d/8/441_Intel_R__DRNG_Software_Implementation_Guide_final_Aug7.pdf
[4] https://www.theregister.co.uk/2013/09/10/torvalds_on_rrrand_nsa_gchq/
[5] https://arstechnica.com/information-technology/2013/12/we-cannot-trust-intel-and-vias-chip-based-crypto-freebsd-developers-say/
[6] https://svnweb.freebsd.org/base/release/11.1.0/sys/dev/random/ivy.c?view=markup
[7] https://github.com/albertobsd/rdrand
[8] https://eprint.iacr.org/2014/504.pdf
[9] http://spectrum.ieee.org/computing/hardware/behind-intels-new-randomnumber-generator
[10] http://www.electronicdesign.com/learning-resources/understanding-intels-ivy-bridge-random-number-generator
#55
Fuente: https://albertobsd.blogspot.mx/2017/07/cable-modem-ubee-wpa2-y-wps-por-defecto.html




Bueno recientemente me instalaron el internet de Megacable (ISP de Internet y Televicion en Mexico ) y me entregaron un modem algo desconocido, pero realmente desconozco que tan usado sea esta marca de modems en las tecnologias de cable coaxial.

Me instalaron un  cable modem Ubee Modelo 1307

desconozco si estas condifuraciones sean para todos lo modelos he incluso para este mismo modelo en otra Compañia de cable.

La cable WPA/WPA2 por defecto para el equipo que me entregaron es PARTE de la MAC Address ORIGINAL. En especifico los ultimos 5 Octetos

Resalto "parte" y "original" ya que si escaneamos las redes Wireless la MAC address Wireless cambia en el ultimo octeto.

Ejemplo ficticio

MAC Adress Original: F8:DA:0C:00:00:00 (Esta es la que viene en nuestra etiqueta)
MAC Adress WAN: F8:DA:0C:00:00:01 (Esta es la que reconoce la compañia de cable)
MAC Adress MTA: F8:DA:0C:00:00:02 (NPI)
MAC Adress Ethernet: F8:DA:0C:00:00:03 (Mac address que ven las computadoras conectas por cable)
MAC Adress Wireless: F8:DA:0C:00:00:04 (Mac addres que ven los equipos wireless)

Entonces para este caso ficticio la cable WPA es DA0C000000
Y el SSID de la red Inalambrica es: Ubee0000

Los datos reales pueden cabiar.

Entonces si tenemos acceso a la MAC address inalambrica la clave serian los 4 octetos de en medio mas los 2 ultimos digitos del SSID.

Otro ejemplo

MAC Adress Wireless: F8:DA:0C:10:10:04
SSID: Ubee1000

La cable WPA seria los numeros resaltados a continuacion:
MAC Adress Wireless: F8:DA:0C:10:10:04
SSID: Ubee1000

Por lo que para este ejemplo seria DA0C101000

Ademas de todo esto el PIN WPS por default que venia en mi dispositivo es 12345670

Interfaz Web

La direccion para acceder a la interfaz web es http://192.168.0.1

El usurio y clave para entrar es user, user esto es:
usuario: user
contraseña: user

Recomendaciones
Desactivar el WPS
Cambiar el nombre de la red inalambrica
Cambiar la clave por defecto.


VULNERABLE A REAVER por defecto.

Atacando mi Equipo con Reaver:

# reaver -b F8:DA:0C:XX:XX:XX  -i mon0 -vv

Reaver v1.4-r119 WiFi Protected Setup Attack Tool
Copyright (c) 2011, Tactical Network Solutions, Craig Heffner <cheffner@tacnetsol.com>


[+] Switching mon0 to channel 10
[+] Waiting for beacon from F8:DA:0C:XX:XX:XX
[+] Associated with F8:DA:0C:XX:XX:XX (ESSID: EyL)
[+] Trying pin 12345670
[+] Sending EAPOL START request
[+] Received identity request
[+] Sending identity response
[+] Received M1 message
[+] Sending M2 message
[+] Received M3 message
[+] Sending M4 message
[+] Received M5 message
[+] Sending M6 message
[+] Received M7 message
[+] Sending WSC NACK
[+] Sending WSC NACK
[+] Pin cracked in 4 seconds
[+] WPS PIN: '12345670'
[+] WPA PSK: 'XXXXXXXXXXXXXX'
[+] AP SSID: 'XXXXXXXXXXXXXX'
[+] Nothing done, nothing to save.
#56
Buenas!

Este problema lo vi en otro Foro, pero me gustaria ampliarlo y Discutir sobre la eficiencia del codigo contra la "FORMA FACIL".



Problema
Tu tienes que proporcionar la Suma de Todos los numeros Impares contenidos en un rango de numeros dados [a,b]

Ejemplo:
a = 5
b = 10
Numeros impares en el rango [5,10] = { 5,7,9 };
Sumatoria 5 +7 + 9 = 21

Ejemplo
a = 1
b = 5
Numeros impares en el rango [1,5] = { 1,3,5 };
Sumatoria 1+3 +5 = 9

Entrada del programa:
Pueden existir multiples casos para probar, La primera Linea contiene el valor T Donde T es el numero de casos a realizar,  1 <= T  <= 100000
Y seguido de T Casos, Cada Caso consiste en dos Numeros enteros a, b  donde 0 <= a <=b <=10000. En dos lineas sepaadas (1 linea por numero entero)

Ejemplo de Entrada:

2
5
10
1
5


Ejemplo de salida

Caso 1: 21
Caso 2: 8






La solucion que muchos aplican es codigo:


int T= 0,a = 0,b= 0,i,suma;
scanf("%d\n",&T);
i = 0;
while(i < T) {
scanf("%d\n",&a);
scanf("%d\n",&b);
suma = 0;
while(a <= b) {
if(a % 2 == 1) {
suma += a;
}
a++;
}
printf("Case %i:%i\n",i+1,suma);
i++;
}


Sin embargo en mi punto de vista es bastante ineficiente, ya que si te dan 10000 Veces el peor de los casos de [0,10000] (Pongo 10000 y no 100000 para que no desborde el entero de 32 bits...) En dado caso tu programa ejecutaria un ciclo de 10000 * 10000 = 100'000,000
Claro que para los procesadores modernos no hay tanta direrencia entre 100, Mi aproximacion fue sacar la formula para determinar la sumaria de los impares del rango de 0 a A y del rango de 0 a B

Y En teoria solo entro al ciclo T veces:


#include<stdio.h>

int main() {
int T= 0,a = 0,b= 0,i;
int rango_a,rango_b;
scanf("%d\n",&T);
i = 0;
while(i < T) {
scanf("%d\n",&a);
scanf("%d\n",&b);
if(a % 2 != 0) {
a-=1;
}
rango_a = (((a/2)*a)/2); // Suma de Impares desde 0 hasta a-1
if(b % 2 == 0) {
rango_b = (((b/2)*b)/2); //Suma de Impares desde 0 hasta b
}
else {
rango_b = ((((b+1)/2)*(b+1))/2); //Suma de Impares desde 0 hasta b
}
printf("Case %i:%i\n",i+1,rango_b-rango_a);
i++;
}
return 0;
}




Consideren el siguiente archivo de Entrada 10000 veces rangos de [0,10000]
http://pastebin.com/raw/nK0xQ6cz
#57
Foro Libre / Bosque Cementerio?
1 Noviembre 2016, 02:29 AM
Vi esta imagen y me agrado la idea que opinan ustedes?

#58
Si tienes hosting en GODADDY y envias correos mediante el MAIL del PHP te aconsejo que dejes de hacerlo:

Cuando tu envías un correo electrónico usando la función de mail de PHP el hosting agrega información de rastreo para los correos con el objetivo de poder rastrear cualquier abuso del mismo y eso esta BIEN, lo que NO esta bien es que agreguen la información en TEXTO PLANO. esto es envían información sensible como:


  • username del CPANEL
  • UID/GID del Proceso baja el cual se ejecuta el PHP (Un hosting linux claro)
  • Hosting principal asociado al Hosting
  • Host de segundario (Si es que existe)...
  • Ruta desde donde se ejecuta el script PHP
  • nombre del Script php que envia el correo

Ejemplo de los headers mencionados:


X-PHP-Script: (HOST_SECUNDARIO)/index.php for 189.181.XXX.XXX
X-AntiAbuse: This header was added to track abuse, please include it with any abuse report
X-AntiAbuse: Originator/Caller UID/GID - [123456 666] / [47 12]
X-AntiAbuse: Sender Address Domain - p3plcpnl0940.prod.phx3.secureserver.net
X-Get-Message-Sender-Via: p3plcpnl0940.prod.phx3.secureserver.net: authenticated_id: username_CPANEL/from_h
X-Source-Args: /usr/sbin/proxyexec -q -d -s /var/lib/proxyexec/cagefs.sock/socket /bin/cagefs.server
X-Source-Dir: (HOST_PRIMARIO):/FULL/PATH/OF/SCRIPT


Fuente:
https://albertobsd.blogspot.mx/2016/09/godaddy-expone-informacion-sensible-al.html
#59
Buen dia, pues esa es la cuestion, estoy viendo como crear PDF desde C# para generar mis reportes y mostrarlos via WEB.

El detalle es que busco algo con buena documentación, he visto buenos comentarios de iTextSharp en su version 5.9, pero carece de mucha documentación

¿Que opciones usan ustedes, cuales recomiendan?

Saludos!
#60
En construcción

Libcrypto
Documentación: No esta muy ordenada
https://wiki.openssl.org/index.php/Libcrypto_API


Libgcrypt
Documentación: Excelente
Algoritmos: La mayoria de los Simetricos y siguen desarrollando los Asimetricos

CitarLibgcrypt is a general purpose cryptographic library based on the code from GnuPG. It provides functions for all cryptograhic building blocks: symmetric ciphers (AES, DES, Blowfish, CAST5, Twofish, SEED, Camellia, Arcfour), hash algorithms (MD4, MD5, RIPE-MD160, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512, TIGER-192, Whirlpool), MACs (HMAC for all hash algorithms), public key algorithms (RSA, Elgamal, DSA, ECDSA), large integer functions, random numbers and a lot of supporting functions.

Libgcrypt works on most POSIX systems and many pre-POSIX systems. It can also be built using a cross-compiler system for Microsoft Windows.
https://www.gnu.org/software/libgcrypt/
https://gnupg.org/download/index.html#libgcrypt





Abro el tema por que me he encontrado con el problema de usar una librería de cifrado en Windows, el problema que el proyecto que estoy haciendo en C en FreeBSD lo hice con libgcrypt pero esta NO se puede portar tan fácilmente a windows :P :P Y cada que alguien preguntaba por alguna librería asi yo siempre recomendaba libgcrypt (Mas que nada la recomendaba por completa suite de algoritmos y excelente documentación).

Realmente no conozco muchas librerias de este tipo ya que siempre trabaje con libgcrypt y me parecia muy completa,
¿podrian comentar algunas mas que usen o conozcan y que tambien funcionen con windows y no tengan tantas dependencias?

Saludos!
#61
Que tal Pongo aqui la solucion que encontre al problema de no tener fork en Windows, la solucion es CreateThread de la winapi



   if(listen(ListenSocket, BACKLOG) == SOCKET_ERROR) {
printf("listen failed with error: %ld\n", WSAGetLastError());
closesocket(ListenSocket);
WSACleanup();
       return 1;
   }
while(entrar) {//Entrar es true solo se cambia por otro segmento del codigo en caso de que queramos finalizar con el hilo principal
b = sizeof(struct sockaddr_in);
client = accept(ListenSocket,(SOCKADDR *) service,&b);
if(client == INVALID_SOCKET) {
exit(1);
}
toThread = malloc(sizeof(SOCKET));
memcpy(toThread,&client,sizeof(SOCKET));// Copiamos la variable socket principal para pasarla al thread
hThread = CreateThread(
           NULL,                   // default security attributes
           0,                      // use default stack size  
           client_funtion,       // thread function name
           toThread,          // argument to thread function
           0,                      // use default creation flags
           &dwThreadId);   // returns the thread identifier
printf("Thread ID %u\n",dwThreadId);
if(hThread == NULL) {
          free(toThread);
  exit(0)
       }
}
   closesocket(ListenSocket);


hay que tener en cuenta que necesitasmos una funcion para el Thread:


DWORD WINAPI client_funtion( LPVOID lpParam ) {
//Variables
// aqui recivir datos y procesarlos, se puede llamar a otras funciones que sean Thread safe
}


Si no queremos que el hilo principal se "preocupe" por cerrar estas conexiones y terminar con el hilo podemos poner lo siguiente:

DWORD WINAPI client_funtion( LPVOID lpParam ) {
HANDLE thread_id;
thread_id = GetCurrentThread();
//Otras variables
//codigo aque para procesar al cliente correctamente

free(lpParam); //Si lpParam es un parametro que tenemos que liberar entonces Free

CloseHandle(thread_id); //Terminamos con nuestro propio Thread
}


Me base en el ejemplo puesto aqui:

http://foro.elhacker.net/programacion_cc/createthread_o_createprocess-t458039.0.html

Saludos
#62
Programación C/C++ / CreateThread o CreateProcess
21 Septiembre 2016, 17:07 PM
Estoy haciendo un servidor en C el tema es cual funcion debo elegir como la deberia de aplicar.

Tengo 2 versiones de mi servidor, una para sistemas Unix y otra para Windows.

En unix no hay problema solo hago un fork y asunto resuelto:

if(listen(ListenSocket, BACKLOG) == -1) {
perror("error: listen");


        return 1;
    }
while(entrar) {
pid = fork();
switch(pid) {
case 0:
//Codigo para el Hijo
break;
case -1:
//Error no fallo Fork
break;
default:
//Get the PID for Parent
break;
}
}


Pero no he encontrado una solucion para Windows, el servidor funciona bastante bien, el punto que en windows no es Multihilo aun, y tarda en responder ya que lo hace en orden secuencial.

He visto los siguientes enlaces y aun no doy con una solucion sencilla al tema

http://stackoverflow.com/questions/985281/what-is-the-closest-thing-windows-has-to-fork
http://stackoverflow.com/questions/14642496/any-simple-quick-way-to-fork-on-windows-ansi-c-beginthread-beginthreadex

Repito tengo 2 archivos distintos uno para Windows con winsock y el otro para Unix con Sockets estandar del sistema.

Saludos!
#63
Bueno escribo por si alguien tiene el mismo problema

Un agregador en servicios móviles es un servicio donde por X cantidad de dinero semanal el usuario tiene acceso a un "servicio y/o beneficio" si es que realmente sirven de algo, cosa que dudo mucho.

Hace unos días mi numero móvil fue agregado a una lista de Servicios de estos servicios, En teoria estos servicios necesitan confirmación por parte del usuario para ser dado de alta pero la verdad NO ES ASI.

Ver tweets:

https://twitter.com/albertobsd/status/769922393158455297
https://twitter.com/albertobsd/status/769194215318310912

No se como, ni quien fue el responsable de hacer esto, en Atención a clientes de mi proveedor (TELCEL) indican que no existe forma para suscribirse a estos servicios sin que el usuario lo confirme mediante mensaje de texto. Y si les dices que no fuiste tu o cualquier otra cosa vuelven a repetirte lo mismo como grabadora parece que tienen esa indicacion y/o no tienen mente propia

Sospecho las siguientes causas:

  • Te suscribe la misma compañía para sacarte mas dinero
  • Visitastes algun sitio con ads/scripts intrusivos que te suscribieron automáticamente a X servicio

Sospecho lo primero por que en mi caso sucedió exactamente una semana después de cancelar el contrato que tenia con ellos.
Y de lo segundo ya que como programador y aprendiz de hacker se que es posible crear algunos scripts que exploten algun bug en tu movil y envien mensajes de texto silenciosos.


DARTE DE BAJA

Para el caso de telcel tenemos las siguientes opciones:




Anterioremente

Hace años circulaban varias paginas de Internet donde estaba un formulario para agregar un numero de celular a estos servicios, paginas amarillistas como "la fecha de tu muerte", "bruja real", "Video no apto para cardiacos" etc...

Cada vez he visto menos de estas paginas pero lo interesare seria ver para quien trabajan estas paginas y tirarles el servicio.

Historias relacionadas:

https://www.reddit.com/r/mexico/comments/o8bc1/telcel_los_agregadores_de_contenido_y_su_nueva/
https://www.reddit.com/r/mexico/comments/3sbr79/quien_regula_a_los_agregadores_de_contenido_en/
#64
Buenas!!

Estoy haciendo un pequeño servidor WEB en C, algo basico y como ejercicio, ya que este algo pulido dejare el link al codigo por aqui.


El detalle que me encuentro es que quiero crear una función de argumentos variables asi como el printf donde le ahorre al usuario "final" ( :rolleyes: :rolleyes:) el reservar memoria para el buffer de respuesta al cliente. para ello solo creare una función llamada "server_print" donde el usuario colocara su formato de cadena y las variables que el quiera. Y que la función haga el trabajo duro...

session es un contenedor de variables auxiliares y ese de momento, se puede obviar...

void server_print(struct peticion *session,char *format,...) {
char *buffer = NULL;
int X;
va_list args;
va_start(args, format);
buffer =malloc(X);
vsnprintf(buffer,X,format, args);

//realizar operaciones sobre session...


va_end(args);
}


Lo que me interesa saber es el cuando debe de valer X para reservar esa cantidad de memoria exacta.. el detalles esta en que puedo ahórrame el "pensar" y asignar MUCHA memoria por cada argumento del programa, pero el detalle esta en que:

¿Que pasa si no alcanza?

Quiero tener un programa eficiente que no malgaste memoria y sea rápido...

Se me ocurre buscar en la cadena de formato por cada % que se encuentre y por ejemplo si es un Entero reservar solo 12 bytes mas, si es cadena sacar el strlen del argumento en cuestion, si es %l dejar sobre 30 bytes mas y asi...

¿Como procederían ustedes?

Saludos!
#65
Estoy desarrollando una app y ahora tengo que poner un limite al numero de trackers que puede tener un torrent.

En teoria no debería de tener limite lo se, pero si vemos la mayoria de los links magnet en TPB solo vienen con unos 3 o 5 trackers

Pero no encuentro ningun documento que especifique un limite claro.

En mi caso he optado por 16 trackers esto solo lo pregunto para optimizar el tamaño de almacenamiento, ya en ejecucion puede crecer lo que sea necesario.

Saludos
#66
Buen dia estoy desarrollando un pequeño servidor en C para un proyecto que tengo.

Ya tengo buena parte trabajado, pero me gustaria consultarles si existen mas cosas que deba de validar en una peticion GET  el ejemplo que mas o menos tengo del codigo es el siguiente:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#define KB 1024

int main() {
char *type,*resource,*protocol,*extra,*hasQuery,**values = NULL,*key,*value,*aux;
int values_count= 0,i;
char *temp = malloc(KB);
strcpy(temp,"GET /LALALA/xD.txt?q=xD&XD HTTP/1.1");
type = strtok(temp," ");
resource = strtok(NULL," ");
protocol = strtok(NULL," ");
extra = strtok(NULL," ");
printf("type = %p: %s\n",type,type);
printf("resource = %p: %s\n",resource,resource);
printf("protocol = %p: %s\n",protocol,protocol);
printf("extra = %p\n",extra);
hasQuery = strstr(resource,"?");
if(hasQuery) {
printf("query = %p: %s\n",hasQuery,hasQuery);
aux =  strtok(hasQuery+1,"&");
do {
if(aux) {
values = realloc(values,sizeof(char*)*(values_count+1));
values[values_count] = aux;
printf("values: %s\n",values[values_count]);
values_count++;
}
aux =  strtok(NULL,"&");
}while(aux);
i = 0;
while(i < values_count) {
key = strtok(values[i],"=");
value = strtok(NULL,"");
//Aqui salvo los valores key y value para su posterior uso
printf("Key: %s\nValue: %s\n",key,value);
i++;
}
}
else
printf("query = %p\n",hasQuery);
if(values)
free(values);
if(temp) {
free(temp);
}
}



Estoy releyendo el protocolo del HTTP y estoy validando de momento solo la primera LINEA de la peticion.

Saludos!
#67
Criptografía / I lost my OPENBSD FDE Password
31 Agosto 2016, 15:42 PM
Demostracion de como recuperan el block key material para descifrar el Disco Duro


Código (csharp) [Seleccionar]
func main() { 
    scmKey := decode(scmKey)
    salt := decode(salt)

    maskkey := pbkdf2.Key([]byte("password"), salt, rounds, 32, sha1.New)

    // AES-ECB-256_decrypt(k=maskkey, scm_key) = scr_key
    a, err := aes.NewCipher(maskkey)
    if err != nil {
        log.Fatal(err)
    }
    for i := 0; i < len(scmKey); i += a.BlockSize() {
        a.Decrypt(scmKey[i:i+a.BlockSize()], scmKey[i:i+a.BlockSize()])
    }

    // HMAC-SHA1(k=maskkey, scm_key) == sch_mac
    h := sha1.Sum(maskkey)
    mac := hmac.New(sha1.New, h[:])
    mac.Write(scmKey)
    expectedMAC := mac.Sum(nil)

    fmt.Print(hex.Dump(expectedMAC))
}



El link con la lectura completa en Ingles:

https://blog.filippo.io/so-i-lost-my-openbsd-fde-password/
#68
Hola que tal estoy desarrollando una plataforma, donde se requiere cierta moderación de contenido,  asi como el foro, con moderadores de distintos Rangos y privilegios....

El detalle es que esta plataforma es semi-automata, entonces estoy buscando si existe algún sistema de votación o similar para realizar ciertas Acciones.

Por ejemplo si quiero aprobar cierto contenido y/o eliminarlo o lo que fuese, la idea seria que lo moderadores votaran por realizar X acción, pero como NO siempre van a estar todos los moderadores en linea, la idea es que el sistema tenga un ALGORITMO que con determinado numero de votos y variables, determinara si realizar la acción o no.

Puedo realizar mi propio algoritmo con los parámetros que necesito, pero la idea es ver si existe algo parecido.

Es como una especie de Democracia Ateniense

Saludos!
#69
El siguiente codigo simula un Sorteo/Loteria 10 Millones de veces tomando 30 muestras de estas simulaciones obtenemos un Valor de veces que se gano el sorteo.

El jugador elige un numero y en cada ciclo se sortean otro Numero si el numero es igual al del jugador este GANA.


Se realizan 2 Tipos de Sorteos:


  • Uno donde el jugador conserva el MISMO numero todas las simulaciones.
  • El otro donde el jugador CAMBIA el numero en cada simulación

Salida Obtenida en 4 ejecuciones:

Total de veces ganador CON cambio de Variable 30636/(300000000 Sorteos)
Total de veces ganador SIN cambio de Variable 27675/(300000000 Sorteos)
Total de veces ganador CON cambio de Variable 30396/(300000000 Sorteos)
Total de veces ganador SIN cambio de Variable 36592/(300000000 Sorteos)
Total de veces ganador CON cambio de Variable 30700/(300000000 Sorteos)
Total de veces ganador SIN cambio de Variable 36890/(300000000 Sorteos)
Total de veces ganador CON cambio de Variable 30635/(300000000 Sorteos)
Total de veces ganador SIN cambio de Variable 27460/(300000000 Sorteos)


Si Observamos en total son 300 Millones de simulaciones 2 veces en cada ejecución, si vemos el "promedio" se mantiene mas o menos constante cuando SI CAMBIA la variable.

y el "promedio" se varia entre ejecuciones cuando NO CAMBIA la variable.

#include<stdio.h>
#include<stdlib.h>
#include<time.h>

#define MUESTRAS 30
#define SIMULACIONES 10000000
#define MAX 60000

int main() {
register int i = 0,j = 0;

int elegido,premio, contador = 0;
srand(time(NULL));

//Sorteos con cambio de Variable
j = 0;
while(j < MUESTRAS){
i = 0;
while(i < SIMULACIONES) {
elegido = rand() % MAX; // La variable elegida cambia en cada sorteo
premio = rand() % MAX;
if(elegido == premio) {
contador++;
}
i++;
}
j++;
}
printf("Total de veces ganador CON cambio de Variable %i/(%i Sorteos)\n",contador,MUESTRAS*SIMULACIONES);


//Sorteos SIN cambio de Variable
j = 0;
elegido = rand() % MAX; // La variable no cambia
contador = 0;
while(j < MUESTRAS){
i = 0;
while(i < SIMULACIONES) {
premio = rand() % MAX;
if(elegido == premio) {
contador++;
}
i++;
}
j++;
}
printf("Total de veces ganador SIN cambio de Variable %i/(%i Sorteos)\n",contador,MUESTRAS*SIMULACIONES);
return 0;
}


Esto va de la mano con la siguiente pregunta:

¿Es bueno cambiar siempre de variable?

Tema relacionado:

Demostracion del problema de Monty Hall

Saludos
#70
Siguiendo con el tema de :

[C] Duda TATETI

en ese tema puse un codigo para Generar un Arbol de N niveles apartir de una jugada inicial

Ahora toca evaluar todos los nodos (Juegos) para asi poder decidir el mejor movimiento

Dada las siguientes definiciones y estructuras:

#define UNKNOW 0 //Nobody win yet
#define O_WIN 1
#define X_WIN 2
#define DRAW 3
#define ERROR 4

struct tablero {
uint8_t juego[3][3];
};


Hice esta funcion que evalua las 3 Filas , 3 Columnas y 2 Diagonales. Adicional evaluar si es empate, si todavia nadie gana y si existe alguna discrepancia en el tablero

La pregunta aqui es, ¿Existe una forma mas eficiente de hacer esto?

Me refiero a que se me hace bastante pesado evaluar todas las lineas xD..

NOTA: No he compilado el codigo por lo que puedw tener errores.

uint8_t estatus_juego(struct tablero *t) {
uint8_t e;  //Estatus a devolver
register uint8_t i = 0,j = 0;
uint8_t contador_X,contador_O,casilla;
bool continuar = true;
//Procedemos a validar las 3 Lineas horizontales
i = 0;
while(continuar && i < 3) {
j = 0;
casilla = t->juego[i][j];
j++;
while(continuar && j < 3 && ) {
if(casilla != t->juego[i][j] || !t->juego[i][j]) {
continuar = false;
}
j++;
}
if(continuar){
//si continuar sigue siendo true en este punto el jugador casilla Gana y ya no es necesario evaluar los otros casos
continuar = false; // Establemos continuar como false para que ya no entre al ciclo siguiente
}
else {
//En caso de que continuar sea false, significa que debemos seguir evaluando las lineas restantes
continuar = true // Establemos continuar como true para que si entre al ciclo siguiente
}
i++;
}
if(continuar) {
//Continuamos la evaluacion de las lineas Verticales
i = 0;
while(continuar && i < 3) {
j = 0;
casilla = t->juego[j][i];
j++;
while(continuar && j < 3) {
if(casilla != t->juego[j][i] || !t->juego[j][i] ) {
continuar = false;
}
j++;
}
if(continuar){
//si continuar sigue siendo true en este punto el jugador casilla Gana y ya no es necesario evaluar los otros casos
continuar = false; // Establemos continuar como false para que ya no entre al ciclo siguiente
}
else {
//En caso de que continuar sea false, significa que debemos seguir evaluando las lineas restantes
continuar = true // Establemos continuar como true para que si entre al ciclo siguiente
}
i++;
}
if(continuar) { //Evaluamos las lineas Diagonales
casilla = t->juego[0][0];
if(casilla == t->juego[1][1] && casilla == t->juego[2][2] && casilla != 0) {
if(casilla == 'X') {
e = X_WIN;
}
else {
e = O_WIN;
}

}
else {
casilla = t->juego[0][2];
if(casilla == t->juego[1][1] && casilla == t->juego[2][0]  && casilla != 0) {
if(casilla == 'X') {
e = X_WIN;
}
else {
e = O_WIN;
}
}
else {
//Todavia nadie gana o es empate en caso de que ya no queden casillas libres
contador_X = 0;
contador_O = 0;
i = 0;
while(i < 3) {
j = 0;
while(j < 3) {
if(t->juego[i][j] == 'X') {
contador_X++;
}
else {
if(t->juego[i][j] == 'O') {
contador_O++;
}
}
j++;
}
i++;
}
if(abs(contador_O-contador_X) > 1) {
//ERROR de Tablero, no es posible que un jugador tenga 2 o mas 'fichas' que el otro en el tablero
e = ERROR;
}
else {
if(contador_X+contador_O < 9) {
e = UNKNOW;
}
else {
e = DRAW;
}
}
}
}
}
else {
//En este punto evaluamos quien gano
if(casilla == 'X') {
e = X_WIN;
}
else {
e = O_WIN;
}
}
}
else {
//En este punto evaluamos quien gano
if(casilla == 'X') {
e = X_WIN;
}
else {
e = O_WIN;
}
}
return e;
}


Saludos
#71
Desarrollo Web / Acceso asincrono a Variables
25 Agosto 2016, 20:20 PM
Hola que tal estoy programando una pequeña interfaz y me encuentro con el siguiente problema:

Tengo una varible Array en javascript:

Código (javascript) [Seleccionar]
var sucursales = new Array;

Dicha variable se actualiza en tiempo de ejecución mediante la siguiente función:

Código (javascript) [Seleccionar]
function lista_sucursal() {
$.ajax({
url: '/get_sucursales.aspx',
type: 'POST',
success: function(data) {
var r = JSON.parse(data);
if(r.ok == true) {
var i = 0;
while (i < r.data.length) {
    sucursales[r.data[i].id] = r.data[i].nombre;
    //Mas codigo irrelevante aqui
i++;
}
}
else {
//Error aqui
}
}
});
}


Dicha funcion se llama al momento de cargar la pagina primero que otras funciones...

Posteriormente tengo otro parte del codigo que hace mas o menos esto:

Código (javascript) [Seleccionar]
function maquinas_sucursales_tabla() {
$("#tabla_body").html("");
$.ajax({
url: '/get_maquinas_sucursales.aspx',
type: 'POST',
success: function(data) {
var r = JSON.parse(data);
if(r.ok == true) {
var i = 0;
while(i < r.data.length) {
    $("#tabla_body").append('<tr><td>' + sucursales[r.data[i].sucursal] + '</td></tr>');
i++;
}
}
else {
//ERROR
}
}
});
}


El detalle esta en que hay veces que pone el dato correctamente y otras veces aparece "undefined" y esto es debido a que el codigo del jquery se ejecuta de forma asincrona...

Que recomiendan para solucionar esto, estaba pensando en usar un semaforo como "sucursales_ready" para solo cargar los otros datos cuando la variable ya este lista....

Pero no se, tal vez existe otro metodo mas rapido y/o sencillo.


Saludos!
#72
Hacking / Respuesta HTTP Extraña
24 Agosto 2016, 01:15 AM
Bueno actualmente estoy testeando un servidor que me esta tratando de hackear... (Eso o estoy paranoico  :rolleyes:)

El detalle que he empezado a recibir un par de correos de una pagina legitima, pero la direccion final de destino esta en un IP dinamica, la pagina tiene el puerto 81 Abierto y he hecho un par de peticiones manualmente mediante netcat

GET / HTTP/1.1
Host: <IP>




y la respuesta siempre es la mismasimilar:

HTTP/1.1 200 OK
Cache-Control: private
Content-Length: 2463
Content-Type: text/html
Server: Microsoft-IIS/7.5
Set-Cookie: ASPSESSIONIDSSDQCRCR=SUPERCOOKIE; path=/
X-Powered-By: ASP.NET
Date: Fri, 20 Aug 2016 00:00:0 GMT

ÿØÿà J.............<OMITIDO>


El contenido nunca cambia a pesar de ser siempre los 2463 y la salida dice ser text/html

Creen que sea información comprimida o alguna idea del formato, por seguridad y un poco de paranoia colocare la información aqui despues de realizarle algunos cuantos test (Muestreos estadísticos)

Saludos!
#73
Hace tiempo vi un post, donde preguntaban sobre como crear una "partición" de swap o intercambio entre memoria y Disco Duro, solo que no logro encontrar el tema.

Bien estos dias estoy trabajando en un proyecto similar, donde tengo un archivo de X cantidad de Gigabytes desde 2, 4, 8, ... o mas

El detalle que cuando quieres trabajar con estas "particiones" para aprender como los sistemas operativos administran la falta de memoria con un espacio de intercambio en Disco te encuentras con el problema de que debes de administrar "optima-mente" ese espacio, y no significa que debas de ahorrar cada byte, pero es comun que las cosas que almacenas en ese espacio en disco cambien de tamaño o sean borradas poco después de escribirlas.. y por optima-mente me refiero a no perder de vista donde dejas cada cosa y a donde se movió, y que espacios quedan libres.

El codigo para escribir un archivo en Blanco de 4 Gigabytes es el siguiente:


#define KB 1024
#define MB 1048576

register int i = 0;
char *buffer = NULL;
FILE *archivo = NULL;
archivo = fopen("cache.bin","wb");
buffer = calloc(MB,sizeof(char));
while(i < 4*KB) {
fwrite(buffer,MB,1,archivo);
i++;
}
fclose(archivo);
return 0;


Con eso ya tenemos nuestro espacio para "intercambio", ahora necesitamos tener otro archivo o estructura donde recordemos donde dejamos cada cosa...

struct map_item {
uint64_t start;
uint64_t end;
uint8_t name[80];
};


Suponiendo que esa sea nuestra estructura de donde dejamos las cosas, podríamos tener la siguiente función para recuperar X catidad de bytes desde el archivo.

uint8_t *get_data_from_swap(uint64_t s,uint64_t e) {
FILE *swap_file = NULL;
uint8_t *data = NULL;
uint64_t l,r;
l = e-s;
swap_file = fopen("cache.bin","rb");
if(swap_file) {
data = malloc(l+1);
fseek(swap_file,s,SEEK_SET);
r = fread(data,1,l,swap_file);
if(l != r) {
fprintf("Error al leer archivo de SWAP",stderr);
}
data[l] = 0;
fclose(swap_file);
}
else {
fprintf("Error al leer archivo de SWAP",stderr);
}
return data;
}


Asi solo pedimos el inicio y el final y la función  se encarga de leer el archivo y devolvernos un apuntador con los datos solicitados + 1 byte de Caracter NULO

Y esto NO SOLO sirve para "Contenido de memoria", simplemente puede ser una archivo de configuración, con X cantidad de parámetros por ejemplo si estamos haciendo un juego podemos guardar Datos ahi, como récords de los usuarios, nombres, items de juego y una larga lista de etceteras...

Solo tenemos que identificarlos bien y tener las rutinas adecuadas para guardar valores nuevos y "Reacomodar" los items existentes para no dejar huecos libres.
#74
Foro Libre / Divagando por Youtube
12 Agosto 2016, 22:04 PM

Yo no tengo Televisión y hace mas de 10 años que no la veo, para mi Youtube es una forma de  Entretenimiento Random ya que nunca se que que voy a terminar viendo al Final del dia.

Youtube tiene sus algoritmos para mostrarte vídeos Relacionados, pero llega un punto en que dices
CitarComo chingados llegue a este video

Y asi como hay usuarios Troll que Desvian Temas... Creo yo que también existen videos troll hecho por Usuarios Troll que solo buscan desviar temas, ya saben... típicos vídeos donde el Thumbnail presenta una imagen realmente prometedora y dicha imagen nunca aparece en el video o el video habla de otra cosa. ODIO ESO!!

¿No les a pasado que empiezan viendo un Tema X y terminan viendo un tema Totalmente diferente al que empezaron?

Saludos!


#75
Un reporte del foro Mundial de Economía, indica que la tecnología introducida por el Bitcoin (El Blockchain) representara el centro de las operaciones de los sistemas financieros en el Mundo.

Dicha tecnología Heredada de sistemas criptograficos a demostrado ser un pilar importante para el registro de operaciones "Económicas" esto es la compra venta de Divisas/Mercancias utilizando el bitcoin.

No significa que los sistemas financieros adopten el bitcoin, simplemente trataran de incorporar lo mejor de este: El Blockchain

Sin duda alguna la tecnología siempre estará a la vanguardia en estos temas


Mas Información en Ingles

http://www.nytimes.com/2016/08/13/business/dealbook/bitcoin-blockchain-banking-finance.html?ref=technology&_r=0

#76
El pasado 21 de julio cerró la página de torrents más famosa y más utilizada en Internet, incluso por encima de ThePirateBay. A pesar de recibir constantes reclamaciones de DMCA que hacían que muchos de los enlaces, sobre todo a series, fueran eliminados a los pocos días de ser subidos, era la página a la que todos iban a comprobar las últimas novedades.

Actualmente han surgido dos mirrors que han vuelto a subir contenido, como son kickass.mx y kickass.cd. Después del cierre surgió kat.am, el cual fue cerrado por las autoridades, y actualmente el dominio ha sido comprado por estafadores, que cuando vas a descargar un enlace torrent, te piden tu cuenta bancaria.


Mas info: http://www.adslzone.net/2016/08/12/antiguos-miembros-kickass-estan-crowdfunding-reabrir-la-web/
#77
Quien no ha visto ese concurso donde hay un solo premio detras de 3 puertas las otras 2 con  Cabras u Ovejas...



La opción adecuada es siempre "cambiar" de puerta cuando te pregunten si te quieres cambiar de la misma..

El programa simula 10 Millones de Juegos 2 veces, en la primera ronda el jugador siempre cambia de puerta y en la segunda ronda el jugador nunca cambia de puerta.

Se demuestra que se tiene 66.6% de probabilidad de ganar si se cambia de puerta, contra 33.3% de probabilidad de ganar si no se cambia  de puerta.

#include<stdio.h>
#include<stdint.h>
#include<string.h>
#include<stdlib.h>
#include<time.h>

#define GOAT 0 //CABRA 0
#define PRIZE 1 //PREMIO 1

#define MAX_SIMULATIONS 10000000

int main() {
/*unsigned char */
uint8_t position = 0; //Posicion del premio
uint8_t selected = 0; //Posicion seleccionada por el jugado
uint8_t doors[3]; //Puertas
uint8_t can_switch = 0; //La puerta a la cual se puede cambiar
register uint32_t count_win = 0;
register uint32_t simulations = 0;
srand(time(NULL)); //Semilla Random
memset(doors,GOAT,sizeof(uint8_t)*3); //Todas las puertas son Cabras
//< 10000000
while(simulations < MAX_SIMULATIONS) {
position = rand() % 3; //position del Premio Pseudo-Aleatoria
doors[position] = PRIZE; //Guardamos el premio en la position antes seleccionada
selected = rand() % 3; //position elejida por el Jugador

switch(selected) { //En base a lo elejido por el jugador
//El encargado del juego valida que puerta tiene otra Cabra y la destapa
//Dandole la oportunida al jugador de cambiar su puerta por la puerta restante
case 0: //Puerta 0 elejida por el Jugador
if(doors[1] == GOAT) { //Si otra puerta 1 Tiene cabra entonces
can_switch = 2; //Le damos la oportunidad de elegir entre la puerta 0 y la puerta 2
}
else { //Caso contrario
can_switch = 1; //Le damos la opotunidad de elegir entre la puerta 0 y la puerta 1
}
break;
case 1: //Repetimos en caso de que seleccione la puerta 1
if(doors[2] == GOAT) {
can_switch = 0;
}
else {
can_switch = 2;
}
break;
case 2: //Repetimos en caso de que seleccione la puerta 2
if(doors[0] == GOAT) {
can_switch = 1;
}
else {
can_switch = 0;
}
break;
}
if(doors[can_switch] == PRIZE) { //Evaluamos si la puerta elejida tiene el premio
count_win++; //Si es asi incrementamos el contador de premios
}
doors[position] = GOAT; //0 //Restablecemos la puerta con premio nuevamente a Cabra
simulations++; //Incrementamos el contador de Simulaciones
}

//Imprimimos totales
printf("Total simulations with change %u, win: %u rate: %f\n",simulations,count_win,(float)((float)count_win/(float)simulations));

count_win = 0; //Restablecemos contador de premios a 0
simulations = 0; //Restablecemos contador de simulaciones a 0

//Como en la siguiente similacion el jugador no cambiara de puerta no es necesario evaluar las otras puertas
while(simulations < MAX_SIMULATIONS) {
position = rand() % 3;
doors[position] = PRIZE;
selected = rand() % 3;
if(doors[selected] == PRIZE) {
count_win++;
}
doors[position] = GOAT; //0
simulations++;
}
printf("Total simulations without change %u, win: %u rate: %f\n",simulations,count_win,(float)((float)count_win/(float)simulations));
return(0);
}


Descripción del problema:

https://en.m.wikipedia.org/wiki/Monty_Hall_problem


Salida del codigo arriba mostrado:

Total simulations with change 10000000, win: 6665613 rate: 0.666561
Total simulations without change 10000000, win: 3335076 rate: 0.333508

Saludos!
#78
Repitan despues de mi...

La memoria no se inicializa en 0 de forma automatica.
Los arreglos no se inicializan en 0 de forma automatica.
Las variables no se inicializan en 0 de forma automatica.

Se que es un tema tanto repetitivo y es el causante de muchos errores de programacion.

No existe ninguna garantia de que la memoria este inicializada en 0 todas las veces, hay ocasiones en la que si lo esta y hay ocasiones en la que no esta veamos este ejemplo, el cual muestra de un arreglo de 20 elementos los que su valor inicial no sea 0,

#include<stdio.h>

int main() {
int i;
int arreglo[20];
i = 0;
while(i < 20) {
if(arreglo[i] != 0) {
printf("La posicion %i del arreglo no esta inicializada su valor actual es %i\n",i,arreglo[i]);
}
i++;
}
return 0;
}



La salida de ese codigo compilado con GCC para windows es:


La posicion 0 del arreglo no esta inicializada su valor actual es 4200160
La posicion 2 del arreglo no esta inicializada su valor actual es 21
La posicion 4 del arreglo no esta inicializada su valor actual es 9966448
La posicion 6 del arreglo no esta inicializada su valor actual es 1
La posicion 8 del arreglo no esta inicializada su valor actual es -1
La posicion 9 del arreglo no esta inicializada su valor actual es -1
La posicion 10 del arreglo no esta inicializada su valor actual es 4200261
La posicion 12 del arreglo no esta inicializada su valor actual es 1
La posicion 14 del arreglo no esta inicializada su valor actual es 4200137
La posicion 16 del arreglo no esta inicializada su valor actual es 3
La posicion 18 del arreglo no esta inicializada su valor actual es 21


Y la segunda vez que lo ejecute fue

La posicion 0 del arreglo no esta inicializada su valor actual es 4200160
La posicion 2 del arreglo no esta inicializada su valor actual es 21
La posicion 4 del arreglo no esta inicializada su valor actual es 12063600
La posicion 6 del arreglo no esta inicializada su valor actual es 1
La posicion 8 del arreglo no esta inicializada su valor actual es -1
La posicion 9 del arreglo no esta inicializada su valor actual es -1
La posicion 10 del arreglo no esta inicializada su valor actual es 4200261
La posicion 12 del arreglo no esta inicializada su valor actual es 1
La posicion 14 del arreglo no esta inicializada su valor actual es 4200137
La posicion 16 del arreglo no esta inicializada su valor actual es 3
La posicion 18 del arreglo no esta inicializada su valor actual es 21


Como ven algunos valores cambiaron y otros se mantiene similares..

Depende del programador inicializar la memoria correctamente, o por lo menos estar cociente de que es posible que tenga basura en la memoria.

Una forma de inicializar en 0 el arreglo mencioanado al momento de declararlo es:

int arreglo[20] = {0};

otra forma es utilizar las funciones para inicializar con X valor la memoria

Por ejemplo para inicializar con 0:

memset(arreglo,0,sizeof(int)*20);

Saludos!
#79
Muy buen dia, les dejo la Base para realizar el algoritmo de dijkstra.

La imagen de ejemplo es la que esta en Wikipedia https://es.wikipedia.org/wiki/Algoritmo_de_Dijkstra#/media/File:Dijkstra_Animation.gif

He aqui el código, el ejemplo que muestra que la ruta mas rápida de 1 a 5 tiene un peso total de 20

El código esta medianamente comentado y Imprime lo que esta haciendo en tiempo de ejecución.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct nodo {
int id;
//Dato del Nodo
//struct data *datos; //En caso de apuntar a otro tipo de estrucutura
//Variables auxiliar para el Grafo
int peso_actual; //Contenedor del peso actual recorrido para llegar a este nodo
struct nodo *mejor_ruta; //Indice de la mejor ruta para llegar al nodo de la ultima busqueda -1 para datos no inicializados
int visitado; //Variable Entera de Visitado, almacena un numero Ramdon para deteminar si fue visitado o no por el proceso actual
int out;
int total; //Total de vetices conectados a reste Nodo
int *aristas; //En caso de que existan distintos pesos para viajar al X vertice se ponen aqui
struct nodo **vertices; //Distintos vertices que se pueden alcanzar desde este Nodo
//int *vertices; //En caso de aplicar un nodo por indices a un arreglo de nodos
};

struct grafo {
int total; // Total de nodos validos en el grafo
int disponible; // Total de espacios asignables en el grafo
struct nodo **nodos; //tabla de acceso rapido a X nodo
};


struct grafo *add(struct grafo *grafo_actual,int origen, int peso, int destino);
void add_nodo(struct grafo *grafo_actual,int origen,int peso,int destino);
int dijkstra(struct nodo *nodo_a,struct nodo *nodo_b);
int menor_ruta(struct grafo *grafo_actual,int A,int B);

int main() {
struct grafo *grafo = NULL;
/*
struct grafo *add(struct grafo *grafo_actual,int origen, int peso, int destino);
*/
grafo = add(grafo,1, 7,2);
grafo = add(grafo,1, 9,3);
grafo = add(grafo,1,14,6);
grafo = add(grafo,6, 9,5);
grafo = add(grafo,6, 2,3);
grafo = add(grafo,3,11,4);
grafo = add(grafo,3,10,2);
grafo = add(grafo,2,15,4);
grafo = add(grafo,4, 6,5);
printf("Ruta %i\n",menor_ruta(grafo,1,5));
return 0;
}

int menor_ruta(struct grafo *grafo_actual,int A,int B) {
return dijkstra(grafo_actual->nodos[A-1],grafo_actual->nodos[B-1]);
}

struct grafo *add(struct grafo *grafo_actual,int origen, int peso, int destino) {
/*
Variables
*/
int mayor = destino;
struct nodo **temp = NULL;
/*
Inicializamos el grafo en caso de que no exista
*/
if(grafo_actual == NULL) {
grafo_actual = calloc(1,sizeof(struct grafo));
}
/*
Determinamos el indice mayor
*/
if(origen > destino) {
mayor = origen;
}
/*
Evaluamos si tenemos espacio suficiente
*/
if(mayor > grafo_actual->disponible) {
/*
En caso de no tener espacio suficiente lo reasignamos
*/
temp = calloc(mayor,sizeof(struct nodo*));
if(temp) {
if(grafo_actual->nodos) {
memcpy(temp,grafo_actual->nodos,grafo_actual->disponible*sizeof(struct nodo*));
free(grafo_actual->nodos);
grafo_actual->nodos = NULL;
}
grafo_actual->nodos = temp;
grafo_actual->disponible = mayor;
}else {
printf("Memory out!!\n");
exit(0);
}
}
/*
Inicializamos los nodos en caso de que no existan
*/
if(grafo_actual->nodos[origen-1] == NULL) {
grafo_actual->nodos[origen-1] = calloc(1,sizeof(struct nodo));
grafo_actual->nodos[origen-1]->id = origen;
grafo_actual->total++;
}
if(grafo_actual->nodos[destino-1] == NULL) {
grafo_actual->nodos[destino-1] = calloc(1,sizeof(struct nodo));
grafo_actual->nodos[destino-1]->id = destino;
grafo_actual->total++;
}

/*
Agregamos las Pesos y Aristas
*/
add_nodo(grafo_actual,origen,peso,destino);
add_nodo(grafo_actual,destino,peso,origen);

/*
Retornamos el grafo_actual
*/
return grafo_actual;
}

void add_nodo(struct grafo *grafo_actual,int origen,int peso,int destino) {
struct nodo *aux = grafo_actual->nodos[origen-1];
aux->aristas = realloc(aux->aristas,sizeof(int)*(aux->total+1));
aux->vertices = realloc(aux->vertices,sizeof(int)*(aux->total+1));
aux->aristas[aux->total]  = peso;
aux->vertices[aux->total] = grafo_actual->nodos[destino-1];
printf("Uniendo nodos: (%i)--[%i]--(%i)\n",origen,peso,destino);
aux->total++;
}

int dijkstra(struct nodo *nodo_a,struct nodo *nodo_b) {
struct nodo *inicio =NULL,*pivote = NULL;
struct nodo **pendientes = NULL; //Arreglo de nodos no visitados a un.
int i,j,total = 0;
int visitado = rand(); //Variable aleatoria para determinar si un Nodo ya fue visitado por esta ocacion
int peso_nuevo; //Variable temporal para evaluar cual es el menor peso al momento de visitar un nodo
i = 0;
pendientes = realloc(pendientes,sizeof(struct nodo*)*(total+1));
pendientes[total] = nodo_a; //Nodo inicial a visitar el el nodo A que se recibio como parametr
nodo_a->peso_actual = 0;
total++;
printf("Buscando ruta de %i a %i\n",nodo_a->id,nodo_b->id);
while(i < total) {
pivote = pendientes[i];
printf("Procesando el nodo %i\n",pivote->id);
if(pivote->out != visitado){ //Si aun no Agotamos el nodo actual
printf("Visitando %i\n",pivote->id);
j = 0;
while(j < pivote->total ) {
if(pivote->vertices[j]->out != visitado) {
if(pivote->vertices[j]->visitado != visitado) {
printf("El subnodo %i no a sido visitado\n",pivote->vertices[j]->id);
pendientes = realloc(pendientes,sizeof(struct nodo*)*(total+1));
pendientes[total] = pivote->vertices[j];
total++;
pivote->vertices[j]->peso_actual = pivote->peso_actual + pivote->aristas[j];
pivote->vertices[j]->mejor_ruta = pivote;
//printf("Ruta de %i a %i vale %i\n",nodo_a->id,pivote->vertices[j]->id,pivote->vertices[j]->peso_actual);
}
else { //Aqui ya lo visitamos, solo validaremos si la ruta pesa menos por este camino que por que se visito previamente
printf("El subnodo %i ya a sido visitado\n",pivote->vertices[j]->id);
//printf("El subnodo %i ya a sido visitado\n",pivote->vertices[j]->id);
peso_nuevo =  pivote->peso_actual + pivote->aristas[j];
printf("%i > %i ? %s\n",pivote->vertices[j]->peso_actual,peso_nuevo,(pivote->vertices[j]->peso_actual > peso_nuevo) ? "si":"no");
if(pivote->vertices[j]->peso_actual > peso_nuevo) { // Si esta condicion se cumple es mas rapido llegar al nodo pivote->vertices[j] mediante el nodo pivote
printf("Nueva mejor ruta a %i con peso de %i\n",pivote->vertices[j]->id,peso_nuevo);
pivote->vertices[j]->peso_actual = peso_nuevo;
pivote->vertices[j]->mejor_ruta = pivote;
}
printf("Ruta de %i a %i vale %i\n",nodo_a->id,pivote->vertices[j]->id,pivote->vertices[j]->peso_actual);
//En caso de que el if no se cumpla es mas rapido llegar al nodo pivote->vertices[j] de la manera en la ya habia sido visitado previamente
}
}
else {
//printf("El subnodo %i ya a sido visitado\n",pivote->vertices[j]->id);
printf("El subnodo %i ya a sido visitado\n",pivote->vertices[j]->id);
peso_nuevo =  pivote->peso_actual + pivote->aristas[j];
printf("%i > %i ? %s\n",pivote->vertices[j]->peso_actual,peso_nuevo,(pivote->vertices[j]->peso_actual > peso_nuevo) ? "si":"no");
if(pivote->vertices[j]->peso_actual > peso_nuevo) { // Si esta condicion se cumple es mas rapido llegar al nodo pivote->vertices[j] mediante el nodo pivote
printf("Nueva mejor ruta a %i con peso de %i\n",pivote->vertices[j]->id,peso_nuevo);
pivote->vertices[j]->peso_actual
= peso_nuevo;
pivote->vertices[j]->mejor_ruta = pivote;
}
printf("Ruta de %i a %i vale %i\n",nodo_a->id,pivote->vertices[j]->id,pivote->vertices[j]->peso_actual);
//En caso de que el if no se cumpla es mas rapido llegar al nodo pivote->vertices[j] de la manera en la ya habia sido visitado previamente
}
pivote->vertices[j]->visitado = visitado;
j++;
}
pivote->out = visitado;
printf("Nodo %i fuera!\n",pivote->id);
}
else {
printf("El nodo %i ya esta fuera\n",pivote->id);
}
i++;
}
free(pendientes);
return nodo_b->peso_actual;
}
#80
Muy buen dia estoy buscando optimizar el tamaño de una estructura dada.

Habia visto que es posible especificar el tamaño de una variable a nivel de bits.

struct nodo {
int id;
unsigned char tabla[4][4];
unsigned char x,y;
struct nodo *aristas[4];
};


Quiero optimizar las variables tabla, x é y

Las variables solo tiene valores del 0 al 15, con lo cual 4 bits serian suficientes.

Habia visto que se puede especificar el tamaño de la variable ejemplo:

struct nodo {
int id;
unsigned char tabla[4][4];
unsigned char x:4;
unsigned char y:4;
struct nodo *aristas[4];
};


Pero no se hacerlo para la variable tabla.

Saludos!
#81
El punto es en eficiencia de busqueda.

Estaba haciendo el grafo que propuse en

¿Imposible? Juego de Rompecabezas imposible

Casi todo marcha bien con el grafo a excepcion de la parte donde valido si un valor ya existe en el grafo. En el ultimo intento que hice llevaba maa de 140 mil nodos en el grafo y con  cada posible nodo nuevo tenia que validar la existencia de su valor en el grafo (Muy lento)

Posteriormente use arreglo de los nodos existentes (Igualmente lento).

Entonces voy a usar un Arbol Binario.

Y la pregunta es esa ¿Hay algo mas eficiente que un arbol binario?

Lo pregunto por que no me he actualizado en mas de 5 años en estructuras de datos, estaba contemplando una tabla hash pero nunca la estudie y dudo que sea mas eficiente que un arbol binario en lo que se refiere a insercion y busqueda de nodos.

Saludos
#82
Bueno les dejo aquí el código del Juego del imposible...

Se juega usando las teclas w,a,s,d como si fueran las flechas del teclado, esta seguida de un enter.

El reto "imposible" es definir dada la matriz inicial llegar a su forma inversa:

[ 1][ 2][ 3][ 4]
[ 5][ 6][ 7][ 8]
[ 9][10][11][12]
[13][14][15][  ]


[15][14][13][12]
[11][10][ 9][ 8]
[ 7][ 6][ 5][ 4]
[ 3][ 2][ 1][  ]



Y si, es IMPOSIBLE

/*
Juego del Imposible | Programación en C

[ 1][ 2][ 3][ 4]
[ 5][ 6][ 7][ 8]
[ 9][10][11][12]
[13][14][15][  ]
               
w
asd

Contacto
Twitter: @albertobsd
Email: alberto.bsd@gmail.com
*/
#include<stdio.h>

void imprimir_tablero();

int tabla[4][4];
int x= 3,y =3;

int main() {
int i = 0,j =0,contador = 1;
char caracter,enter;
//Inicializar la tabla o matriz de juego
while(i < 4) {
j = 0;
while(j < 4) {
tabla[i][j] = contador;
//printf("[%2i]",tabla[i][j]);
j++;
contador++;
}
printf("\n");
i++;
}
tabla[y][x] = 0;
imprimir_tablero();
do {
caracter = getchar();
enter = getchar();
switch(caracter) {
case 'w': //arriba
if(y <= 2) {
//Movimiento de ficha
tabla[y][x] = tabla[y+1][x];
tabla[y+1][x] = 0;
imprimir_tablero();
y++;
}
else {
printf("Fuera de los limites\n");
}
break;
case 's': //abajo
if(y >= 1) {
//Movimiento de ficha
tabla[y][x] = tabla[y-1][x];
tabla[y-1][x] = 0;
imprimir_tablero();
y--;
}
else {
printf("Fuera de los limites\n");
}
break;
case 'a': //izquierda
if(x <= 2) {
//Movimiento de ficha
tabla[y][x] = tabla[y][x+1];
tabla[y][x+1] = 0;
imprimir_tablero();
x++;
}
else {
printf("Fuera de los limites\n");
}

break;
case 'd': //derecha
if(x >= 1) {
tabla[y][x] = tabla[y][x-1];
tabla[y][x-1] = 0;
imprimir_tablero();
x--;
}
else {
printf("Fuera de los limites\n");
}
break;
case '0': //Salida
break;
default:
printf("Caracter Incorrecto");
break;
}
printf("Caracter : %c\n",caracter);
}while(caracter != '0');
return 0;
}

void imprimir_tablero() {
int i = 0,j;
while(i < 4) {
j = 0;
while(j < 4) {
if(tabla[i][j] != 0) {
printf("[%2i]",tabla[i][j]);
}
else {
printf("[  ]");
}
j++;
}
printf("\n");
i++;
}
}



Video:

[youtube=640,360]https://www.youtube.com/watch?v=etbTecakXFg[/youtube]

Dejo también un Documento donde se explica de forma matemática por que es imposible el acomodo invertido dada una posición inicial.

http://miscelaneamatematica.org/Misc40/Campos_r.pdf

Aclaro que ese documento no es mio, lo realizaron los autores ahí señalados en el mismo.

Saludos!
#83
En la cuenta de Twitter de Den Delimarsky se puede leer que la aplicación por falta de validacion de certificado es vulnerable a ser engañada mediante un proxy y con llamadas a la API es posible navegar en el mundo de pokemon go desde la comodidad del hogar y sin los peligros de ser atropellado en la calle.

@DennisCode

https://twitter.com/DennisCode/status/751592223330881536

CitarPokemon Go... get yourself whatever you want because I can hook directly into the APIs with mitmproxy. No cert check

Saludos!
#84
Aunque no he usado Tapatalk

He visto que siempre deja titulos "Re:" sin el titulo original del tema.

Deberian de solucionar eso xD.

Saludos
#85
Foro Libre / Juego: Premios y Castigos
8 Julio 2016, 14:56 PM
Muy buen dia.

Estoy haciendo un pequeño juego en la casa (No tiene nada que ver con computadoras) y necesitaba algunas ideas frescas para los premios y/o castigos.

El detalle de esto es que estoy haciendo una estadística y quiero que en base a los premios y/o catigos los jugadores esten muy motivados para ganar.

Estaba desempolvado la vieja mesa de tortura medieval que consegui en la deepweb  :rolleyes:  :rolleyes:  :xD pero creo que no aplica para el juego xD

La primera opcion que pense es dinero como premio o que lo paguen como castigo pero no se ustedes que sugieren?

Tambien pense en los siguientes castigos

  • mini descargas electricas
  • Poner hielo en alguna parte del cuerpo

Espero sus comentarios

Saludos
#86
Muy buen dia como saben en mi canal de youtube tengo tutoriales de programación en C el ultimo que hice es el juego de Piedra Pepel y Tijera algo sencillo pero usando una Tabla de Estados simulando la forma mas básica de un autómata.

Dejo el codigo no sin antes proponerles un reto y es el siguiente: Dado el código siguiente modificarlo para que el programa sea capaz de "aprender" del histórico de jugadas del usuario y asi sea capas de predecir la próxima jugada.

Este aprendizaje no debe de perderse (Por lo tanto se debe de poder guardar para ser cargados en Futuros juegos)

/*
Realizado por Luis Alberto

Contacto
Twitter: @albertobsd

*/
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include<stdbool.h>

//Constantes para las jugadas
#define PIEDRA 0
#define PAPEL 1
#define TIJERA 2


int main() {
int jugador = 0, computadora = 0; // Variables para la seleccion de los Jugadores (Usuario - Computadora)
char *jugadas[3] = {"Piedra","Papel","Tijera"}; //Cadenas para imprimir segun lo seleccionado por las variables Anteriores

/*
Exclusivamente para el resultado (Matriz bidimencional)

Columnas para la Computadora
Filas para el Jugador

Valores:
- 1 si el jugador Gana
- 0 si el jugador Empata
- 2 si el jugador Pierde
[0][P][G]
[G][0][P]
[P][G][0]

*/
int resultados[3][3] = {{0,2,1},
{1,0,2},
{2,1,0}};
char *resultados_str[3] = {"El jugador Empata","El Jugador Gana","El jugador Pierde"}; // Cadenas con los resultados
bool entrar = true; //Variable para detener el ciclo
int opcion; //Opcion seleccionada
char temp[10]; //Variable temporal para guardar la entrada desde el teclado
char *valor = NULL; //Puntero adicional usado por strtol
srand(time(NULL)); // inicializar la semilla Pseudo-Aleatoria
do {
computadora = rand() % 3; //Valor seleccionado por la computadora al azar
//Menu para el usuario
printf("1) %s\n",jugadas[PIEDRA]);
printf("2) %s\n",jugadas[PAPEL]);
printf("3) %s\n",jugadas[TIJERA]);
printf("S) Salir\n");
printf("Ingrese su opcion: ");
fgets(temp,10,stdin); // Capturamos texto
opcion = strtol(temp,&valor,10); //Convertimos el texto a Entero
if(valor[0] == '\0' || valor[0] == 0x0a) { //Si es un valor valido continuas
switch(opcion) { //switch para las opciones pero se pudo usar un IF
case 1:
case 2:
case 3:
jugador = opcion - 1; //Seleccion del Jugador
//resultados:
printf("La computadora elijio %s\n",jugadas[computadora]);
printf("El jugador elijio %s\n",jugadas[jugador]);
printf("Resultado: %s\n",resultados_str[resultados[jugador][computadora]]);
break;
default:
printf("Aprende a leer solo valores del 1 al 3 o la letra S mayuscula\n");
break;
}
}
else { //Si no es valor valido posiblemente sea una S
//printf("Elijio %.2x\n",valor[0]);
if(temp[0] == 'S') { //Si es S establecemos la variable para salir del ciclo
entrar = false;
}
}
}while(entrar);
return 0;
}


Aqui les dejo el vídeo mencionado:

[youtube=640,360]https://www.youtube.com/watch?v=OPP5fua87ew[/youtube]

Saludos!


He creado una estructura para guardar los resultados y posteriormente guardar la estructura en un archivo

De hecho son 2 estrucuturas:

struct nodo_ppt {
int count;
int respuesta[3];
};


La estrucutura anterior guarda un contador para indicar cuantas veces se a entrado a ese nodo y posteriormente cual fue la respuesta a esto.

Por ejemplo tenemos un arreglo de  9 nodos
struct nodo_ppt nodos[9];

Y por ejemplo se juega Piedra(Jugador) vs Tijera(Computadora) entonces al igual que en la matriz de resultados:

int resultados[3][3] = {{0,2,1},{1,0,2},{2,1,0}};

Entonces guardamos como nodos "previo" la posicion de nodos [(Jugador*3) +computadora]  y en el proximo juego incrementamos la seleccion del jugador en el nodo previo y nuevamente ajustamos el nodo previo a la seleccion actual y repetimos.

Con esto tendremos un histórico de (Si en el juego anterior se juego X entonces en el juego siguiente Jugara Y (con mas probabilidad)) donde Y es el mayor numero seleccionado en el contador de respuesta
#87
En windos 10 cada que ejecuto chrome me sale un aviso de que el Edge esto o el otro (Por parte de M$) Claro... Como se deshabilita ese molesto aviso?

Saludos
#88
No recuerdo si ya lo han pedido antes.

Pero la idea es poder insertar tweeta dada su URL, asi como cuando agregas un video de youtube.

Saludos

#89
Sin duda un golpe mas para la seguirdad de millones de usuarios, mediante fuerza bruta y algunos otros vectores de ataques! logran conseguir llaves privadas para el cifrado de los teléfonos Android con procesador Qualcomm

Desde la version 5 de android, Google implemento el cifrado completo del "disco" en sus terminales usando el password del usuario para crear una clave RSA de 2048 bits la cual ea guardada en la trustzone para cifrar el disco.

Pues bien mediente varias vulnerabilidades el atacante  es capas de extraer esta llave privada y mediante un proceso de fuerza bruta obtener asi el password del usuario.

Mas info: http://thehackernews.com/2016/07/hacking-android-encryption.html?m=1

Si en Ingles!!

Saludos!
#90
Entre las lecturas que me topo dia con dia aparecio la siguiente

ECB Byte at a Time

Aun que esta en ingles muestra el proceso basico pata determinar el factor de secret en un cifrado por bloque usando AES_ECB

AES_ECB(INPUT + SECRET, KEY)

Y eso solo es posible si tienes el control de INPUT.

Espero y les sirva.

Saludos