CryptoByLeo/Src/RSA/Keys/Public.mqh

332 lines
9.8 KiB
MQL5

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