Saltar al contenido

Diferencia entre SHA256withRSA y SHA256 luego RSA

Solución:

La diferencia

La diferencia entre firmar con "SHA256withRSA" y calcular el hash SHA256 y firmarlo con "RSA" (= "NONEwithRSA") es ante todo que, en el primer caso, el valor hash SHA-256 calculado se encapsula primero en un DigestInfo estructura

DigestInfo ::= SEQUENCE 
    digestAlgorithm DigestAlgorithm,
    digest OCTET STRING

antes de ser acolchado y luego encriptado, mientras que en el último caso el valor hash SHA256 desnudo es acolchado y encriptado.

Si son diferentes, ¿hay alguna forma de modificar el método 2 para que ambos métodos den el mismo resultado?

En primer lugar, tendrá que encapsular el valor hash en un DigestInfo estructura antes de firmar usando "NONEwithRSA".

La sección 9.2 de RFC 3447 ayuda aquí al indicar en la Nota 1 que

1. For the six hash functions mentioned in Appendix B.1, the DER
   encoding T of the DigestInfo value is equal to the following:
   ...
   SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00
                04 20 || H.

Haciendo que funcione

En respuesta a la sección anterior, el OP actualizó su pregunta con el código actualizado. Desafortunadamente, sin embargo, todavía no le funcionó. Por lo tanto,

El código del OP

Ejecuté el código del OP (SignInSteps.java). Como no proporcionó el privado key, Usé una prueba key propio (demo-rsa2048.p12). El resultado:

GreenhandOriginal:
1B9557B6A076226FA4C26A9370A0E9E91B627F14204D427B03294EC4BFC346FDEEFB3A483B1E5A0593F26E9DE87F9202E1064F4D75B24B8FA355B23A560AF263361BB94B2339C3A01952C447CAC862AA9DCAB64B09ABAA0AD50232CDB299D1E4B5F7138F448A87ED32BFF4B5B66F35FFA08F13FD98DFCEC7114710282E463245311DA7A56CBEA958D88137A8B507D8601464535978EFE36EE37EF721260DB7112484F244409F0BD64C823ACFB13D06ABA84A9A0C5AB207E19231D6A71CC80F07FDA2A9654F0F609C2C3396D6DFFBBB10EF4C3D4B5ADFC72EACC044E81F252B699F095CFEF8630B284B1F6BD7201367BD5FDF2BB4C20BD07B9CC20B214D86C729
4B9ECA6DD47C1B230D972E7DA026165F1CE743EC96825E4C13DFE2C6437FE673A13CA622047EE7D2F7C5280198D81550A1CBD17F8E8A3C4C2D53A746FA6464AA5194FC2782527B014F017008D89BB2C80B7FA367C74FE01369986B56BCE7DC573A11ED884511F0CB12160CA5E42D488451AA8961BF5A9F71E6A5E89F19BC8EFAC26DDE989A0369667EE74372F6E558887FE2561EA926B441AB8F0FD3DEDD608A671011313372084B059CAD7E4807AC852C0873C57F216349422771C089678BAC3021D054C4427EADE70219E251617B83E68640DD7D03C3F99E47F79EB71C124F59EDEA724496A4552F2E9E1F90DDE550745E85483D823F146982C6D2008FE9AA

GreenhandUpdated:
method 1: 4B9ECA6DD47C1B230D972E7DA026165F1CE743EC96825E4C13DFE2C6437FE673A13CA622047EE7D2F7C5280198D81550A1CBD17F8E8A3C4C2D53A746FA6464AA5194FC2782527B014F017008D89BB2C80B7FA367C74FE01369986B56BCE7DC573A11ED884511F0CB12160CA5E42D488451AA8961BF5A9F71E6A5E89F19BC8EFAC26DDE989A0369667EE74372F6E558887FE2561EA926B441AB8F0FD3DEDD608A671011313372084B059CAD7E4807AC852C0873C57F216349422771C089678BAC3021D054C4427EADE70219E251617B83E68640DD7D03C3F99E47F79EB71C124F59EDEA724496A4552F2E9E1F90DDE550745E85483D823F146982C6D2008FE9AA
method 2: 4B9ECA6DD47C1B230D972E7DA026165F1CE743EC96825E4C13DFE2C6437FE673A13CA622047EE7D2F7C5280198D81550A1CBD17F8E8A3C4C2D53A746FA6464AA5194FC2782527B014F017008D89BB2C80B7FA367C74FE01369986B56BCE7DC573A11ED884511F0CB12160CA5E42D488451AA8961BF5A9F71E6A5E89F19BC8EFAC26DDE989A0369667EE74372F6E558887FE2561EA926B441AB8F0FD3DEDD608A671011313372084B059CAD7E4807AC852C0873C57F216349422771C089678BAC3021D054C4427EADE70219E251617B83E68640DD7D03C3F99E47F79EB71C124F59EDEA724496A4552F2E9E1F90DDE550745E85483D823F146982C6D2008FE9AA

