API Reference

Uso de llaves criptográficas en Milio

Esta sección explica cómo utilizar correctamente las llaves criptográficas proporcionadas por Milio para asegurar la información intercambiada entre nuestra plataforma y su aplicación. El proceso descrito aquí aplica de manera general, independiente del lenguaje de programación o framework que utilices.

Encriptar información

Para encriptar información que deseas enviar a Milio, utiliza la llave pública que te fue entregada. El proceso general es el siguiente:

  1. Obtener la llave pública: Esta llave es proporcionada por Milio y generalmente está en formato PEM (comienza con \-----BEGIN RSA PUBLIC KEY----- y finaliza con -----END RSA PUBLIC KEY-----).
  2. Preparar la información a encriptar: Convierte los datos que deseas proteger (texto o archivo) a un formato adecuado para el cifrado (generalmente texto plano o binario).
  3. Cifrado del mensaje:
    • Usa una biblioteca o función estándar de tu lenguaje o framework que soporte RSA.
    • Cifra la información con la llave pública proporcionada.
    • El resultado del proceso será un mensaje encriptado, listo para ser transmitido a Milio.

Ejemplo

import {publicEncrypt} from 'crypto'
import * as constants from 'constants'
...

public encryptPublicKey = (publicKey: string, data: string) => {
    try {
      return crypto.publicEncrypt(
        {key: publicKey, padding: constants.RSA_PKCS1_OAEP_PADDING},
        Buffer.from(data, 'utf8'),
      )
    } catch (error) {
      //catch error
    }
  }

import android.util.Base64
import java.security.KeyFactory
import java.security.PublicKey
import java.security.spec.X509EncodedKeySpec
import javax.crypto.Cipher

// Llave pública proporcionada por Milio (esto es solo un ejemplo, usa la real en producción)
private const val PUBLIC_KEY_PEM = """
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7...
-----END RSA PUBLIC KEY-----
""".trimIndent()

/**
 *  Método para encriptar información con la llave pública de Milio.
 *
 * @param publicKeyPem Llave pública en formato PEM.
 * @param data Información que se desea encriptar.
 * @return Datos encriptados en Base64 o null en caso de error.
 */
fun encryptWithPublicKey(publicKeyPem: String, data: String): String? {
    return try {
        // Convertir la llave pública de formato PEM a PublicKey
        val publicKey = getPublicKeyFromPem(publicKeyPem)

        // Configurar el cifrado RSA con el padding OAEP seguro
        val cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA-256AndMGF1Padding")
        cipher.init(Cipher.ENCRYPT_MODE, publicKey)

        // Cifrar los datos y convertirlos a Base64
        val encryptedBytes = cipher.doFinal(data.toByteArray(Charsets.UTF_8))
        Base64.encodeToString(encryptedBytes, Base64.NO_WRAP)
    } catch (e: Exception) {
        e.printStackTrace()
        null
    }
}

/**
 * 🔑 Convierte una clave pública en formato PEM a un objeto PublicKey.
 */
private fun getPublicKeyFromPem(publicKeyPem: String): PublicKey {
    val keyBytes = Base64.decode(
        publicKeyPem.replace("-----BEGIN RSA PUBLIC KEY-----", "")
            .replace("-----END RSA PUBLIC KEY-----", "")
            .replace("\\s".toRegex(), ""),
        Base64.DEFAULT
    )
    val keySpec = X509EncodedKeySpec(keyBytes)
    return KeyFactory.getInstance("RSA").generatePublic(keySpec)
}

import Foundation
import Security

// Llave pública proporcionada por Milio (esto es solo un ejemplo, usa la real en producción)
let publicKeyPem = """
-----BEGIN RSA PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7...
-----END RSA PUBLIC KEY-----
"""

/**
 * 🔒 Método para encriptar información con la llave pública de Milio.
 *
 * @param publicKeyPem Llave pública en formato PEM.
 * @param data Información que se desea encriptar.
 * @return Datos encriptados en Base64 o nil en caso de error.
 */
func encryptWithPublicKey(publicKeyPem: String, data: String) -> String? {
    guard let publicKey = getPublicKey(from: publicKeyPem) else {
        print("❌ Error: No se pudo obtener la llave pública.")
        return nil
    }
    
    guard let dataToEncrypt = data.data(using: .utf8) else {
        print("❌ Error: No se pudo convertir la data a formato UTF-8.")
        return nil
    }
    
    let bufferSize = SecKeyGetBlockSize(publicKey)
    var encryptedData = Data(count: bufferSize)
    
    var encryptedLength = bufferSize
    let status = encryptedData.withUnsafeMutableBytes { encryptedBytes in
        dataToEncrypt.withUnsafeBytes { plainTextBytes in
            SecKeyEncrypt(publicKey,
                          .oaep,
                          plainTextBytes.baseAddress!,
                          dataToEncrypt.count,
                          encryptedBytes.baseAddress!,
                          &encryptedLength)
        }
    }
    
    guard status == errSecSuccess else {
        print("❌ Error en el cifrado RSA: \(status)")
        return nil
    }
    
    encryptedData.count = encryptedLength
    return encryptedData.base64EncodedString()
}

/**
 * 🔑 Convierte una clave pública en formato PEM a un objeto SecKey.
 */
func getPublicKey(from pemString: String) -> SecKey? {
    let keyString = pemString
        .replacingOccurrences(of: "-----BEGIN RSA PUBLIC KEY-----", with: "")
        .replacingOccurrences(of: "-----END RSA PUBLIC KEY-----", with: "")
        .replacingOccurrences(of: "\n", with: "")
    
    guard let keyData = Data(base64Encoded: keyString) else {
        print("❌ Error: No se pudo convertir la llave pública en Base64.")
        return nil
    }
    
    let options: [String: Any] = [
        kSecAttrKeyType as String: kSecAttrKeyTypeRSA,
        kSecAttrKeyClass as String: kSecAttrKeyClassPublic,
        kSecAttrKeySizeInBits as String: 2048
    ]
    
    return SecKeyCreateWithData(keyData as CFData, options as CFDictionary, nil)
}



Descifrar información enviada por Milio

Cuando recibas información cifrada desde Milio, debes usar tu llave privada, siguiendo estos pasos generales:

  1. Cargar tu llave privada: Asegúrate que esta llave esté almacenada de forma segura y únicamente accesible a tu aplicación. Esta llave debe estar en formato PEM (-----BEGIN RSA PRIVATE KEY-----, -----END RSA PRIVATE KEY-----).
  2. Desencriptar la información recibida:
    • Usa una biblioteca o módulo que soporte RSA para descifrado.
    • Proporciona tu llave privada a esta biblioteca para descifrar el mensaje.
    • Obtendrás el texto original desencriptado.

Ejemplo

import {privateDecrypt} from 'crypto'
import * as constants from 'constants'
...

public decryptPrivateKey = (
    privateKey: string,
    data: Buffer<ArrayBufferLike>,
  ) => {
    try {
      return privateDecrypt(
        {key: privateKey, padding: constants.RSA_PKCS1_OAEP_PADDING},
        data,
      ).toString('utf8')
    } catch (error) {
      //catch error
    }
  }

Recomendaciones importantes:

  • Seguridad: Nunca compartas tu llave privada con terceros y asegúrate de almacenarla en un lugar seguro, preferiblemente utilizando servicios o bóvedas de secretos seguras.
  • Compatibilidad: Usa siempre algoritmos estándar (como RSA) para garantizar compatibilidad con los servicios de Milio.