Cifrado rsa.

499 views
Skip to first unread message

Denis Romero

unread,
Jun 18, 2019, 8:51:29 PM6/18/19
to Comunidad de Visual Foxpro en Español
Buenas tardes, estoy batallando en el Fox para hacer la receptación que me piden en el texto que les adjunto. Aclaro que no tengo mucha experiencia en Fox. Agradezco la ayuda que me puedan brindar.
Wondersoft Autorización Cliente PagePago V2 - Especificaciones v10.01.02.docx

Fernando Mora

unread,
Jun 24, 2019, 1:14:38 AM6/24/19
to Comunidad de Visual Foxpro en Español
El camino es largo, pero es posible hacer todo eso 100% fox, para ello debes revisar la documentación de Microsoft para poder entender y usar las apis (BCrypt) que permite crear claves publicas y privadas en formato RSA, crear hash, y firmar dichos hash. Aquí te comparto el código de lo más básico que necesitas según leí la documentación que publicas. Si quieres empaparte mas del tema, revisa la documentación de la librería CNG de MS, hay ejemplos de todo esto, están en lenguaje C++ pero con algo de paciencia y con conocimientos básico de C++ se puede traducir esos ejemplos a Fox. He traducido algunos, los que mas he necesitado hasta ahora, pero el tema es largo.


*-------- DECLARACIONES API CNG
DECLARE LONG BCryptOpenAlgorithmProvider IN BCrypt; 
LONG @phAlgorithm, ;
STRING pszAlgId, ; 
STRING pszImplementation, ;
LONG dwFlags 

DECLARE LONG BCryptGenerateKeyPair IN BCrypt; 
LONG hAlgorithm, ;
LONG @phKey, ;
LONG dwLength, ; 
LONG dwFlags 

DECLARE LONG BCryptFinalizeKeyPair IN BCrypt; 
LONG hKey, ;
LONG dwFlags 

DECLARE LONG BCryptCloseAlgorithmProvider IN BCrypt; 
LONG hAlgorithm, ;
LONG dwFlags 

DECLARE LONG BCryptExportKey IN BCrypt;
LONG kKey, ;
LONG hExportKey, ;
STRING pszBlobType, ; 
STRING @pbOutput, ;
LONG cbOutput, ;
LONG @pcbResult, ; 
LONG dwFlags 

DECLARE LONG BCryptImportKeyPair IN BCrypt; 
LONG hAlgorithm,;
LONG hImportKey,;
STRING pszBlobType,;
LONG @phKey,;
STRING pbInput,;
LONG cbInput,; 
LONG dwFlags 

DECLARE LONG BCryptSignHash IN BCrypt;  
LONG hKey,;
LONG @pPaddingInfo,;
STRING pbInput,;  
LONG cbInput,;
STRING @pbOutput,;
LONG cbOutput,;  
LONG @pcbResult,;
LONG dwFlags

DECLARE LONG BCryptGetProperty IN BCrypt;
LONG hObject,;
STRING pszProperty,;
LONG @pbOutput,;
LONG cbOutput,;
LONG @pcbResult,;
LONG dwFlags

DECLARE LONG BCryptCreateHash IN BCrypt; 
LONG hAlgorithm,;
LONG @phHash,;
STRING @pbHashObject,;
LONG cbHashObject,;
STRING pbSecret,;
LONG cbSecret,; 
LONG dwFlags

DECLARE LONG BCryptHashData IN BCrypt; 
LONG hHash,;
STRING pbInput,;
LONG cbInput,;
LONG dwFlags 

DECLARE LONG BCryptFinishHash IN BCrypt; 
LONG hHash,;
STRING @pbOutput,;
LONG cbOutput,;
LONG dwFlags 

DECLARE LONG BCryptDestroyHash IN BCrypt; 
LONG hHash 

DECLARE LONG BCryptDestroyKey IN BCrypt; 
LONG hKey

DECLARE LONG GetProcessHeap IN Kernel32

DECLARE LONG HeapAlloc IN Kernel32;
LONG hHeap,;
LONG dwFlags,;
LONG dwBytes

