es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Las claves públicas RSA originales y restauradas son idénticas, pero sus representaciones codificadas en X509 no lo son?

Estoy generando claves públicas y privadas RSA de 2048 bits, codificándolas en formato X509, convirtiendo el resultado al formato PKCS#1, codificando eso como una cadena Base64 y guardándolo en una base de datos. Luego, recupero la cadena de la base de datos, la restauro al formato PKCS#1, la convierto al formato X509 y luego restauro el objeto de clave pública.

Cuando llamo println() en los objetos de clave pública original y restaurado, confirmo que tienen el mismo módulo y exponente público. Cuando compruebo su igualdad con .equals(), la aserción devuelve verdadero. Sin embargo, cuando comparo la representación codificada en X509 del objeto de clave pública original y la del objeto de clave pública restaurado, son diferentes. Esto es problemático para mí porque uso un hash derivado de este valor para identificar las claves.

¿Por qué está sucediendo esto y cómo puedo solucionarlo?

Debo almacenar las claves en la base de datos en formato PKCS#1 porque el archivo de la base de datos se trasladará a un dispositivo iOS y las claves se restaurarán allí, y el marco de seguridad de Apple solo permite la exportación o importación de claves RSA en formato PKCS#1.

Estoy usando Kotlin en JVM; el código a continuación reproduce el problema:

import org.bouncycastle.asn1.ASN1Primitive
import org.bouncycastle.asn1.DERNull
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
import org.bouncycastle.asn1.x509.AlgorithmIdentifier
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
import java.security.KeyFactory
import java.security.KeyPair
import java.security.KeyPairGenerator
import java.security.PublicKey
import java.security.spec.X509EncodedKeySpec
import java.util.*
import kotlin.test.Test

class IssueExample {
    @Test
    fun demonstrateProblem() {
        //Generate RSA key pair
        val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("RSA")
        keyPairGenerator.initialize(2048)
        val keyPair = keyPairGenerator.generateKeyPair()

        //Convert public key to X509, then to PKCS1 format
        val pubKeyX509Bytes = keyPair.public.encoded
        val sPubKeyInfo: SubjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(pubKeyX509Bytes)
        val pubKeyPrimitive: ASN1Primitive = sPubKeyInfo.parsePublicKey()
        val pubKeyPkcs1Bytes: ByteArray = pubKeyPrimitive.encoded

        //Convert PKCS1 to Base64 string
        val encoder = Base64.getEncoder()
        val base64PubKey = encoder.encodeToString(pubKeyX509Bytes)

        //Restore Base64 string to PKCS#1
        val decoder = Base64.getDecoder()
        val restoredPubKeyPKCS1Bytes = decoder.decode(base64PubKey)

        //Restore PKCS#1 to X509
        val algorithmIdentifier: AlgorithmIdentifier = AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
        val restoredPubKeyX509Bytes: ByteArray = SubjectPublicKeyInfo(algorithmIdentifier, pubKeyPkcs1Bytes).encoded

        //Restore X509 to public key
        val restoredPubKey: PublicKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(pubKeyX509Bytes))

        //Comparing the two public key objects returns true
        println(restoredPubKey.equals(keyPair.public))
        //And calling println() yields identical results for both
        println(restoredPubKey)
        println(keyPair.public)
        //Yet their X509 representations return false!!
        println(restoredPubKey.encoded.equals(keyPair.public.encoded))
        println(restoredPubKey.encoded)
        println(keyPair.public.encoded)
    }
}
Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema es que estás restaurando la cadena codificada en Base64 al formato PKCS # 1 en lugar de restaurarla al formato X509. Esto significa que la clave restaurada no está en el mismo formato que la clave original.

    Para solucionar esto, debes restaurar la cadena codificada en Base64 al formato PKCS # 1, como lo estás haciendo actualmente, y luego convertirla al formato X509 antes de restaurarla al objeto de clave pública. Para hacer esto, reemplaza la línea:

    `
    val restoredPubKeyX509Bytes: ByteArray = SubjectPublicKeyInfo(algorithmIdentifier, pubKeyPkcs1Bytes).encoded
    `

    con:

    `
    val restoredPubKeyX509Bytes: ByteArray = SubjectPublicKeyInfo.getInstance(pubKeyPkcs1Bytes).encoded
    `

    Esto asegurará que la clave restaurada esté en el formato correcto antes de ser convertida en un objeto de clave pública.

    Una vez que hagas este cambio, la representación codificada en X509 de los objetos de clave pública original y restaurada debe ser la misma, y deberías poder utilizar el hash derivado de este valor para identificar las claves.

    Aquí está el código modificado:

    “ `
    import org.bouncycastle.asn1.ASN1Primitive
    import org.bouncycastle.asn1.DERNull
    import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers
    import org.bouncycastle.asn1.x509.AlgorithmIdentifier
    import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo
    import java.security.KeyFactory
    import java.security.KeyPair
    import java.security.KeyPairGenerator
    import java.security.PublicKey
    import java.security.spec.X509EncodedKeySpec
    import java.util.*
    import kotlin.test.Test

    class IssueExample {

    @Test
    fun demonstrateProblem() {
        //Generar par de claves RSA
        val keyPairGenerator: KeyPairGenerator = KeyPairGenerator.getInstance("RSA")
        keyPairGenerator.initialize(2048)
        val keyPair = keyPairGenerator.generateKeyPair()
    
        //Convertir clave pública a formato X509, luego a formato PKCS1
        val pubKeyX509Bytes = keyPair.public.encoded
        val sPubKeyInfo: SubjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(pubKeyX509Bytes)
        val pubKeyPrimitive: ASN1Primitive = sPubKeyInfo.parsePublicKey()
        val pubKeyPkcs1Bytes: ByteArray = pubKeyPrimitive.encoded
    
        //Convertir PKCS1 a cadena codificada en Base64
        val encoder = Base64.getEncoder()
        val base64PubKey = encoder.encodeToString(pubKeyPkcs1Bytes)
    
        //Restaurar cadena codificada en Base64 a PKCS # 1
        val decoder = Base64.getDecoder()
        val restoredPubKeyPKCS1Bytes = decoder.decode(base64PubKey)
    
        //Restaurar PKCS # 1 a X509
        val algorithmIdentifier: AlgorithmIdentifier = AlgorithmIdentifier(PKCSObjectIdentifiers.rsaEncryption, DERNull.INSTANCE);
        val restoredPubKeyX509Bytes: ByteArray = SubjectPublicKeyInfo.getInstance(restoredPubKeyPKCS1Bytes).encoded
    
        //Restaurar X509 a clave pública
        val restoredPubKey: PublicKey = KeyFactory.getInstance("RSA").generatePublic(X509EncodedKeySpec(restoredPubKeyX509Bytes))
    
        //Comparar los dos objetos de clave pública devuelve verdadero
        println(restoredPubKey.equals(keyPair.public))
        //¡¡Y llamar a println () arroja resultados idénticos para ambos!!
        println(restoredPubKey)
        println(keyPair.public)
        //¡Ahora sus representaciones X509 también son iguales!
        println(restoredPubKey.encoded.equals(keyPair.public.encoded))
        println(restoredPubKey.encoded)
        println(keyPair.public.encoded)
    }
    

    }
    “`

Comments are closed.