2012-06-12 26 views

Respuesta

8

Sí, las firmas de cifrado PKCS # 1 y PKCS # 1 son different. En el caso de cifrado (el que probó), el mensaje de entrada simplemente se rellena antes de que se exponga.

PKCS # 1 signagtures en el otro lado primero calculará una estructura ASN.1 DER de la forma

DigestInfo ::= SEQUENCE { 
    digestAlgorithm AlgorithmIdentifier, 
    digest OCTET STRING 
} 

Esto entonces se rellena de nuevo para formar el mensaje codificado EM

EM = 0x00 || 0x01 || PS || 0x00 || T 

donde PS es una cadena de relleno de 0xff de longitud suficiente. Si reproduce este EM y usa RSA_private_encrypt, obtendrá la codificación de firma PKCS # 1 v1.5 correcta, la misma que obtendría con RSA_sign o incluso mejor, utilizando el genérico EVP_PKEY_sign.

Aquí hay una pequeña demostración en Ruby:

require 'openssl' 
require 'pp' 

data = "test" 
digest = OpenSSL::Digest::SHA256.new 
hash = digest.digest("test") 
key = OpenSSL::PKey::RSA.generate 512 

signed = key.sign(digest, data) 
dec_signed = key.public_decrypt(signed) 

p hash 
pp OpenSSL::ASN1.decode dec_signed 

Los SHA-256 de hash impresiones de la siguiente manera:

"\x9F\x86\xD0\x81\x88L}e\x9A/..." 

dec_signed es el resultado de RSA_sign descifrado de nuevo con la clave pública - esto da Devolvemos exactamente la entrada a la función RSA con el relleno eliminado, y como resultado, esta es exactamente la estructura DigestInfo mencionada anteriormente:

#<OpenSSL::ASN1::Sequence:0x007f60dc36b250 
@infinite_length=false, 
@tag=16, 
@tag_class=:UNIVERSAL, 
@tagging=nil, 
@value= 
    [#<OpenSSL::ASN1::Sequence:0x007f60dc36b318 
    @infinite_length=false, 
    @tag=16, 
    @tag_class=:UNIVERSAL, 
    @tagging=nil, 
    @value= 
    [#<OpenSSL::ASN1::ObjectId:0x007f60dc36b390 
     @infinite_length=false, 
     @tag=6, 
     @tag_class=:UNIVERSAL, 
     @tagging=nil, 
     @value="SHA256">, 
     #<OpenSSL::ASN1::Null:0x007f60dc36b340 
     @infinite_length=false, 
     @tag=5, 
     @tag_class=:UNIVERSAL, 
     @tagging=nil, 
     @value=nil>]>, 
    #<OpenSSL::ASN1::OctetString:0x007f60dc36b2a0 
    @infinite_length=false, 
    @tag=4, 
    @tag_class=:UNIVERSAL, 
    @tagging=nil, 
    @value="\x9F\x86\xD0\x81\x88L}e\x9A/...">]> 

Como puede ver, el valor del campo digest de DigestInfo es el mismo que el hash SHA-256 que calculamos nosotros mismos.

+0

Gracias por la respuesta detallada. Obtuve la firma correcta usando RSA_sign con NID_sha1 (NID_sha1WithRSA es el incorrecto), y creo que puedo obtener el valor codificado que es la entrada de RSA_private_encrypt modificando la función RSA_sign de OpenSSL. ¡De nuevo muchas gracias! –

+0

Lo siento, otra pregunta, ¿cómo podría obtener el EM con OpenSSL?Seguí el RSA_sign() y encontré i = RSA_private_encrypt (i, s, sigret, rsa, RSA_PKCS1_PADDING); que termina llevando a una función rsa_priv_enc que no puedo encontrar en ningún otro lado. Gracias –

+1

Y, ¿qué hace RSA_PKCS1_PADDING hacer aquí? –

3

Creo que estás trabajando en el nivel de abstracción de OpenSSL incorrecto; probablemente debería estar utilizando la función rsa.h -declared RSA_sign() y RSA_verify(), que estaban destinadas a ser usadas en PKCS#1 -firmas compatibles.

+0

Gracias por responder. Todavía no entiendo qué más RSA_sign() espera las funciones de encriptación hash y RSA? ¿No deberían estos dos ser suficiente? –

+0

También maneja el relleno PKCS # 1 y la codificación ASN.1; si solo está firmando contenido sin relleno, puede generar debilidades en RSA y la codificación es interoperar con otros programas de manera confiable. – sarnold

+0

Utilicé RSA_sign (NID_SHA1, ...), pero el resultado no es el mismo que obtuve con xmlsec (API de firma xml). Me pregunto si RSA_sign (NID_SHA1, ...) está haciendo RSASSA-PKCS1-v1_5? –

Cuestiones relacionadas