DECLARE LONG HeapFree IN Kernel32;
LONG hHeap,;
LONG dwFlags,;
LONG lpMem

*------------------------ CONSTANTES 
#DEFINE PUBLICKEYBLOB 0x6
#DEFINE PRIVATEKEYBLOB 0x7
#DEFINE BCRYPT_RSA_ALGORITHM STRCONV("RSA" + CHR(0), 5)
#DEFINE BCRYPT_PRIVATE_KEY_BLOB STRCONV("PRIVATEBLOB" + CHR(0), 5)
#DEFINE LEGACY_RSAPRIVATE_BLOB STRCONV("CAPIPRIVATEBLOB" + CHR(0), 5)
#DEFINE BCRYPT_SHA1_ALGORITHM STRCONV("SHA1" + CHR(0), 5)
#DEFINE BCRYPT_PAD_PKCS1 0x00000002
#DEFINE BCRYPT_PAD_PSS 0x00000008

*--------- MAIN
*----- NOTA: Las cadenas de respuestas, el formato original es ASN1, para este ejemplo las presentaremos en Base64.
*----- Creamos en par de claves genéricas, RSA de 2049 bits de longitud
CLEAR
SET STEP ON
lcTypeKey = "RSA"
tnLengthKey = 2048
lnKeyPair = GetCngGenerateKeyPair(lcTypeKey, tnLengthKey)
*----- Exportamos el Par de Claves, primero la clave Privada y luego la clave publica.
lcPrivate = "RSAPRIVATEBLOB"
lcPublic = "RSAPUBLICBLOB"
cPrivateKey = GetCngExportKeyBCrypt(lnKeyPair, lcPrivate)
cPublicKey = GetCngExportKeyBCrypt(lnKeyPair, lcPublic)
? "Private Key: " + STRCONV(cPrivateKey,13)
? "Public Key: " + STRCONV(cPublicKey,13)
?
cCadenaParaHash = "Este es el texto que deseo crear hash y firmar, aquí va su texto"
cAlgoritmoHash = "SHA1"
cHashResp = GetDigestValue(cCadenaParaHash, cAlgoritmoHash)
? "Hash: " + STRCONV(cHashResp,13)
?
cSignHash = GetSignHash(cHashResp, lnKeyPair)
? "Signature: " + STRCONV(cSignHash,13)
?

*--------- REGIÓN DE PROCEDURES
*----- Función GetCngGenerateKeyPair, genera un par de claves genéricas RSA de longitud 2048 bit
PROCEDURE GetCngGenerateKeyPair()
PARAMETERS tcTypeKey AS String, tnLengthKey AS Integer
lnKey = 0
lnAlg = 0 
nResp = BCryptOpenAlgorithmProvider(@lnAlg, STRCONV(tcTypeKey,5)+CHR(0), NULL, 0)
IF nResp==0
nResp = BCryptGenerateKeyPair(lnAlg, @lnKey, tnLengthKey, 0)
IF nResp==0
BCryptFinalizeKeyPair(lnKey, 0)
ENDIF
ENDIF
IF lnAlg<>0 
BCryptCloseAlgorithmProvider(lnAlg, 0)
ENDIF
RETURN lnKey
ENDPROC

*----- Función GetCngExportKeyBCrypt, exporta un par de claves genérica.
PROCEDURE GetCngExportKeyBCrypt()
PARAMETERS tnKey AS Long, tcKey AS String
hKey = tnKey
pszBlobType = STRCONV(tcKey,5)+CHR(0)
pcbResult = 0
nResp = BCryptExportKey(hKey, 0, pszBlobType, NULL, 0, @pcbResult, 0)
pbOutPut = SPACE(pcbResult) 
nResp = BCryptExportKey(hKey, 0, pszBlobType, @pbOutPut, LEN(pbOutPut), @pcbResult, 0)
RETURN pbOutPut
ENDPROC

