2026-08-23 19:36:33 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| Public.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_RSA_KEYS_PUBLIC_MQH
|
| | | #define CRYPTOBYLEO_SRC_RSA_KEYS_PUBLIC_MQH
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | #include "H.mqh"
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | namespace TSN
|
| | | {
|
2026-08-29 20:40:52 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-30 10:39:49 -05:00 | | | void CRsaPublicKey::Load(BigUInteger &n, const ulong e, int totaln_bits)
|
2026-08-29 20:40:52 -05:00 | | | {
|
| | | m_n.RobarDe(n);
|
| | | m_e = e;
|
2026-08-31 08:11:57 -05:00 | | | m_total_sbits = totaln_bits;
|
| | | m_total_sbytes = totaln_bits >> 3;
|
2026-08-29 20:40:52 -05:00 | | | }
|
| | |
|
2026-08-23 19:36:33 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CRsaPublicKey::Verify(const uchar &firma[], const uchar &data[])
|
| | | {
|
2026-08-30 10:39:49 -05:00 | | | /*
|
2026-08-29 21:53:22 -05:00 | | | switch(m_sing_padder)
|
2026-08-24 09:57:30 -05:00 | | | {
|
| | | case RSA_SING_PADDER_PSS:
|
| | | {
|
| | | // m_sing_fhash uso del hash base para este firmado (se usa en pss y en mgf1 dos en uno)
|
2026-08-30 10:39:49 -05:00 | | | //return CPSS::Verify(data, firma, m_total_sbits - 1, m_sing_fhash, m_sing_data.salt_len);
|
2026-08-24 09:57:30 -05:00 | | | }
|
| | | case RSA_SING_PADDER_PKCS1V15:
|
| | | {
|
| | |
|
| | | return;
|
| | | }
|
| | | default:
|
| | | break;
|
2026-08-30 10:39:49 -05:00 | | | }*/
|
2026-08-29 17:17:26 -05:00 | | | return true;
|
2026-08-24 09:57:30 -05:00 | | | }
|
| | |
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-29 21:53:22 -05:00 | | | template <typename TRandomFunc>
|
2026-08-24 09:57:30 -05:00 | | | bool CRsaPublicKey::Cifrar(const uchar &raw[], uchar &out[])
|
| | | {
|
2026-08-29 21:53:22 -05:00 | | | //---
|
| | | uchar em[];
|
2026-09-01 12:16:15 -05:00 | | | TRandomFunc::RandomCryptoBytes(m_cip_random_bytes, TSN::CCryptoHashMeta::g_crytpo_hash_meta[m_cip_fhash].outl);
|
2026-08-30 10:39:49 -05:00 | | | if(COAEP::Encode(raw, m_total_sbytes, m_cip_random_bytes, m_cip_fhash, em) == -1)
|
2026-08-29 21:53:22 -05:00 | | | return false;
|
2026-08-23 19:36:33 -05:00 | | |
|
2026-08-29 21:53:22 -05:00 | | | //---
|
| | | m_base.FromBytesBE(em);
|
| | | m_base.PowMod(m_e, m_n);
|
2026-08-23 19:36:33 -05:00 | | |
|
2026-08-29 21:53:22 -05:00 | | | //---
|
2026-08-30 10:39:49 -05:00 | | | m_base.ToBytesBE(out, 0, m_total_sbytes);
|
2026-08-29 17:17:26 -05:00 | | | return true;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | /*
|
| | | SubjectPublicKeyInfo ::= SEQUENCE {
|
| | | algorithm AlgorithmIdentifier,
|
| | | subjectPublicKey BIT STRING }
|
| | |
|
| | | AlgorithmIdentifier ::= SEQUENCE {
|
| | | algorithm OBJECT IDENTIFIER, -- rsaEncryption: 1.2.840.113549.1.1.1
|
| | | parameters NULL }
|
| | |
|
| | | -- El contenido del BIT STRING es a su vez:
|
| | | RSAPublicKey ::= SEQUENCE {
|
| | | modulus INTEGER, -- n
|
| | | publicExponent INTEGER -- e
|
| | | }
|
| | | */
|
| | |
|
2026-08-30 10:39:49 -05:00 | | | //+------------------------------------------------------------------+
|
2026-08-29 17:17:26 -05:00 | | | int CRsaPublicKey::ToSubjectPublicKeyInfo(uchar &buf[], int w = 0) const
|
| | | {
|
| | | //--- Empezamosres claculasl el len de todo
|
| | | //-- De abajo ahcia arriab emepzoas con los numeros
|
| | | //- E
|
| | | int e_k;
|
| | | uchar e_wl;
|
| | | bool e_he;
|
2026-08-30 13:43:59 -05:00 | | | int e_len = CNumberDERUtils::DEREstimateLen(m_e, e_k, e_he, e_wl);
|
2026-08-29 17:17:26 -05:00 | | | //-- N
|
| | | bool n_he;
|
| | | int n_k;
|
| | | uchar n_wl;
|
| | | int n_len = m_n.DerEstimateLen(n_he, n_k, n_wl);
|
| | | //-- Nivel mas arriba BIT STRING
|
| | | uchar rsa_lenw;
|
2026-08-30 13:43:59 -05:00 | | | int rsa_len = CASN1Utils::ContentTotalBytes(n_len + e_len, rsa_lenw);
|
2026-08-29 17:17:26 -05:00 | | | // 1 = unnuseds bits
|
2026-08-30 10:39:49 -05:00 | | | uchar bits_lenw;
|
2026-08-30 13:43:59 -05:00 | | | int bits_total = CASN1Utils::ContentTotalBytes((1 + rsa_len), bits_lenw);
|
2026-08-29 17:17:26 -05:00 | | | //--- parte 2 (AlgorithmIdentifier + BIT
|
| | | uchar total_lenw;
|
2026-08-30 13:43:59 -05:00 | | | int total = CASN1Utils::ContentTotalBytes(RSA_ALG_OID_TSIZE + bits_total, total_lenw);
|
2026-08-29 17:17:26 -05:00 | | |
|
| | | //--- Ahora siahora mismo estamos en el "top" ahora bajamos
|
| | | if(total + w > ArraySize(buf))
|
| | | ArrayResize(buf, total + w);
|
| | |
|
| | | //--- Inicaimos
|
| | | // SubjectPublicKeyInfo
|
2026-08-30 13:43:59 -05:00 | | | buf[w++] = CBL_ASN1_TAG_SEQUENCE;
|
| | | CBL_ASN1_U_WRITELEN(buf, w, total_lenw, total)
|
2026-08-29 17:17:26 -05:00 | | | // Ahora copy tal cual
|
| | | w += ArrayCopy(buf, g_rsa_alg_id, w, 0, RSA_ALG_OID_TSIZE);
|
| | |
|
| | | //-- seguimso con bit string
|
2026-08-30 13:43:59 -05:00 | | | buf[w++] = CBL_ASN1_TAG_BITSTRING;
|
| | | CBL_ASN1_U_WRITELEN(buf, w, bits_lenw, bits_total)
|
| | | buf[w++] = CBL_ASN1_V_UNUSED_BITS;
|
2026-08-29 17:17:26 -05:00 | | |
|
| | | //-- rsa
|
2026-08-30 13:43:59 -05:00 | | | buf[w++] = CBL_ASN1_TAG_SEQUENCE;
|
| | | CBL_ASN1_U_WRITELEN(buf, w, rsa_lenw, rsa_len)
|
2026-08-29 17:17:26 -05:00 | | | // n
|
| | | BIGUINTEGERBYLEO_DER_WRITE(buf, w, m_n, n_he, n_k, n_wl, n_len)
|
| | | // e
|
| | | NUMBERUTILS_DER_WRITE_NUMBER(buf, w, m_e, ulong, e_he, e_k, e_wl, e_len)
|
| | | return w;
|
| | | }
|
| | |
|
| | |
|
2026-08-30 10:39:49 -05:00 | | |
|
| | |
|
2026-08-29 17:17:26 -05:00 | | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
2026-08-30 15:01:10 -05:00 | | | // Aqui elegi este diseño dado qeu noramlte cuando hay una deciion de disñeo como esta
|
| | | // me pongo a testear y hacer benchs, la cosa es que habai tres candidasots
|
| | | // 1. B64 Manual + \r\n cada 48 bytes
|
| | | // 2. Cada 48 bytes callear a b64 natvo y insertar \r\n
|
| | | // 3. Bulk masivo de b64 y luego copiar trozos e insetar \r\n
|
2026-08-31 08:11:57 -05:00 | | | // Al final testenado el 3. ha sido mas rapido.... y el 1. como segundo mas rapido
|
2026-08-30 15:01:10 -05:00 | | | // (pero no era muha difenica 10%~ aprox) esto en parte se debe a que el b64 nativo
|
2026-08-31 08:11:57 -05:00 | | | // me da qeu no usa algo rapido por dbeajo tipo una lib con simd o algo si no mas bien
|
| | | // una imepltacion funcional en cpp puro sin los ckeos de rango a cada acceso...
|
2026-08-30 15:01:10 -05:00 | | | // dado que la version en MQL5 puro en mi caso es 160mb\s mas lento que la version nativa
|
| | | // Lo otro el ArrayCopy intemante tampco hace ckehs (solo una vez) por lo qeu tambien
|
2026-08-31 08:11:57 -05:00 | | | // el costo que se nos cva en allocar un buffer entero ya quizas lo cubren esos dos factores..
|
2026-08-30 15:01:10 -05:00 | | | // tema de acceso.
|
| | | // Por cierto ese material del los bench estan en (DiseñoBenchs)
|
2026-08-29 20:40:52 -05:00 | | | int CRsaPublicKey::ToSubjectPublicKeyInfoPem(uchar &buf[], int w = 0) const
|
2026-08-29 17:17:26 -05:00 | | | {
|
2026-08-29 20:40:52 -05:00 | | | //---
|
| | | // inplace (sin otro buffer hasta ahora 2 buffers en juego)
|
| | | uchar raw[];
|
| | | ToSubjectPublicKeyInfo(raw);
|
2026-08-29 17:17:26 -05:00 | | |
|
2026-08-29 20:40:52 -05:00 | | | //---
|
2026-09-01 17:56:09 -05:00 | | | // NOTA quizas cambie esto dado qeu no se puede hacer eso....
|
| | | //
|
2026-08-29 20:40:52 -05:00 | | | const int n = CryptEncode(CRYPT_BASE64, raw, raw, raw);
|
| | | const int lines = (n + 63) >> 6; // ceil(n/64)
|
| | |
|
| | | //---
|
| | | const int final_s = w + RSA_PUBKEY_PEMHEADER_SIZE + (n + (lines << 1)) + RSA_PUBKEY_PEMFOOTER_SIZE;
|
| | | if(final_s > ArraySize(buf))
|
| | | ArrayResize(buf, final_s);
|
2026-08-29 17:17:26 -05:00 | | |
|
2026-08-29 20:40:52 -05:00 | | | //--- header
|
| | | w += ArrayCopy(buf, g_rsa_pubkey_pem_header, w, 0, RSA_PUBKEY_PEMHEADER_SIZE);
|
2026-08-23 19:36:33 -05:00 | | |
|
2026-08-29 20:40:52 -05:00 | | | //--- in
|
| | | int pos = 0;
|
| | | while(n - pos >= RSA_PUBKEY_PEM_LINESIZE)
|
| | | {
|
| | | w += ArrayCopy(buf, raw, w, pos, RSA_PUBKEY_PEM_LINESIZE);
|
| | | buf[w++] = '\r';
|
| | | buf[w++] = '\n';
|
| | | pos += RSA_PUBKEY_PEM_LINESIZE;
|
| | | }
|
| | | if(pos < n)
|
| | | {
|
| | | const int fin = n - pos;
|
| | | w += ArrayCopy(buf, raw, w, pos, n);
|
| | | buf[w++] = '\r';
|
| | | buf[w++] = '\n';
|
| | | }
|
| | |
|
| | | //--- footer
|
| | | w += ArrayCopy(buf, g_rsa_pubkey_pem_footer, w, 0, RSA_PUBKEY_PEMFOOTER_SIZE);
|
| | | return w;
|
2026-08-23 19:36:33 -05:00 | | | }
|
| | |
|
2026-08-31 08:11:57 -05:00 | | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | bool CRsaPublicKey::LoadSubjectPublicKeyInfo(const uchar &buf[], int r = 0)
|
| | | {
|
| | | if(buf[r++] != CBL_ASN1_TAG_SEQUENCE)
|
| | | return false; // err
|
| | | // saltamos len
|
| | | CBL_ASN1_U_SALTAR_LEN(buf, r)
|
| | | // ahora si chekeamos OID (tiene que ser RSA)
|
| | | for(int i = 0; i < RSA_ALG_OID_TSIZE; i++)
|
| | | if(buf[r++] != g_rsa_alg_id[i])
|
| | | return false;
|
| | | // ahora bit string
|
| | | if(buf[r++] != CBL_ASN1_TAG_BITSTRING)
|
| | | return false;
|
| | | // len bit string
|
| | | CBL_ASN1_U_SALTAR_LEN(buf, r)
|
| | | // unused bit
|
| | | r++;
|
| | |
|
| | | //-- rsa
|
| | | if(buf[r++] != CBL_ASN1_TAG_SEQUENCE) // tag sequencue
|
| | | return false;
|
| | | //--
|
| | | CBL_ASN1_U_SALTAR_LEN(buf, r)
|
| | | //--- ahora leemos numero
|
| | | r = m_n.FromDER(buf, r);
|
| | | if(r == -1)
|
| | | return false;
|
| | | //--- terminamso con el exponente
|
| | | return CNumberDERUtils::DERRead(buf, r, m_e) >= r;
|
| | | }
|
| | |
|
| | | //+------------------------------------------------------------------+
|
| | | //| |
|
| | | //+------------------------------------------------------------------+
|
| | | // Diseño para el decode elegido en BE64_PUB_DEC
|
| | | bool CRsaPublicKey::LoadSubjectPublicKeyInfoPem(const uchar &buf[], int r = 0)
|
| | | {
|
| | | //---
|
| | | const int t = ArraySize(buf); // tamaño del buffer
|
| | |
|
| | | //--- Buscar el inicio
|
| | | r += RSA_PUBKEY_PEMHEADER_SIZE;
|
| | | //- saltar ws
|
| | | while(true)
|
| | | {
|
| | | if(buf[r] > 32)
|
| | | break;
|
| | | r++;
|
| | | if(r >= t)
|
| | | return false;
|
| | | }
|
| | | // ahora mismo en el primer carcater no ws
|
| | |
|
| | | //--- Ahora buscamos el fin
|
| | | int k = t - 1;
|
| | | //- saltar ws
|
| | | while(true)
|
| | | {
|
| | | if(buf[k] > 32)
|
| | | break;
|
| | | k--;
|
| | | if(k < 0)
|
| | | return false;
|
| | | }
|
| | | k -= RSA_PUBKEY_PEMFOOTER_CLEAN; // ahora restamos
|
| | | // saltamos ws que encontremos..
|
| | | while(true)
|
| | | {
|
| | | if(buf[k] > 32)
|
| | | break;
|
| | | k--;
|
| | | if(r >= t)
|
| | | return false;
|
| | | }
|
| | |
|
| | | //---
|
| | | // Justo en el inicio de b64
|
| | | uchar out[];
|
| | | const int rlen = (k - r) + 1;
|
| | | ArrayResize(out, ((rlen >> 2) + 1) * 3);
|
| | |
|
| | |
|
| | | //--- ahora si decodeamos
|
| | | int w = 0;
|
| | | uint acc = 0;
|
| | | int bits = 0;
|
| | |
|
| | | //---
|
| | | for(; r <= k; r++)
|
| | | {
|
| | | //---
|
| | | const uchar c = buf[r];
|
| | | if(c < 33 || c == '=')
|
| | | continue;
|
| | | //---
|
| | | acc = (acc << 6) | g_b64_decode[c];
|
| | | bits += 6;
|
| | | if(bits >= 8)
|
| | | {
|
| | | bits -= 8;
|
| | | out[w++] = uchar(acc >> bits);
|
| | | }
|
| | | }
|
| | |
|
| | | //---
|
| | | // Ahora si cargamos ya con la data verdadera
|
| | | return LoadSubjectPublicKeyInfo(out);
|
| | | }
|
| | |
|
2026-08-23 19:36:33 -05:00 | | | //+------------------------------------------------------------------+
|
| | | }
|
| | |
|
| | |
|
| | | //---
|
| | | #endif // CRYPTOBYLEO_SRC_RSA_KEYS_PUBLIC_MQH
|