¿Cómo cifrar un bloque de datos pequeño con solo la clave pública RSA usando Microsoft ECSP?

StackOverflow https://stackoverflow.com/questions/295345

  •  08-07-2019
  •  | 
  •  

Pregunta

Necesito encriptar un pequeño bloque de datos (16 bytes) usando una clave pública RSA de 512 bits, una tarea bastante fácil para la mayoría de las bibliotecas de criptografía que conozco, excepto para MS CSP API, como parece. La documentación para CryptEncrypt indica que la función

  

El Proveedor criptográfico mejorado de Microsoft admite el cifrado directo con claves públicas RSA y el descifrado con claves privadas RSA. El cifrado utiliza el relleno PKCS # 1.

Sin embargo, no me funcionó. Bueno, mi código funciona y produce un bloque cifrado de datos con el tamaño correcto, pero openssl no puede descifrarlo. Parece que CryptEncrypt todavía usa cifrado simétrico.

Desafortunadamente, todos los ejemplos que he encontrado se refieren a la criptografía combinada con cifrado simétrico, por lo que no tengo un ejemplo de trabajo en manos que definitivamente haría las cosas más fáciles.

¿Podría alguien señalarme un ejemplo así o avisarme si hay algunas trampas obvias que me he perdido?

Gracias.

¿Fue útil?

Solución

Esto suena como un problema de endianness . Función CryptEncrypt de Microsoft devuelve el texto cifrado en formato little-endian, mientras que OpenSSL espera que sus datos estén en formato big-endian. Deberá invertir los datos cifrados antes de pasarlos a OpenSSL.

Otros consejos

Aquí está el código (en caso de que alguien haya buscado en Google este tema):

BYTE *spkiData = SPKI; // X.509 ASN.1 encoded SubjectPublicKeyInfo
DWORD dwSPKISize = SPKI_SIZE; // 94 bytes for RSA

DWORD dwBufSize = 0;
// Get buffer size for decoded spki structure
CryptDecodeObject(X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, spkiData, dwSPKISize, 0, NULL, &dwBufSize);
BYTE* decBuf = new BYTE[dwBufSize];
CryptDecodeObject( X509_ASN_ENCODING, X509_PUBLIC_KEY_INFO, spkiData, dwSPKISize, 0, decBuf, &dwBufSize);
// Now decode the RSA Public key itself
CERT_PUBLIC_KEY_INFO * spki = (CERT_PUBLIC_KEY_INFO *) decBuf;
// Get buffer size for decoded public key structure
CryptDecodeObject( X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, spki->PublicKey.pbData, spki->PublicKey.cbData, 0, 0, &dwBufSize);
// Get the RSA public key blob
BYTE *blobBuf = new BYTE[dwBufSize];
CryptDecodeObject(X509_ASN_ENCODING, RSA_CSP_PUBLICKEYBLOB, spki->PublicKey.pbData, spki->PublicKey.cbData, 0, blobBuf, &dwBufSize);
// Acquire crypto provider context
HCRYPTPROV hCryptProv = NULL;
CryptAcquireContext(&hCryptProv, 0, MS_ENHANCED_PROV, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
// Import key
HCRYPTKEY key = NULL;
CryptImportKey(hCryptProv, blobBuf, dwBufSize, 0, 0, &key);
// Get the key size
DWORD dwKeySize;
DWORD dwParamSize = sizeof(DWORD);
CryptGetKeyParam(key, KP_KEYLEN, (BYTE*) &dwKeySize, &dwParamSize, 0);
// we need it in bytes for convenience
dwKeySize /= 8;
// Now the fun
// allocate a buffer of key size
BYTE *data = new BYTE[dwKeySize];
// Copy data need to be encrypted
// With PKCS#1 padding data length can not exceed keysize - 11 bytes
DWORD dataLen = 16;
memcpy(data, "0123456789012345", dataLen);
CryptEncrypt(key, 0, TRUE, 0, data, &dataLen, dwKeySize)
// now convert it to big endian (for the rest of the world)
for (int i = 0; i < (dwKeySize / 2); i++) {
    BYTE c = data[i];
    data[i] = data[dwKeySize - 1 - i];
    data[dwKeySize - 1 - i] = c;
}
// now data points to a dwKeySize length block of RSA PKCS#v1.5 encrypted data
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top