Por lo tanto, a diferencia de las observaciones del OP, las firmas son iguales en el caso del código actualizado.

Sin asumir errores de copiar y pegar, aún puede haber otras diferencias involucradas.

El entorno

Probé usando Java 8 (1.8.0_20) con archivos de jurisdicción ilimitados agregados y BouncyCastle 1.52, 1.49 y 1.46 (con una pequeña modificación del código de prueba debido a los cambios de la API de BC).

El OP mencionado en un comentario:

Java es la actualización 66 de JRE 8. BouncyCastle es bcprov-jdk15on-153.jar.

Así actualicé Java, todavía no hay diferencia.

Luego actualicé BouncyCastle a 1.53. Y, de hecho, de repente los resultados fueron diferentes:

GreenhandOriginal:
1B9557B6A076226FA4C26A9370A0E9E91B627F14204D427B03294EC4BFC346FDEEFB3A483B1E5A0593F26E9DE87F9202E1064F4D75B24B8FA355B23A560AF263361BB94B2339C3A01952C447CAC862AA9DCAB64B09ABAA0AD50232CDB299D1E4B5F7138F448A87ED32BFF4B5B66F35FFA08F13FD98DFCEC7114710282E463245311DA7A56CBEA958D88137A8B507D8601464535978EFE36EE37EF721260DB7112484F244409F0BD64C823ACFB13D06ABA84A9A0C5AB207E19231D6A71CC80F07FDA2A9654F0F609C2C3396D6DFFBBB10EF4C3D4B5ADFC72EACC044E81F252B699F095CFEF8630B284B1F6BD7201367BD5FDF2BB4C20BD07B9CC20B214D86C729
4B9ECA6DD47C1B230D972E7DA026165F1CE743EC96825E4C13DFE2C6437FE673A13CA622047EE7D2F7C5280198D81550A1CBD17F8E8A3C4C2D53A746FA6464AA5194FC2782527B014F017008D89BB2C80B7FA367C74FE01369986B56BCE7DC573A11ED884511F0CB12160CA5E42D488451AA8961BF5A9F71E6A5E89F19BC8EFAC26DDE989A0369667EE74372F6E558887FE2561EA926B441AB8F0FD3DEDD608A671011313372084B059CAD7E4807AC852C0873C57F216349422771C089678BAC3021D054C4427EADE70219E251617B83E68640DD7D03C3F99E47F79EB71C124F59EDEA724496A4552F2E9E1F90DDE550745E85483D823F146982C6D2008FE9AA

GreenhandUpdated:
method 1: 6BAAAC1060B6D0D56AD7D45A1BEECE82391088FF47A8D8179EFBBEB0925C4AC6C9DFC56F672E99F4A6E3C106A866B70513C25AE11B267286C584A136FBC20C4D1E7B10697352DF020BA5D67029A6EF890B2674F02C496CB1F1EBB0D4DBB580EB045DBB0FA0D7D73B418FF63F345658C6C73DA742FE260C9639C94967A928F74F61DACA03310B9986C32D83CAB8C7FC13E80612CCFC0B7E3E35BEA04EAEBDAA55FB8837B4661DC71499B4A0B1D36E1D23D9927CDB55C237D5AB2E5C088F29C6FAFAD9FE64DD4851CEC113560864E9923D485D0C6E092C8EBE82D29C312E5835B38EE9BD6B8B4BCC753EF4EE4D0977B2E781B391839E3EC31C36E5B1AA0CE90227
method 2: 4B9ECA6DD47C1B230D972E7DA026165F1CE743EC96825E4C13DFE2C6437FE673A13CA622047EE7D2F7C5280198D81550A1CBD17F8E8A3C4C2D53A746FA6464AA5194FC2782527B014F017008D89BB2C80B7FA367C74FE01369986B56BCE7DC573A11ED884511F0CB12160CA5E42D488451AA8961BF5A9F71E6A5E89F19BC8EFAC26DDE989A0369667EE74372F6E558887FE2561EA926B441AB8F0FD3DEDD608A671011313372084B059CAD7E4807AC852C0873C57F216349422771C089678BAC3021D054C4427EADE70219E251617B83E68640DD7D03C3F99E47F79EB71C124F59EDEA724496A4552F2E9E1F90DDE550745E85483D823F146982C6D2008FE9AA

