2026-08-19 22:16:17 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Main.mqh |
|
| | | //| Copyright 2026, Niquel Mendoza |
|
| | | //| https://www.mql5.com |
|
| | | //+------------------------------------------------------------------+
|
| | | #property copyright "Copyright 2026, Niquel Mendoza"
|
| | | #property link "https://www.mql5.com"
|
| | | #property strict
|
| | |
|
| | | #ifndef CRYPTOBYLEO_SRC_PADDING_PSS_MAIN_MQH
|
| | | #define CRYPTOBYLEO_SRC_PADDING_PSS_MAIN_MQH
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include "..\\..\\MGF1\\Main.mqh"
|
| | |
|
2026-08-20 11:04:12 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // https://datatracker.ietf.org/doc/html/rfc8017#section-9.1
|
| | |
|
2026-08-20 17:10:56 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // maximo tamaño de salt en esta implemtacion (max HLEN * 4)
|
| | | // mas de eso no tiene mucho sentido
|
| | | #define PSS_MAX_SIZE_SALT (CRYPTOBYLEO_HASHFUNC_FIXED_MAX_OL<<2)
|
| | |
|
2026-08-19 22:16:17 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | class CPSS
|
| | | {
|
| | | public:
|
| | | CPSS(void) {}
|
| | | ~CPSS(void) {}
|
| | |
|
2026-08-20 19:39:46 -05:00 | | | //---
|
2026-08-23 19:36:33 -05:00 | | | // msg= array de bytes
|
| | | // slen= len del salt
|
| | | // salt= datos random
|
| | | // em_bits=(modBits - 1) osea longitud del modulo (n) en bits -1
|
| | | // f=funcion de hasheo
|
| | | // out=array de salida
|
2026-08-20 19:39:46 -05:00 | | | static int Encode(const uchar &msg[], int slen, const uchar& salt[], int em_bits,
|
| | | TSN::CCryptoHashMeta::ENUM_TSN_CRYPTO_HASH f, uchar &out[]);
|
| | |
|
| | | //---
|
2026-08-23 19:36:33 -05:00 | | | // msg= original
|
| | | // em = mensaje codificado (firmado)
|
| | | // em_bits=(modBits - 1) osea longitud del modulo (n) en bits -1
|
| | | // f=funcion de hash
|
| | | // slen=lent del salt
|
| | | static bool Verify(const uchar &msg[], const uchar &em[], int em_bits,
|
| | | TSN::CCryptoHashMeta::ENUM_TSN_CRYPTO_HASH f, int slen);
|
2026-08-19 22:16:17 -05:00 | | | };
|
| | |
|
2026-08-20 17:10:56 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | /*
|
| | |
|
| | | +-----------+
|
| | | | M |
|
| | | +-----------+
|
| | | |
|
| | | V
|
| | | Hash
|
| | | |
|
| | | V
|
| | | +--------+----------+----------+
|
| | | M' = |Padding1| mHash | salt |
|
| | | +--------+----------+----------+
|
| | | |
|
| | | +--------+----------+ V
|
| | | DB = |Padding2| salt | Hash
|
| | | +--------+----------+ |
|
| | | | |
|
| | | V |
|
| | | xor <--- MGF <---|
|
| | | | |
|
| | | | |
|
| | | V V
|
| | | +-------------------+----------+--+
|
| | | EM = | maskedDB | H |bc|
|
| | | +-------------------+----------+--+
|
| | | */
|
| | |
|
2026-08-19 22:16:17 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-20 11:04:12 -05:00 | | | static int CPSS::Encode(const uchar &msg[], int slen, const uchar& salt[], int em_bits,
|
| | | TSN::CCryptoHashMeta::ENUM_TSN_CRYPTO_HASH f, uchar &out[])
|
2026-08-19 22:16:17 -05:00 | | | {
|
| | | //---
|
| | | const int hlen = TSN::CCryptoHashMeta::g_crytpo_hash_meta[f].outl; // tamañao de salida
|
| | | const int ml = ArraySize(msg);
|
| | |
|
| | | //---
|
| | | const int em_len = (em_bits + 7) >> 3;
|
| | | if(em_len < (hlen + slen + 2))
|
| | | return -1;
|
| | |
|
| | | //--- Tamaños
|
| | | /*
|
| | | // parte 1
|
| | | const int p1s = 8 + hlen + slen;
|
| | | luego se le aplica un H hash asi que euqda
|
| | | hlen
|
| | |
|
| | | // parte 2
|
| | | const int ps = (em_len - slen - hlen - 2);
|
| | | const int dbs = ps + 1 + slen;
|
| | |
|
| | | // ems
|
| | | = dbs + hlen + 1
|
| | |
|
| | | */
|
| | |
|
2026-08-20 19:39:46 -05:00 | | | //----
|
| | | const int req_s = ((em_len - 1) << 1) - hlen;
|
| | | if(req_s > ArraySize(out))
|
| | | ArrayResize(out, req_s);
|
| | |
|
2026-08-20 11:04:12 -05:00 | | | //---
|
2026-08-20 19:39:46 -05:00 | | | const TSN::CCryptoHashMeta::TsnCryptoByLeoHashFuncFixed func = TSN::CCryptoHashMeta::g_crypto_fhash_fixed[f];
|
2026-08-20 11:04:12 -05:00 | | |
|
2026-08-20 19:39:46 -05:00 | | | //---- Calcullo de los tamaños que necesitaremos reservar
|
| | | //
|
2026-08-20 17:10:56 -05:00 | | | // DB = PS + b"\x01" + salt
|
2026-08-20 19:39:46 -05:00 | | | //
|
| | | // dbs = (em_len - slen - hlen - 2) + 1 + slen
|
| | | // dbs = em_len - hlen - 2 + 1
|
| | | // dbs = em_len - hlen - 1
|
| | | // final_size = dbs + hlen + 1
|
| | | // final_size = em_len - hlen - 1 + hlen + 1
|
| | | // final_size = em_len (total)
|
| | | //
|
| | | // mprima_size = (8 + hlen + slen)
|
| | | // +1=BC
|
| | | //
|
| | | // max_size = dbs + (8 + hlen + slen) + 1 ; (maximo tamaño que llega alcanzar)
|
| | | // max_size = em_len - hlen - 1 + 8 + hlen + slen + 1
|
| | | // max_size = em_len + 8 + slen
|
| | | //
|
| | | // En nuestro caso no llegaremos a usar eso si no:
|
| | | // = dbs + hlen + dbs
|
| | | // porque:
|
| | | // - dbs: parte inicial del layout
|
| | | // - hlen: H Prima inicial
|
| | | // - dbs (2): Neceistaremos un temproal para poder almacenar el tema del mask para DB
|
| | | // Asi que simplifiquemos lo que podamos
|
| | | // = dbs + hlen + dbs
|
| | | // = em_len - hlen - 1 + hlen + dbs
|
| | | // = em_len - 1 + dbs
|
| | | // nuestro tamaño final queda como:
|
| | | // = em_len - 1 + em_len - 1 - hlen
|
| | | // digamos que: x = em_len - 1
|
| | | // = x + x - hlen
|
| | | // = 2x - hlen
|
| | | // asi qeu usaremos eso para cualar el tamaño requerido para nuestras operaciones
|
| | |
|
| | | //--- parte 1
|
2026-08-19 22:16:17 -05:00 | | | // padding inicial
|
| | | const int ps = (em_len - slen - hlen - 2);
|
| | | int i = 0;
|
| | | for(; i < ps; i++)
|
| | | out[i] = 0;
|
| | | // 1
|
| | | out[i++] = 1;
|
| | | // salt
|
2026-08-20 19:39:46 -05:00 | | | for(int k = 0; k < slen; k++)
|
2026-08-20 11:04:12 -05:00 | | | out[i + k] = salt[k];
|
| | | i += slen;
|
2026-08-19 22:16:17 -05:00 | | |
|
2026-08-20 19:39:46 -05:00 | | | const int dbs = i;
|
| | |
|
2026-08-20 11:04:12 -05:00 | | | //----- parte 2
|
2026-08-20 17:10:56 -05:00 | | | // M_prima = b"\x00" * 8 + mHash + salt
|
2026-08-20 19:39:46 -05:00 | | | const int mprima_s = 8 + hlen + slen;
|
| | | uchar MPrima[8 + CRYPTOBYLEO_HASHFUNC_FIXED_MAX_OL + PSS_MAX_SIZE_SALT];
|
| | |
|
| | | //- Padding inicial
|
| | | MPrima[0] = 0;
|
| | | MPrima[1] = 0;
|
| | | MPrima[2] = 0;
|
| | | MPrima[3] = 0;
|
| | | MPrima[4] = 0;
|
| | | MPrima[5] = 0;
|
| | | MPrima[6] = 0;
|
| | | MPrima[7] = 0;
|
| | |
|
| | | //- Hash del mensaje
|
| | | func(msg, ml, MPrima, 8);
|
| | |
|
| | | //- concatenamos salt
|
| | | for(int k = 0; k < slen; k++)
|
| | | MPrima[8 + hlen + k] = salt[k];
|
| | |
|
2026-08-20 11:04:12 -05:00 | | |
|
| | | //---- Ahora le aplicamos otro hahs a la parte 2
|
2026-08-20 19:39:46 -05:00 | | | // tenemos que aplicarle la funcion hash a MPrima
|
| | | // el resultado va en [i ... hlen bytes] = H
|
| | | func(MPrima, mprima_s, out, i);
|
| | |
|
| | |
|
| | | //--- ahora toca crear la mascara
|
| | | const int i_mask = i + hlen; // inicio de donde estara la mascara
|
| | | // entonces:
|
| | | // tomamos: [i ... hlen bytes]
|
| | | // le aplicamos mgf1
|
| | | // resultado en: [i_mask ... dbs bytes]
|
| | | MGF1(out, i, hlen, out, i_mask, dbs, f);
|
| | |
|
| | | // reiniciamos i
|
| | | i = 0;
|
| | | // aplicamos un xor entre (DB Mask XOR DB)
|
| | | for(; i < dbs; i++)
|
| | | out[i] ^= out[i_mask + i];
|
| | |
|
| | | //--- por ultimos ponemos
|
| | | // pamaos a em len a bits
|
| | | const int bits_sob = (em_len << 3) - em_bits;
|
| | | if(bits_sob > 0)
|
| | | {
|
| | | // en caso haya bits sobrantes el byte 0 de masked DB (resultado db mask DB)
|
| | | // le aplicamos la mascara de bits para ponerlkos en 0 (and de 0 y x da 0)
|
| | | const uchar mask = uchar(0xff >> bits_sob);
|
| | | out[0] &= mask;
|
| | | }
|
| | |
|
| | | //--- BC
|
| | | // el final final (dbs + hlen) justo aqui lo pnemos con un valor de BC
|
| | | out[i_mask] = 0xBC;
|
| | | //terminamso
|
| | |
|
| | | //--- retornamos
|
| | | return em_len;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | static bool CPSS::Verify(const uchar &msg[], const uchar &em[], int em_bits, TSN::CCryptoHashMeta::ENUM_TSN_CRYPTO_HASH f, int slen)
|
| | | {
|
| | | const int hlen = TSN::CCryptoHashMeta::g_crytpo_hash_meta[f].outl; // tamañao de salida
|
| | | const int em_len = (em_bits + 7) >> 3; // /8 mathceil(em_bits / 8)
|
| | |
|
| | | //--- cheke de len del enconden message (creo qeu esto es por ps dado qeu si fuera menor el padding seria invalido)
|
| | | const int min = hlen + slen + 2;
|
| | | if(em_len < min)
|
| | | return false;
|
| | | //---
|
| | |
|
| | | if(ArraySize(em) != em_len)
|
| | | return false;// no es igual a lo esperado
|
| | |
|
| | | //---
|
| | | if(em[em_len - 1] != 0xbc)
|
| | | return false;// layout invalido
|
| | |
|
| | | //---
|
| | | const int dbs = em_len - hlen - 1;
|
| | |
|
| | | //---
|
| | | const int bits_sob = (em_len << 3) - em_bits;
|
| | | uchar mask = 0xff;
|
| | | if(bits_sob > 0)
|
| | | {
|
| | | // ahora la mascara que tenamis apagamos x bits ahora el tema es que
|
| | | // digmoas si tnemis la mascra 00110011
|
| | | // y por lo tanto el inverso 00110011 = 11001100
|
| | | // entonces un and entre ambos debe de dar 0
|
| | | // x and ~x = 0
|
| | | // pero si x (el nuevo) se modificdo dara > 0
|
| | | mask >>= uchar(bits_sob);
|
| | | if((em[0] & (~mask)) != 0)
|
| | | return false;
|
| | | }
|
| | |
|
| | | //---
|
| | | // empezmaos a leer desde [dbs ... hlen bytes] (Osea donde se ubicaaba H real)
|
| | | uchar db[];
|
| | | ArrayResize(db, em_len + 6 + dbs);
|
| | |
|
| | | //---
|
| | | const int i_db = min + 6; // empiza justo donde terminar m_prima (hlen+slen+8)
|
| | | MGF1(em, dbs, hlen, db, i_db, dbs, f);
|
| | |
|
| | | //---
|
| | | // obteenmmos la mascara de db ahora la corregiremos
|
| | | for(int i = 0; i < dbs; i++)
|
| | | db[i_db + i] ^= em[i];
|
| | |
|
| | | // aplicamos la mascara al primer elemento
|
| | | db[i_db] &= mask;
|
| | |
|
| | | //--- Ahora chekeamos DB
|
| | | // padding de zeros
|
| | | // ps = (em_len - slen - hlen - 2)
|
| | | const int fin = i_db + (em_len - slen - hlen - 2); // fin apunta al final de del padding
|
| | | int ip = i_db;
|
| | | // ahora ip esta justo en i_db
|
| | | for(; ip < fin; ip++)
|
| | | if(db[ip] != 0x0)
|
| | | return false;
|
| | |
|
| | | // byte 0x1 luego del padding
|
| | | if(db[ip++] != 0x1)
|
| | | return false;
|
| | | // ip arhao mismo apuinta a la prima posicion de salt
|
| | |
|
| | | //--- ahora verficiameso el slen
|
| | | // (dbs + i_db) nos da el fin real en db del array DB
|
| | | if(slen != ((dbs + i_db) - ip)) // (dbs - ip) nos da el tamaño del slen real
|
| | | return false; // no coincidio
|
| | |
|
| | | //--- ahora m_prima
|
| | | // Ahora el pro qeu agrege al buffer dbs un hlen:
|
| | | // em_len > hlen + slen + 2
|
| | | // dbs = em_len - hlen - 1
|
| | | // como dbs no es 0 entonces como minimo es mayor a slen
|
| | | // dado qeu emlen es mayot a hlen+slen+2 eso quiere deicr qeu si le restamos hlen y 1
|
| | | // entonces aun nos queda slen+1 como minimo
|
| | | // em_len - hlen - 1 > slen + 1
|
| | | // asi que: dbs > slen + 1
|
| | | // si garanzamis el peor caso=slen 0
|
| | | // entonces dbs>1
|
| | | // pero hlen como minimo (pro el minimo hash) hlen>=31
|
| | | // si totamos un caso borde
|
| | | // hlen=32, slen=0
|
| | | // emlen como minoimo > 34
|
| | | // por lo que el minimo valo rde dbs = 35 - 32 - 1 = 2 (cumple mayor que 1)
|
| | | // debido a esto.. nuestro peor caso tnemos un len de dbs=2 que no cumple
|
| | | // con la condicino de ser mayor o igual a hlen
|
| | | // asi que debemos de sumar hlen aparte como lo reutilizamos para armar prima
|
| | | // tiene que ser mayor a > 8 + hlen + slen
|
| | | // en nuestro caso borde no lo seria.. asi que aumentos + 8 tambien para cumplir eso
|
| | | // bueno estuve dando rodeos a este tema pero note algo
|
| | | // partimso de que emlen > hlen + slen + 2
|
| | | // entonces tambien sabes que emlen > dbs
|
| | | // asi qeu para que peuda cumplir que m_prima_size < em_len
|
| | | // summeos 6 a ambos lados de la inecuaion
|
| | | // emlen + 6 > hlen + slen + 2 + 6
|
| | | // ahora si em_len + 6 > hlen + slen + 8
|
| | | // por lo qeu ahora mismo tenemos que si reservmaos con eso nuestro buffer sera mayor a:
|
| | | // - m_prima
|
| | | // - dbs
|
| | | // entonces esto es lo suficiente para nuestro uso..
|
| | |
|
| | |
|
| | | //--- bueno ahroa si obtengamos m-prima
|
| | | // ahora para poder usar 8+hlen bytes sin pisar el salt previo tenemso qeu verificar qeu
|
| | | // ps+1 > 8 + hlen
|
| | | // ps = (em_len - slen - hlen - 2) | + 1
|
| | | // v = em_len - slen - hlen - 1
|
| | | // para empzar ps!=0 dado qeu em_len>hlen + slen + 2
|
| | | // asi qeu el minimo valor que toma esta exprecion sera de 2 (1+1)
|
| | | // por lo qeu tampoco... es candidatara a reutlizacion
|
| | | // Bueno hagamos algo
|
| | | // db es este
|
| | | // [......][....]
|
| | | // lo partiremos en dos partes la prienmra es donde pondre M Prima (parte baja)
|
| | | // La parte alta ahi pondre todo el tema de DB
|
| | | // entonces para tener un len adecuado seria
|
| | | // dbs+m_len+6 con eso cubro un m_prima+dbs
|
| | |
|
| | | //---- MPrima
|
| | | // ahora si empezmoas con el padding de zeros
|
| | | db[0] = 0;
|
| | | db[1] = 0;
|
| | | db[2] = 0;
|
| | | db[3] = 0;
|
| | | db[4] = 0;
|
| | | db[5] = 0;
|
| | | db[6] = 0;
|
| | | db[7] = 0;
|
| | |
|
| | | // Hasheos el mensaje primero (lo añadimos)
|
| | | const CCryptoHashMeta::TsnCryptoByLeoHashFuncFixed func = TSN::CCryptoHashMeta::g_crypto_fhash_fixed[f];
|
| | | func(msg, ArraySize(msg), db, 8);
|
| | |
|
| | | // ahora añdimos el salt (qeu esta en la parte alta justo en ip apartirt de ahi iterarmos)
|
| | | for(int i = 0; i < slen; i++)
|
| | | {
|
| | | // se posiciona justo donde ira el salt lo copiamos ahi
|
| | | db[i + 8 + hlen] = db[ip + i];
|
| | | }
|
| | |
|
| | |
|
| | | //--- parte final lo mutamos para uqe ahora tenga el H real
|
| | | func(db, i_db, db, 0); // 0= empiza a escribir en 0
|
2026-08-19 22:16:17 -05:00 | | |
|
2026-08-20 19:39:46 -05:00 | | | //---- por ultimo comparamos este H obteneido con el H real del em
|
| | | uchar v = 0;
|
| | | for(int i = 0; i < hlen; i++)
|
| | | {
|
| | | v |= db[i] ^ em[i + dbs];
|
| | | }
|
| | | return v == 0;
|
2026-08-19 22:16:17 -05:00 | | | }
|
| | |
|
| | | }
|
| | |
|
| | | #endif // CRYPTOBYLEO_SRC_PADDING_PSS_MAIN_MQH
|