*----- Función GetDigestValue, crear un valor Hash a partir de una cadena de caracteres, usando un algoritmo
PROCEDURE GetDigestValue()
PARAMETERS tcData AS String, tcHashAlg AS String
lnAlg = 0
nRespBCOAP = BCryptOpenAlgorithmProvider(@lnAlg, STRCONV(tcHashAlg,5)+CHR(0), NULL, 0)
IF nRespBCOAP<>0
MESSAGEBOX("ERROR AL ABRIR ALGORITMO")
RETURN ""
ENDIF
*----- Determinamos cuántos bytes necesitamos para almacenar el objeto hash
lnSizeObj = 0 
lnData = 0 
nRespNCGP = BCryptGetProperty(lnAlg, STRCONV("ObjectLength",5)+CHR(0), @lnSizeObj, 4, @lnData, 0)
IF nRespNCGP<>0
MESSAGEBOX("ERROR AL OBTENER PROPIEDAD DE ENCRIPTACION")
RETURN ""
ENDIF
*----- Determinamos la longitud de valor hash 
lnSizeHash = 0 
nRespNCGP = BCryptGetProperty(lnAlg, STRCONV("HashDigestLength",5)+CHR(0), @lnSizeHash, 4, @lnData, 0)
IF nRespNCGP<>0
MESSAGEBOX("ERROR AL OBTENER PROPIEDAD DE ENCRIPTACION")
RETURN ""
ENDIF
*----- Creamos un objeto Hash
LOCAL lnHash, lcHashObj 
lnHash = 0 
lcHashObj = SPACE(lnSizeObj) 
nRespBCCH = BCryptCreateHash(lnAlg, @lnHash, @lcHashObj, lnSizeObj, NULL, 0, 0)
IF nRespBCCH<>0
MESSAGEBOX("ERROR AL CREAR OBJETO HASH")
RETURN ""
ENDIF
*----- Para crear el valor hash agregamos datos al objeto hash. Puede repetir este paso según sea necesario
nLenData = LEN(tcData)
nRespBCHD = BCryptHashData(lnHash, tcData, nLenData, 0)
IF nRespBCHD<>0
nRespBCHD = BCryptHashData(lnHash, tcData, nLenData, 0)
IF nRespBCHD<>0
=GetMensajeError(nRespBCHD)
RETURN ""
ENDIF
ENDIF
*----- Indicamos al objeto hash que hemos terminado. El algoritmo ahora calcula el valor de hash y lo devuelve. 
lcHash = SPACE(lnSizeHash) 
=BCryptFinishHash(lnHash, @lcHash, lnSizeHash, 0)
IF lnAlg<>0
BCryptCloseAlgorithmProvider(lnAlg, 0) 
ENDIF 
IF lnHash<>0 
BCryptDestroyHash(lnHash) 
ENDIF
RETURN lcHash
ENDPROC

*----- Firma una valor Hash usando un par de claves de tipo BCrypt
PROCEDURE GetSignHash()
PARAMETERS tcDataSign AS String, tnParKey AS Integer
lcSigned = ""
lnAlg = 0
lnRes = BCryptOpenAlgorithmProvider(@lnAlg, BCRYPT_RSA_ALGORITHM, NULL, 0)
lnKey = tnParKey
lnAlgoString = HeapAlloc(GetProcessHeap(), 0, LEN(BCRYPT_SHA1_ALGORITHM))
IF lnAlgoString <> 0
SYS(2600, lnAlgoString, LEN(BCRYPT_SHA1_ALGORITHM), BCRYPT_SHA1_ALGORITHM)
lnSize = 0
lnRes = BCryptSignHash(lnKey, @lnAlgoString, tcDataSign, LEN(tcDataSign), NULL, 0, @lnSize, 8)
IF lnRes = 0
*---- Firmamos la cadena de datos
lcSigned = SPACE(lnSize)
lnRes = BCryptSignHash(lnKey, @lnAlgoString, tcDataSign, LEN(tcDataSign), @lcSigned, lnSize, @lnSize, 8)
IF lnRes = 0
*---- EXITO!
lcSigned = LEFT(lcSigned, lnSize)
ELSE
*---- Siga participando
lcSigned = ""
ENDIF
ENDIF
HeapFree(GetProcessHeap(), 0, lnAlgoString)
BCryptDestroyKey(lnKey)
ENDIF
BCryptCloseAlgorithmProvider(lnAlg, 0)
RETURN lcSigned
ENDPROC

Luis Martinez Rguez.

unread,
Jun 24, 2019, 6:51:14 AM6/24/19
to Comunidad de Visual Foxpro en Español
Hola Fernando:
Da error en el cálculo del Hash y falta la función GetMensajeError

Saludos.
Luis Martinez Rodriguez
A Coruña
España

Fernando Mora

unread,
Jun 24, 2019, 12:42:41 PM6/24/19
to Comunidad de Visual Foxpro en Español
Saludos Luis Martinez.

Prueba desactivando el SET STEP ON para que el ejemplo corra, no debería darte problema.
Respecto a la función que GetMensajeError, has lo siguiente: 
Agrega estas declaraciones en la región de declaraciones api del ejemplo anterior


*------------------------ Kernel
DECLARE INTEGER GetLastError IN Kernel32

DECLARE LONG FormatMessage IN Kernel32;
  LONG dwFlags,;
  STRING @lpSource,;
  LONG dwMessageId,;
  LONG dwLanguageId,;
  STRING @lpBuffer,;
  LONG nSize,;
  LONG Arguments


Agrega esta constante en la región de CONSTANTES


#DEFINE FORMAT_MESSAGE_FROM_SYSTEM 0x00001000


Y finalmente, agrega la función GetMensajeError al final de la región de PROCEDURES


PROCEDURE GetMensajeError(tcNumError)
IF VARTYPE(tcNumError)=="N"
lnErrorCode = tcNumError
ELSE
lnErrorCode = GetLastError()
ENDIF
lpBuffer = SPACE(128)
=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 'WINERROR.H', lnErrorCode, 0, @lpBuffer, 128 , 0)
=MESSAGEBOX(lpBuffer, 16, "Error: " + TRANSFORM(lnErrorCode,"@0"))
ENDPROC

Fernando Mora

unread,
Jun 24, 2019, 12:56:22 PM6/24/19
to Comunidad de Visual Foxpro en Español
Aquí un capture del ejemplo corriendo y devolviendo todos los valores solicitados. 

Fernando.

GENERIC_PAIR_KEY.jpg


Denis Romero

unread,
Jun 25, 2019, 6:16:21 AM6/25/19
to Comunidad de Visual Foxpro en Español
Fernando, gracias por la informacion. Te consulto en que parte del codigo que pasaste le indico que tiene que usar una clave publica que ya tengo y una privada que tambien ya tengo, es decir hacer el cifrado con unas llaves que ya tengo en lugar de usar las que genera en el momento.
Te comento que dichas llaves ya generadas no las tengo en archivos .xml ni .key, etc. Las tengo en una cadena de Sting.
Gracias!!!!

Fernando Mora

unread,
Jun 25, 2019, 9:03:55 AM6/25/19
to Comunidad de Visual Foxpro en Español
Saludos Denis Romero.
Para ese caso necesitas importar el par de claves dentro de un puntero de memoria y con ese puntero se firma el Hash, tal como se hizo en el ejemplo anterior al generar el par de claves genéricas se creo un puntero de memoria y ese puntero se paso a la función GetSignHash en el segundo parámetro (tnParKey).

Para importar el par de claves, se necesita que las cadenas estén en formato ASN1, por lo general si esas claves te las hicieron llegar, lo mas probable es que los archivos estén en formato Base64 o Hexadecimal, que son los formatos de intercambio. Entonces se tendrían que convertir a ASN1. Por otro lado se necesita saber con que proveedor criptográfico se generaron dichas claves, si fueron generadas con CNG de MS la importación es un procedimiento sencillo, si son de otro proveedor criptográfico que no es CNG (lo mas probable) el proceso es un tanto mas complicado, pero es posible la importación.

El siguiente código, rueda en las redes como ejemplo de C++ y aplicado para la vieja librería criptográfica de windows CSP, lo traduje a Fox y actualizado para la librería nueva de criptográfíca de windows CNG, con la colaboración de Diego Fazio a quien le envió saludos se logró producir esta función en Fox para importar claves privadas de proveedores criptograficos externos. El código puede ser usado para importar clave privada desde archivo key, pem o cer, y también desde una cadena de texto. El requisito es que tienen que estar en Base64, pero bien se podría adaptar para algún caso en Hexadecimal. 

Recordar que se utiliza la clave privada para firmar, PRIVATEKEY, la clave publica se usa para verificar un firmado PUBLICKEY.

Saludos desde Machala, Ecuador.
Fernando


*------------ REGION DE DECLARACIONES API
*------------ CRYPTO API CSP (Cryptographic Service Providers)
*------------ Crypt32.DLL
DECLARE LONG CertCreateCertificateContext IN Crypt32;
LONG dwCertEncodingType,;
STRING pbCertEncoded,;
LONG cbCertEncoded

DECLARE LONG CryptBinaryToString IN Crypt32;
STRING pbBinary, ;
LONG cbBinary, ;
LONG dwFlags,;
STRING @pszString, ;
LONG @pcchString

DECLARE LONG CryptStringToBinaryA IN Crypt32;
STRING @pszString, ;
LONG cchString, ;
LONG dwFlags,;
STRING @pbBinary, ;
LONG @pcbBinary,;
LONG @pdwSkip, ;
LONG @pdwFlags

DECLARE LONG CryptStringToBinaryW IN Crypt32;
STRING @pszString, ;
LONG cchString, ;
LONG dwFlags,;
STRING @pbBinary, ;
LONG @pcbBinary,;
LONG pdwSkip, ;
LONG pdwFlags
DECLARE LONG CryptEncodeObject IN Crypt32;
LONG dwCertEncodingType,;
STRING lpszStructType,;
STRING pvStructInfo,;
STRING @pbEncoded,;
LONG @pcbEncoded

DECLARE LONG CryptEncodeObjectEx IN Crypt32;
LONG dwCertEncodingType,;
STRING lpszStructType,;
STRING pvStructInfo,;
LONG dwFlags,;
STRING pEncodePara,;
STRING @pvEncoded,;
LONG @pcbEncoded

DECLARE LONG CryptDecodeObject IN Crypt32;
LONG dwCertEncodingType,;
STRING lpszStructType,;
STRING pbEncoded,;
LONG cbEncoded,;
LONG dwFlags,;
STRING @pvStructInfo,;
LONG @pcbStructInfo

DECLARE LONG CryptDecodeObjectEx IN Crypt32;
LONG dwCertEncodingType,;
LONG lpszStructType,;
STRING pbEncoded,;
LONG cbEncoded,;
LONG dwFlags,;
STRING pDecodePara,;
STRING @pvStructInfo,;
LONG @pcbStructInfo

DECLARE LONG CryptAcquireCertificatePrivateKey IN Crypt32;
LONG pCert,;
LONG dwFlags,;
LONG pvParameters,;
LONG @phCryptProvOrNCryptKey,;
LONG @pdwKeySpec,;
LONG @pfCallerFreeProvOrNCryptKey

DECLARE LONG CertGetPublicKeyLength IN Crypt32;
LONG dwCertEncodingType,;
STRING @pPublicKey

*------- CRYPTO API CNG (Cryptography Next Generation)
*------- BCrypt.DLL
DECLARE LONG BCryptOpenAlgorithmProvider IN BCrypt; 
LONG @phAlgorithm, ;
STRING pszAlgId, ; 
STRING pszImplementation, ;
LONG dwFlags

DECLARE LONG BCryptImportKeyPair IN BCrypt; 
LONG hAlgorithm, ;
LONG hImportKey, ;
STRING pszBlobType, ; 
LONG @phKey, ;
STRING pbInput, ;
LONG cbInput, ; 
LONG dwFlags

DECLARE LONG BCryptCloseAlgorithmProvider IN BCrypt; 
LONG hAlgorithm, ;
LONG dwFlags 

DECLARE LONG BCryptDestroyKey IN BCrypt; 
LONG hKey 

*------------ APIS de procesos del SO
*------------ Kernel32.DLL
DECLARE LONG GetLastError IN Kernel32

DECLARE LONG FormatMessage IN Kernel32;
  LONG dwFlags, ;
  STRING @lpSource, ;
  LONG dwMessageId, ;
  LONG dwLanguageId, ;
  STRING @lpBuffer, ;
  LONG nSize, ;
  LONG Arguments

