//+------------------------------------------------------------------+ //| 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 { //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CRsaPublicKey::Load(BigUInteger &n, const ulong e, int totaln_bits) { m_n.RobarDe(n); m_e = e; m_total_sbits = totaln_bits; m_total_sbytes = totaln_bits >> 3; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CRsaPublicKey::Verify(const uchar &firma[], const uchar &data[]) { /* switch(m_sing_padder) { 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) //return CPSS::Verify(data, firma, m_total_sbits - 1, m_sing_fhash, m_sing_data.salt_len); } case RSA_SING_PADDER_PKCS1V15: { return; } default: break; }*/ return true; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ template bool CRsaPublicKey::Cifrar(const uchar &raw[], uchar &out[]) { //--- uchar em[]; TRandomFunc::RandomCryptoBytes(m_cip_random_bytes, TSN::CCryptoHashMeta::g_crytpo_hash_meta[m_cip_fhash].outl); if(COAEP::Encode(raw, m_total_sbytes, m_cip_random_bytes, m_cip_fhash, em) == -1) return false; //--- m_base.FromBytesBE(em); m_base.PowMod(m_e, m_n); //--- m_base.ToBytesBE(out, 0, m_total_sbytes); 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 } */ //+------------------------------------------------------------------+ 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; int e_len = CNumberDERUtils::DEREstimateLen(m_e, e_k, e_he, e_wl); //-- 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; int rsa_len = CASN1Utils::ContentTotalBytes(n_len + e_len, rsa_lenw); // 1 = unnuseds bits uchar bits_lenw; int bits_total = CASN1Utils::ContentTotalBytes((1 + rsa_len), bits_lenw); //--- parte 2 (AlgorithmIdentifier + BIT uchar total_lenw; int total = CASN1Utils::ContentTotalBytes(RSA_ALG_OID_TSIZE + bits_total, total_lenw); //--- Ahora siahora mismo estamos en el "top" ahora bajamos if(total + w > ArraySize(buf)) ArrayResize(buf, total + w); //--- Inicaimos // SubjectPublicKeyInfo buf[w++] = CBL_ASN1_TAG_SEQUENCE; CBL_ASN1_U_WRITELEN(buf, w, total_lenw, total) // Ahora copy tal cual w += ArrayCopy(buf, g_rsa_alg_id, w, 0, RSA_ALG_OID_TSIZE); //-- seguimso con bit string buf[w++] = CBL_ASN1_TAG_BITSTRING; CBL_ASN1_U_WRITELEN(buf, w, bits_lenw, bits_total) buf[w++] = CBL_ASN1_V_UNUSED_BITS; //-- rsa buf[w++] = CBL_ASN1_TAG_SEQUENCE; CBL_ASN1_U_WRITELEN(buf, w, rsa_lenw, rsa_len) // 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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ // 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 // Al final testenado el 3. ha sido mas rapido.... y el 1. como segundo mas rapido // (pero no era muha difenica 10%~ aprox) esto en parte se debe a que el b64 nativo // 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... // 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 // el costo que se nos cva en allocar un buffer entero ya quizas lo cubren esos dos factores.. // tema de acceso. // Por cierto ese material del los bench estan en (DiseñoBenchs) int CRsaPublicKey::ToSubjectPublicKeyInfoPem(uchar &buf[], int w = 0) const { //--- // inplace (sin otro buffer hasta ahora 2 buffers en juego) uchar raw[]; ToSubjectPublicKeyInfo(raw); //--- // NOTA quizas cambie esto dado qeu no se puede hacer eso.... // 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); //--- header w += ArrayCopy(buf, g_rsa_pubkey_pem_header, w, 0, RSA_PUBKEY_PEMHEADER_SIZE); //--- 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; } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ 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); } //+------------------------------------------------------------------+ } //--- #endif // CRYPTOBYLEO_SRC_RSA_KEYS_PUBLIC_MQH