Curiosamente, solo difiere el valor del método 1 en el código actualizado. Por lo tanto, miré los objetos intermedios en ese caso

[BC 1.52]
hash: 03AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4
algo: 2.16.840.1.101.3.4.2.1
info: 3031300D06096086480165030402010500042003AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4

[BC 1.53]
hash: 03AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4
algo: 2.16.840.1.101.3.4.2.1
info: 302F300B0609608648016503040201042003AC674216F3E15C761EE1A5E255F067953623C8B388B4459E13F978D7C846F4

Por lo tanto, BouncyCastle 1.53 codifica el objeto DigestInfo de manera diferente. Y la codificación en 1.52 (e inferior) es la esperada por RFC 3447 Sección 9.2.

Al observar los volcados de ASN.1, se ve que BC 1.52 codifica el AlgorithmIdentifier como

 2  13:   SEQUENCE 
   <06 09>
 4   9:     OBJECT IDENTIFIER sha-256 (2 16 840 1 101 3 4 2 1)
      :       (NIST Algorithm)
   <05 00>
15   0:     NULL
      :     

mientras que BC 1.53 crea

 2  11:   SEQUENCE 
   <06 09>
 4   9:     OBJECT IDENTIFIER sha-256 (2 16 840 1 101 3 4 2 1)
      :       (NIST Algorithm)
      :     

Entonces, en 1.53 faltan los parámetros del algoritmo. Esto sugiere cambiar la línea

AlgorithmIdentifier sha256Aid = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, null);

para

AlgorithmIdentifier sha256Aid = new AlgorithmIdentifier(NISTObjectIdentifiers.id_sha256, DERNull.INSTANCE);

y de repente también funciona con BouncyCastle 1.53, ¡los valores para el método 1 y el método 2 coinciden! 😉

TL; DR

No use null como los parámetros SHA-256 al instanciar el AlgorithmIdentifier, usar DERNull.INSTANCE en lugar de.

¿Cómo hice …

En un comentario, el OP indicó que le gustaría saber más sobre

  1. ¿Cómo se inspecciona el objeto intermedio de BouncyCastle y
  2. cómo se producen los volcados ASN.1.

Entonces…

… inspeccionar el objeto intermedio

Bastante sencillo. Primero dividí la línea

rsaSignature.update(di.toASN1Primitive().getEncoded());

en el código actualizado como

byte[] encodedDigestInfo = di.toASN1Primitive().getEncoded();
rsaSignature.update(encodedDigestInfo);

y luego se agregaron salidas de consola

System.out.println("    hash: " + bytesToHex(outputDigest));
System.out.println("    algo: " + sha256Aid.getAlgorithm());
System.out.println("    info: " + bytesToHex(encodedDigestInfo));

Finalmente ejecuté el código con las diferentes versiones de BouncyCastle.

… producir los vertederos ASN.1

Existe una utilidad conocida llamada dumpasn1 por Peter Gutmann que se ha convertido en el núcleo de muchas herramientas de línea de comando y GUI para crear y mostrar volcados ASN.1. Actualmente uso GUIdumpASN-ng.

En el caso que nos ocupa, guardé el contenido del byte[] encodedDigestInfo a un archivo (que se puede hacer usando, por ejemplo, Files.write) y abrió estos archivos en GUIdumpASN-ng.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *