Diferença entre assinar com o SHA256 vs. assinar com o RSA-SHA256

eu jogo com assinaturas digitais usando o nó.js. Para fins de teste, eu criei uma assinatura digital de alguns dados XML, primeiro usando apenas SHA256, em seguida, usando RSA-SHA256.

o que me intriga é que ambos os métodos de assinatura criam exactamente a mesma assinatura. Ambas as assinaturas são idênticas. Se eles são idênticos, então por que dois métodos diferentes (SHA256 vs. RSA-SHA256)?

incluo o código abaixo:

var crypto = require('crypto'),
    path   = require('path'),
    fs     = require('fs'),

    pkey_path = path.normalize('private_key.pem'),
    pkey = '';

function testSignature(pkey) {
    var sign1 = crypto.createSign('RSA-SHA256'),
        sign2 = crypto.createSign('SHA256');

    fs.ReadStream('some_document.xml')
        .on('data', function (d) {
            sign1.update(d);
            sign2.update(d);
        })
        .on('end', function () {
            var s1 = sign1.sign(pkey, "base64"),
                s2 = sign2.sign(pkey, "base64");

            console.log(s1);
            console.log(s2);
        });
}

// You need to read private key into a string and pass it to crypto module.
// If the key is password protected, program execution will stop and
// a prompt will appear in console, awaiting input of password.

testSignature(fs.readFileSync(pkey_path));

o código acima mostra alguma cadeia de caracteres, que é a assinatura, e então novamente exatamente a mesma string, que também é uma assinatura dos mesmos dados, mas criado com - supostamente - algoritmo diferente, mas é idêntico ao anterior...

Author: Arim, 2014-11-20

2 answers

Uma Assinatura não pode ser criada apenas pela SHA256.

SHA256 é um algoritmo de hashing, ou seja, um algoritmo que cria um número de impressões digitais pequeno que representa uma quantidade arbitrária de dados. Para produzir uma assinatura, esta impressão digital ainda tem de ser tratada de alguma forma para permitir a identificação do titular de alguma chave de assinatura privada. Um desses tratamentos é criptografar a impressão digital usando a chave privada de um par de chaves rsa permitindo que outros para descriptografar o resultado usando o associado chave pública e assim verificar que o guardião da chave privada realmente deve ter sido o assinante.

No contexto da sua API crypto que o esquema de encriptação RSA ou é o tratamento padrão quando o tratamento não é explicitamente nomeado, ou o tipo de tratamento é deduzido da chave privada que usa como parâmetro na chamada sign - Se é uma chave RSA privada, usa a RSA; se é uma chave DSA, usa a DSA; ...

 11
Author: mkl, 2014-11-20 13:53:56

O que está a ver é duas vezes a assinatura PKCS#1 v1.5. Este é um esquema determinístico para assinaturas, então ele sempre retorna o mesmo resultado (compare isso com o esquema PSS, que é randomizado, proporcionando melhores propriedades de segurança). RSA PKCS#1 v1.5 geração de assinatura e geração de assinatura PSS é definida dentro RFC 3447 (também conhecido como as especificações RSA v2.1).

Se usar o seu código com RSA 512 bits (apenas para fins de teste, use uma chave de 2048 bits ou mais) então você terá o seguinte resultado:

Chave Privada:

-----BEGIN RSA PRIVATE KEY-----
MIIBOgIBAAJBALLA/Zk6+4JFJ+XdU6wmUkuEhGa8hLZ+m6J3puZbc9E+DSt7pW09
yMYwHF5MMICxE86cA6BrLjQLUUwvquNSK0ECAwEAAQJAcI/w4e3vdRABWNFvoCcd
iWpwSZWK6LR/YuZ/1e1e2DJw+NXyPXbilSrLvAdxnjlWTsTxUiEy1jFh36pSuvMk
AQIhAO4WtgysOoWkyvIOLIQwD0thWfdHxTpxqfd6flrBJ91hAiEAwDOQqHhnSeET
+N/hwUJQtCkHBJqvMF/kAi4Ry5G+OeECIEg1Exlc0pLdm781lUKx4LGX4NUiKyrC
di3cNJ4JnrGBAiEAi2gbYYbLbDO8F8TTayidfr9PXtCPhyfWKpqdv6i7cCECIH7A
6bh0tDCl6dOXQwbhgqF4hXiMsqe6DaHqIw8+XLnG
-----END RSA PRIVATE KEY-----

Assinatura como base 64 (usando o seu código):

YY6sur9gkHXH23cUbDMYjCJYqDdBK8GKp4XyRNl8H09cW8H/gKQI9Z6dkLMhNh7oPq1yABCRfTP8yRtfLVj7FA==

E em hexadecimais

618eacbabf609075c7db77146c33188c2258a837412bc18aa785f244d97c1f4f5c5bc1ff80a408f59e9d90b321361ee83ead720010917d33fcc91b5f2d58fb14

Descodificado utilizando RSA RAW (ou seja, apenas exponenciação modular com o expoente público):

0001ffffffffffffffffffff003031300d0609608648016503040201050004202af565b95e5f4479492c520c430f07ae05d2bcff8923322e6f2ef6404d72ac64

Este é um exemplo muito claro de uma assinatura PKCS#1, facilmente reconhecida pelo enchimento FF, seguido pelo ASN.1 estrutura (começando por 30, sequência):

SEQUENCE (2 elem)
  SEQUENCE (2 elem)
  OBJECT IDENTIFIER 2.16.840.1.101.3.4.2.1 {joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) nistAlgorithm(4) hashAlgs(2) sha256(1)}
    NULL
  OCTET STRING(32 byte) 2AF565B95E5F4479492C520C430F07AE05D2BCFF8923322E6F2EF6404D72AC64
Então aquela coisa em o fim é o hash, neste caso sobre apenas Test 123\n Como Eu não queria digitar qualquer XML hoje.
$ sha256sum some_document.xml 
2af565b95e5f4479492c520c430f07ae05d2bcff8923322e6f2ef6404d72ac64  some_document.xml

$ sha256sum some_document.xml 
2af565b95e5f4479492c520c430f07ae05d2bcff8923322e6f2ef6404d72ac64  some_document.xml
 3
Author: Maarten Bodewes, 2014-11-21 00:40:56