DECLARE LONG GetProcessHeap IN Kernel32

DECLARE LONG HeapAlloc IN Kernel32;
LONG hHeap,;
LONG dwFlags,;
LONG dwBytes

DECLARE LONG HeapFree IN Kernel32;
LONG hHeap,;
LONG dwFlags,;
LONG lpMem

*------------ REGION DE CONSTANTES
#DEFINE X509_ASN_ENCODING 1  
#DEFINE PKCS_7_ASN_ENCODING 0x00010000
#DEFINE FORMAT_MESSAGE_FROM_SYSTEM 0x00001000
#DEFINE CRYPT_STRING_ANY 0x00000007
#DEFINE CRYPT_STRING_BASE64HEADER 0x00000000
#DEFINE CRYPT_STRING_BASE64 0x00000001
#DEFINE CRYPT_STRING_BINARY 0x00000002

*------------ REGION MAIN
*----- Firmar con archivo Key (pem, cer)
*!* lcFileKey = GETFILE("KEY")
*!* IF EMPTY(lcFileKey)
*!* RETURN 0
*!* ENDIF
*!* cStringKey = ALLTRIM(FILETOSTR(lcFileKey))
*!* IF EMPTY(cStringKey)
*!* MESSAGEBOX("El archivo esta vacio", 16, _SCREEN.Caption)
*!* RETURN 0
*!* ENDIF
*----- Firmar con cadena PrivateKey
TEXT TO cStringKey ADDITIVE NOSHOW
MIICXAIBAAKBgQCf6YAJOSBYPve1jpYDzq+w++8YVoATI/YCi/RKZaQk+l2ZfoUQ
g0qrYrfkzeoOa/qd5VLjTTvHEgwXnlDXMfo+vSgxosUxDOZXMTBqJGOViv5K2QBv
k8A1wi4k8tuo/7OWya29HvcfavUk3YXaV2YFe8V6ssaZjNcVWmDdjqNkXwIDAQAB
AoGALrd+ijNAOcebglT3ioE1XpUbUpbir7TPyAqvAZUUESF7er41jY9tnwgmBRgL
Cs+M1dgLERCdKBkjozrDDzswifFQmq6PrmYrBkFFqCoLJwepSYdWnK1gbZ/d43rR
2sXzSGZngscx0CxO7KZ7xUkwENGd3+lKXV7J6/vgzJ4XnkECQQDTP6zWKT7YDckk
We04hbhHyBuNOW068NgUUvoZdBewerR74MJx6nz28Tp+DeNvc0EveiQxsEnbV8u+
NRkX5y0xAkEAwcnEAGBn5kJd6SpU0ALA9XEpUv7tHTAGQYgCRbfTT59hhOq6I22A
ivjOCNG9c6E7EB2kcPVGuCpYUhy7XBIGjwJAK5lavKCqncDKoLwGn8HJdNcyCIWv
q5iFoDw37gTt1ricg2yx9PzmabkDz3xiUmBBNeFJkw/FToXiQRGIakyGIQJAJIem
PPPvYgZssYFbT4LVYO8d/Rk1FWVyKHQ9CWtnmADRXz7oK7l+m7PfEuaGsf9YpOcR
koGJ/TluQLxNzUNQnQJBAImwr/yYFenIx3HQ6UX/fCt6qpGDv0VfOLyR64MNeegx
o7DhNxHbFkIGzk4lKhMKcHKDrawZbdJtS9ie2geSwVQ=
ENDTEXT

SET STEP ON
lpParKey = GetImportPrivateKeyToCng(cStringKey)
IF lpParKey<>0
? "Exito!, puntero para firmar: " + TRANSFORM(lpParKey)
BCryptDestroyKey(lpParKey)
ELSE
? "No se pudo importar el par de claves"
ENDIF

*------------ REGION DE PROCEDURES
*/// Recibe una cadena de claves publico/privada (KEY) de intercambio
*/// Si tiene exito devuelve un puntero al par de claves importadas, listo para firmar o verificar un firmado
PROCEDURE GetImportPrivateKeyToCng(tcStringKey AS String)
*----- Decodificamos la cadena
pcbBinary=0
pdwSkip=0
pdwFlags=0
nResp = CryptStringToBinaryA(@tcStringKey , LEN(tcStringKey ), CRYPT_STRING_ANY, NULL, @pcbBinary, @pdwSkip, @pdwFlags)
DO CASE
CASE pdwFlags=0
lcPrivKey=STREXTRACT(tcStringKey , "-----BEGIN RSA PRIVATE KEY-----", "-----END RSA PRIVATE KEY-----")
IF EMPTY(lcPrivKey)
lcPrivKey=STREXTRACT(tcStringKey , "-----BEGIN ENCRYPTED PRIVATE KEY-----", "-----END ENCRYPTED PRIVATE KEY-----")
ENDIF
pbBinary=STRCONV(lcPrivKey,14)
pcbBinary=LEN(pbBinary)
CASE pdwFlags=1
nResp = CryptStringToBinaryA(@tcStringKey , LEN(tcStringKey ), CRYPT_STRING_BASE64, NULL, @pcbBinary, 0, 0)
pbBinary  = REPLICATE(CHR(0), pcbBinary)
nResp = CryptStringToBinaryA(@tcStringKey , LEN(tcStringKey ), CRYPT_STRING_BASE64, @pbBinary, @pcbBinary, 0, 0)
CASE pdwFlags=2
nResp = CryptStringToBinaryW(@tcStringKey , LEN(tcStringKey ), CRYPT_STRING_BINARY, NULL, @pcbBinary, 0, 0)
pbBinary  = REPLICATE(CHR(0), pcbBinary)
nResp = CryptStringToBinaryW(@tcStringKey , LEN(tcStringKey ), CRYPT_STRING_BINARY, @pbBinary, @pcbBinary, 0, 0)
ENDCASE
*----- Decodificamos la cadena ASN1
dwCertEncodingType = BITOR(PKCS_7_ASN_ENCODING, X509_ASN_ENCODING)
lpszStructType = 43
pbEncoded = pbBinary && lcPrivKey
cbEncoded = pcbBinary && LEN(lcPrivKey)
cbKeyBlob = 0
nResp=CryptDecodeObjectEx(dwCertEncodingType, @lpszStructType , pbEncoded, cbEncoded, 0, NULL, NULL, @cbKeyBlob)
IF cbKeyBlob=0
GetMessageError()
RETURN 0
ENDIF
pbKeyBlob = SPACE(cbKeyBlob)
nResp=CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded, cbEncoded, 0, NULL, @pbKeyBlob, @cbKeyBlob)
*----- Abrimos un proveedor de algoritmo
pszAlgId = STRCONV("RSA" + CHR(0), 5)
lnAlg = 0
lnRes = BCryptOpenAlgorithmProvider(@lnAlg, pszAlgId, NULL, 0)
IF lnRes <> 0
MESSAGEBOX("No se pudo apertura el proveedor de algoritmo", 16, _SCREEN.Caption)
RETURN 0
ENDIF
*------ Importamos el par de claves para CNG, probamos con varios formatos (todos los conocidos hasta ahora)
pszBlobType01V = STRCONV("PRIVATEBLOB" + CHR(0), 5)
pszBlobType01B = STRCONV("PUBLICBLOB" + CHR(0), 5)
pszBlobType02V = STRCONV("DHPRIVATEBLOB" + CHR(0), 5)
pszBlobType02B = STRCONV("DHPUBLICBLOB" + CHR(0), 5)
pszBlobType03V = STRCONV("DSAPRIVATEBLOB" + CHR(0), 5)
pszBlobType03B = STRCONV("DSAPUBLICBLOB" + CHR(0), 5)
pszBlobType04V = STRCONV("ECCPRIVATEBLOB" + CHR(0), 5)
pszBlobType04B = STRCONV("ECCPUBLICBLOB" + CHR(0), 5)
pszBlobType05V = STRCONV("RSAPRIVATEBLOB" + CHR(0), 5)
pszBlobType05B = STRCONV("RSAPUBLICBLOB" + CHR(0), 5)
pszBlobType06V = STRCONV("CAPIPRIVATEBLOB" + CHR(0), 5)
pszBlobType06B = STRCONV("CAPIPUBLICBLOB" + CHR(0), 5)
pszBlobType07V = STRCONV("CAPIDHPRIVATEBLOB" + CHR(0), 5)
pszBlobType07B = STRCONV("CAPIDHPUBLICBLOB" + CHR(0), 5)
pszBlobType08V = STRCONV("CAPIDSAPRIVATEBLOB" + CHR(0), 5)
pszBlobType08B = STRCONV("CAPIDSAPUBLICBLOB" + CHR(0), 5)
pszBlobType09V = STRCONV("V2CAPIDSAPRIVATEBLOB" + CHR(0), 5)
pszBlobType09B = STRCONV("V2CAPIDSAPUBLICBLOB" + CHR(0), 5)

lnKey = 0
DO CASE
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType01V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType01V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType01B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType01B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType02V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType02V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType02B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType02B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType03V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType03V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType03B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType03B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType04V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType04B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType04B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType04B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType05V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType05V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType05B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType05B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType06V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType06V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType06B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType06B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType07V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType07V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType07B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType07B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType08V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType08V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType08B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType08B
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType09V, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType09V
CASE BCryptImportKeyPair(lnAlg, 0, pszBlobType09B, @lnKey, pbKeyBlob, cbKeyBlob, 0)==0
? pszBlobType09B
OTHERWISE
MESSAGEBOX("No se pudo importar el par de claves." +CHR(13)+ "revise que el archivo key tenga el formato correcto", 16, _SCREEN.Caption)
ENDCASE
BCryptCloseAlgorithmProvider(lnAlg, 0)
RETURN lnKey
ENDPROC

*----- Presenta el ultimo error del sistema.
PROCEDURE GetMessageError(tnNumError AS Long)
IF VARTYPE(tnNumError)=="N"
lnErrorCode = tnNumError
ELSE
lnErrorCode = GetLastError()
ENDIF
lpBuffer = SPACE(128)
=FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 'WINERROR.H', lnErrorCode, 0, @lpBuffer, 128 , 0)
=MESSAGEBOX(lpBuffer, 16, "Error: " + TRANSFORM(lnErrorCode,"@0"))
ENDPROC

Denis Romero

unread,
Jun 25, 2019, 12:52:41 PM6/25/19
to Comunidad de Visual Foxpro en Español
Gracias por la pronta respuesta, Fernando. Consulte esto al proveedor "wonder" y ellos me respondieron esto.
--------------------------------------
Usamos la clase "RSACryptoServiceProvider", la cual realiza el cifrado y descifrado asimétricos utilizando la implementación del algoritmo RSA proporcionado por el proveedor de servicios criptográficos de MS que esté instalado.
--------------------------------------
Nuevamente gracias!!!!

Fernando Mora

unread,
Jun 25, 2019, 1:36:32 PM6/25/19
to Comunidad de Visual Foxpro en Español
La clase RSACryptoServiceProvider pertenece a Net, y Net usa CNG para el tema criptográfico, la importación es mucho mas simple que el ejercicio anterior que importada pares de claves creados con OpenSSL por ejemplo, con la función BCryptImportKeyPair() importas la clave privada y ya tienes el puntero de memoria para pasarlo a la función GetSingHash que publique. ¿En que formato esta la cadena de la clave privada, Base64 o Hexadecimal? recuerda que hay que convertirla a ASN1.

Denis Romero

unread,
Jun 25, 2019, 1:44:39 PM6/25/19
to Comunidad de Visual Foxpro en Español
Por lo poco que entiendo del tema cifrado, las llaves están en formato Base64.

Luis Martinez Rguez.

unread,
Jun 29, 2019, 5:41:10 AM6/29/19
to Comunidad de Visual Foxpro en Español
Hola Fernando:
Ya funciona correctamente.
Muchas gracias por compartir tus conocimientos sobre el cifrado.
Reply all
Reply to author
Forward
0 new messages