-1

问题: nodejs 应用程序创建一个作为许可证的 json 文件,而 asp.net 核心应用程序需要使用公钥验证信息。节点应用程序使用 RSA sha256 使用私钥对其进行签名,.net 核心应用程序将使用公钥进行验证。谢谢你。json 文件包含以下信息:

    {
    "info":{
    "validto":1514678400000,"validfrom":1498608000000,"nodes":10,"email":"person@example.com","name":"TAC Account","phone":"3333333333333","address":"something"
    },

"signature":
    {
    "data":[159,1,86,24,244,199,39,40,251,195,175,80,18,33,232,63,178,213,205,129,150,58,243,154,138,168,61,197,222,50,222,80,33,82,135,243,121,250,176,33,9,25,167,177,235,193,246,236,235,19,187,118,57,64,38,143,42,35,12,207,133,33,166,201,34,76,40,87,242,163,141,14,218,198,247,91,191,132,86,162,194,143,177,147,65,171,160,41,2,244,130,53,82,178,72,39,247,45,242,139,243,59,79,196,12,70,14,202,246,48,231,66,38,94,235,237,204,77,40,252,216,63,41,204,210,228,93,16,201,4,123,104,119,251,56,160,9,105,180,217,129,113,19,166,89,199,203,129,47,218,20,131,94,87,251,193,177,111,151,72,187,79,0,63,0,168,36,147,155,47,5,123,176,203,189,111,199,165,90,12,122,2,148,62,107,115,132,183,76,147,7,238,154,174,198,226,170,204,193,18,197,30,191,189,133,134,33,33,159,14,90,153,219,226,184,149,19,179,210,171,136,39,144,178,229,236,126,11,252,80,65,83,181,117,26,37,231,92,151,110,33,93,239,243,129,58,201,214,231,248,151,23,19,170,0,19],
    "type":"Buffer"
    }

    }

我们在 asp.net 核心方面尝试了很多东西,但没有成功,给定的公钥有一些不寻常的字符,如 \n,通常看不到。以下是我们尝试过的不同方法之一:

using System ;
using System.IO ;
using System.Text ;
using Org.BouncyCastle.Crypto ;
using Org.BouncyCastle.Crypto.Parameters ;
using Org.BouncyCastle.OpenSsl ;
using Org.BouncyCastle.Security ;

namespace ValidateRsa
{
    internal class Program
    {
        private static readonly string info =
                @"{""validto"":1514678400000,""validfrom"":1498608000000,""nodes"":10,""email"":""person@example.com"",""name"":""TAC Account"",""phone"":""3333333333333"",""address"":""something""}"
            ;
        private static readonly byte[] signature =
        {
            159, 1, 86, 24, 244, 199, 39, 40, 251, 195, 175, 80, 18, 33, 232, 63, 178, 213, 205, 129, 150, 58, 243, 154, 138, 168,
            61, 197, 222, 50, 222, 80, 33, 82, 135, 243, 121, 250, 176, 33, 9, 25, 167, 177, 235, 193, 246, 236, 235, 19, 187, 118,
            57, 64, 38, 143, 42, 35, 12, 207, 133, 33, 166, 201, 34, 76, 40, 87, 242, 163, 141, 14, 218, 198, 247, 91, 191, 132, 86,
            162, 194, 143, 177, 147, 65, 171, 160, 41, 2, 244, 130, 53, 82, 178, 72, 39, 247, 45, 242, 139, 243, 59, 79, 196, 12,
            70, 14, 202, 246, 48, 231, 66, 38, 94, 235, 237, 204, 77, 40, 252, 216, 63, 41, 204, 210, 228, 93, 16, 201, 4, 123, 104,
            119, 251, 56, 160, 9, 105, 180, 217, 129, 113, 19, 166, 89, 199, 203, 129, 47, 218, 20, 131, 94, 87, 251, 193, 177, 111,
            151, 72, 187, 79, 0, 63, 0, 168, 36, 147, 155, 47, 5, 123, 176, 203, 189, 111, 199, 165, 90, 12, 122, 2, 148, 62, 107,
            115, 132, 183, 76, 147, 7, 238, 154, 174, 198, 226, 170, 204, 193, 18, 197, 30, 191, 189, 133, 134, 33, 33, 159, 14, 90,
            153, 219, 226, 184, 149, 19, 179, 210, 171, 136, 39, 144, 178, 229, 236, 126, 11, 252, 80, 65, 83, 181, 117, 26, 37,
            231, 92, 151, 110, 33, 93, 239, 243, 129, 58, 201, 214, 231, 248, 151, 23, 19, 170, 0, 19
        } ;
        private static void Main (string[] args)
        {
            Console.WriteLine ("Setting up validator...") ;
            TextReader text = File.OpenText (@"X:\Scratch\pubkey.asc") ;
            var pemr = new PemReader (text) ;
            object pem = pemr.ReadObject () ;
            text.Close () ;
            var keyParams = (RsaKeyParameters) (AsymmetricKeyParameter) pem ;
            ISigner sig = SignerUtilities.GetSigner ("SHA-256withRSA") ;
            sig.Init (false, keyParams) ;
            byte[] infoBytes = Encoding.ASCII.GetBytes (Program.info) ;
            sig.BlockUpdate (infoBytes, 0, infoBytes.Length) ;
            if (sig.VerifySignature (Program.signature))
                Console.WriteLine ("Verified!") ;
            else
                Console.WriteLine ("Failed!") ;
            Console.ReadLine () ;
        }
    }
}

公钥格式如下:

 -----BEGIN RSA PUBLIC KEY
-----\nMIIBCgKCAQEAqao1ZkAYKDybHSeoy79ySQDcXODByDRaZKT2nYwT8GrYohBle8phB5LgSoQu\nVD7ErRFGHxutcqPrfL3AuTHg874Kmw6/G+25/FdC9uNJzLtCP+Z5mOrF5HlU8dGOOpTeq4y5\n0EPcj//YuO4kScj0wOOp1HMRwxsdVo\nAZUQwMz5w1QIoGL5CoW7RKiL/oQw0Mh0Ju+9ofVbovSzBTo0r7onqw6M0hOJScV86iQ21Ukl\nup/6CmXCMwcYK1Fr5J6YNbeZoQhkII7VazPMgZetJBCfm+iyBPSPARlf13RLM0cHzwIDAQAB\n-----END RSA PUBLIC KEY-----\n

nodejs 应用程序对数据进行签名的代码:

 const licenseSchema = new Schema({
  info: {
    name: String,
    address: String,
    phone: String,
    email: String,
    nodes: Number,
    validfrom: Schema.Types.Mixed,  // validfrom and validto must be either
    validto: Schema.Types.Mixed,    // valid Date strings or ms since epoch
  },

  signature: {
    type: { type: String, required: true },
    data: { type: Schema.Types.Mixed, required: true },
  },
});

// updates license.signature
licenseSchema.statics.createAndSignLicense = function createAndSignLicense(object, privateKey, cb) {
  let arrayInfo = [];
  arrayInfo = [
    object.name,
    object.address,
    object.phone.toString(),
    object.email,
    object.nodes.toString(),
    object.validfrom,
    object.validto,
  ];
  const sign = crypto.createSign('RSA-SHA256');
  sign.update(JSON.stringify(arrayInfo));
  const sig = sign.sign(privateKey);

  const LicenseModel = this;

  const licenseDoc = new LicenseModel({
    info: object,
    signature: {
      type: 'Buffer',
      data: Array.prototype.slice.call(sig, 0),
    },
  });

  licenseDoc.save((err) => {
    if (err) { return cb(err); }

    return cb(null, licenseDoc);
  });
};

还有另一个 nodejs 应用程序正在成功验证数据,示例如下,只是在 .net 中,事情没有走到一起:

    const Schema = mongoose.Schema;

export const Errors = {LicenseValidationError: 'LicenseValidationError'};

const LicenseDescription = {
    key: { type: String, unique: true },
    info: {
        name: String,
        address: String,
        phone: String,
        email: String,
        nodes: Number,
        validfrom: Schema.Types.Mixed,  // validfrom and validto must be either
        validto: Schema.Types.Mixed,    // valid Date strings or ms since epoch
    },
    signature: {
        type: { type: String, required: true },
        data: Schema.Types.Mixed
    }
};

// Application state variable representing license validity.
let isLicenseValid = false;

/*
 * uses the utils function with a validator to set the system-wide document
 * license is a file (buffer) or JSON license.
 * This method attempts to validate the input.
 *
 * See: License.statics.ValidateLicense()
 *
 * cb: function (err, license) { ... }
 */
const License = utils.createSchema(LicenseDescription, {
    validator: function (license, cb) {
        validateLicense(license, (err, valid) => {
            if (err) {
                return cb(err);
            }
            isLicenseValid = isLicenseWithinDateRange(license);
            return cb(null, true);
        });
    }
});


// license public key, hardcoded.
// Uses RSA-SHA256
    const pair = () => ({
    public: `-----BEGIN RSA PUBLIC KEY-----\nMIIBCgKCAQEAqao1ZkAYKDybHSeoy79ySQDcXODByDRaZKT2nYwT8GrYohBle8phB5LgSoQu\nVD7ErRFGHxutcqPrfL3AuTHg874Kmw6/G+25/FdC9uNJzLtCP+Z5mOrF5HlU8dGOOpTeq4y5\n0EPcj//YuO4kScj0wOOp1HMRwxsdVo+G00Q\nAZUQwMz5w1QIoGL5CoW7RKiL/oQw0Mh0Ju+9oV86iQ21Ukl\nup/6CmXCMwcYK17VazPMgZetJBCfm+iyBPSPARlf13RLM0cHzwIDAQAB\n-----END RSA PUBLIC KEY-----\n`
});

/*
 * Verifies the supplied license (must be a valid JSON object) against the
 * public key (hardcoded).
 *
 * Returns true if valid, false otherwise.
 */
const verifySignature = license => {
    winston.info('Verifying license signature:');

    // crypto.verify relies on specific key ordering (undefined behavior, unfortunately).
    // To try to force key order, we construct this object (with explicit toString calls
    // where applicable).
    const infoString = [
        license.info.name,
        license.info.address,
        license.info.phone,
        license.info.email,
        license.info.nodes.toString(),
        new Date(license.info.validfrom).toString(),
        new Date(license.info.validto).toString(),
    ];

    const infoMS = [
        license.info.name,
        license.info.address,
        license.info.phone,
        license.info.email,
        license.info.nodes.toString(),
        license.info.validfrom,
        license.info.validto,
    ];

    const verifyString = crypto.createVerify('RSA-SHA256'), verifyMS = crypto.createVerify('RSA-SHA256'), 
    licenseInfoString = JSON.stringify(infoString), licenseInfoMS = JSON.stringify(infoMS);

    // Currently the signature must be a buffer and the type field is ignored.
    let buf;
    try {
        buf = new Buffer(license.signature.data);
    } catch (parseError) {
        return false;
    }

    verifyString.update(licenseInfoString);
    verifyMS.update(licenseInfoMS);

    const isLicenseValid = verifyString.verify(pair().public, buf) || verifyMS.verify(pair().public, buf);
    winston.info(`The license signature is ${(isLicenseValid) ? 'valid.' : 'invalid.'}`);
    return isLicenseValid;
};
4

1 回答 1

0

我猜你的密钥文件有问题?

您的代码工作正常。

这是在节点中生成签名的示例:

var crypto = require('crypto');
var fs = require('fs');

var privateKey = fs.readFileSync('./junk').toString('utf8');
var publicKey = fs.readFileSync('./junk.pem').toString('utf8');

var sign = crypto.createSign('RSA-SHA256');
sign.update("Test123");
var sig = sign.sign(privateKey);
var bytes = Array.prototype.slice.call(sig, 0);
console.log(JSON.stringify(bytes));

var verify = crypto.createVerify('RSA-SHA256');
verify.update("Test123");
var success = verify.verify(publicKey, new Buffer(sig));

console.log("Did sign? " + success);

这是一个使用 C# .net 核心中的充气城堡验证它的示例(我已经简化,但它基本上正是您正在做的):

using System;
using System.IO;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Parameters;
using Org.BouncyCastle.OpenSsl;
using Org.BouncyCastle.Security;

namespace RsaTest
{
  class Program
  {
    static void Main(string[] args)
    {
      var signature = new byte[]
      {
        193, 185, 118, 187, 54, 28, 71, 173, 185, 255, 213, 61, 254, 51, 86, 168, 224, 11, 113, 23, 81, 123, 89,
        31, 89, 183, 142, 194, 7, 250, 194, 165, 230, 254, 74, 61, 15, 12, 137, 246, 151, 61, 83, 107, 112, 178,
        98, 183, 234, 247, 56, 11, 246, 179, 183, 74, 27, 190, 17, 99, 161, 31, 209, 178, 81, 41, 56, 214, 184, 165,
        232, 20, 125, 155, 25, 102, 104, 193, 1, 101, 143, 209, 192, 145, 47, 215, 190, 95, 196, 164, 69, 203, 206, 69,
        142, 18, 196, 155, 221, 8, 31, 179, 5, 165, 143, 29, 34, 148, 218, 177, 94, 31, 174, 218, 153, 52, 85, 156, 67,
        2, 157, 29, 111, 95, 231, 249, 212, 39, 123, 229, 75, 2, 18, 238, 44, 94, 181, 181, 98, 156, 150, 44, 219, 208,
        161, 18, 250, 117, 91, 146, 133, 233, 210, 161, 133, 233, 228, 111, 124, 107, 96, 134, 123, 148, 88, 238, 193,
        50, 216, 187, 42, 131, 51, 28, 52, 55, 150, 31, 49, 95, 63, 245, 58, 212, 205, 26, 223, 32, 124, 233, 20, 148,
        107, 33, 162, 47, 107, 221, 238, 221, 200, 89, 199, 52, 164, 114, 177, 254, 146, 60, 118, 1, 78, 73, 231, 138,
        136, 201, 242, 26, 100, 57, 237, 135, 181, 44, 193, 143, 191, 155, 93, 66, 142, 69, 203, 57, 22, 147, 120, 161,
        117, 167, 54, 16, 200, 6, 27, 160, 187, 15, 197, 138, 201, 114, 52, 202
      };

      var inlinePem = @"
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1I++ulXUpZUopjSe7M74
PJpj0D9JbbpV3MChYvqnu1m9+Rnd5fr1FUg7xQu+EI0XN+YIi9CbZl4tGtxjela0
0MidM2dd1BI/5W2Zl4DHnPPmvfZoybBquK6dwkkTe5AhCCZegYD4TsNhKWGqea8D
fSiCAvTeG0uiXbQGPD6lWei3IoVcOQ0cuz3LheCl440Bbmg2BVMUrZO81r6yH1Nz
0ypYnBfx26Mo7379ngHc3yjxi8vjDF/is4wqOgWj34R3gbbf9EZ5OWS+DpItPpFZ
Ykh82DrNHNCPSyvD0XvmcPhJ6O7yrloAPSiTUP9+u7w1zBpg50Srcp+afUcGODYm
KQIDAQAB
-----END PUBLIC KEY-----
      ";

      var pemr = new PemReader(new StringReader(inlinePem.Trim()));
      var pem = pemr.ReadObject();

      var keyParams = (RsaKeyParameters) (AsymmetricKeyParameter) pem;
      var sig = SignerUtilities.GetSigner("SHA-256withRSA");
      sig.Init(false, keyParams);
      var infoBytes = Encoding.ASCII.GetBytes("Test123");
      sig.BlockUpdate(infoBytes, 0, infoBytes.Length);

      Console.WriteLine($"{sig.VerifySignature(signature)}");
    }
  }
}

我只是随机生成了这两个关键文件:

-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEA1I++ulXUpZUopjSe7M74PJpj0D9JbbpV3MChYvqnu1m9+Rnd
5fr1FUg7xQu+EI0XN+YIi9CbZl4tGtxjela00MidM2dd1BI/5W2Zl4DHnPPmvfZo
ybBquK6dwkkTe5AhCCZegYD4TsNhKWGqea8DfSiCAvTeG0uiXbQGPD6lWei3IoVc
OQ0cuz3LheCl440Bbmg2BVMUrZO81r6yH1Nz0ypYnBfx26Mo7379ngHc3yjxi8vj
DF/is4wqOgWj34R3gbbf9EZ5OWS+DpItPpFZYkh82DrNHNCPSyvD0XvmcPhJ6O7y
rloAPSiTUP9+u7w1zBpg50Srcp+afUcGODYmKQIDAQABAoIBAChRh7zycN5jl41H
J+oFLCLaqhojFvuAP68avsH2h4BK+nTYijWIT5qU0/mBS7D6AjBxKqfSjtdw/587
tIbNEYkUtHS+o5aJS6NqEZsiKzrDLL5VkfTHyMZ1IKlskQx7/zf7hyuLWg4ekzx1
MQ/ZuZCw8VA8QDDvPMIHVrNwso6F8/vc/K3tqygeFBh+rfAbkzp2zvK4Tr+reJTT
hmsg68wBzTNAzmeHK8FsMB2NZvwW/zq5ZgEIkZVkJZl7XbYGj+ggVSn2h0J8KleK
H+60nx39wk/KnscsHo9lPpv/7RoYb7OGEVR8W0fY5+QvALTZ8U9HZftm9TfhUd/0
Is5CIT0CgYEA/kaqLKK2hYlEdP2f9N6w/qiF2Gmxu6N1Tk+gvbz1ChukPHW42xUz
iG45So6iGDWNzjVf9IxAP2n0Zltar4tMlyC767jk5Xs7kONZMwqge5a52NYLRRvt
xoklLgXCjurriq+hw6tNAuvVjs/ScOHOQyC4emVDqJ5Z9766zqrpkCsCgYEA1gCt
pGAwt5KoDOXlk3311BDS6XLev536GW25CmKrs9sJH2cOWSRFA0fWcPr0gVotM9F5
+2ymmJmlYLLDRYWTYCX+vL8aysTTDqezpOhJ9VIzgeTh3FwD17LFE5j4W0AqE5jR
2eMItfobMYqHF4iHp+OmfhocLpLQcTC4BlMvZPsCgYBLXOZTFGbEbUq84e7mxJnw
4EHLQohK9Mdvzmn10mtN86NZyAph5IbBiOmyD1Q7mKPO2kL2WBsysFSfgbP/E2o/
4JPR6Zrt6PhemQN2/U9TUfkDK21rrjtq/HroiQyBD1+AW022kK7ijsNc8HuOuV5I
xwnmPN0wvL4tj3oOhtlywQKBgAsXq+h6R+wsAOPyQq0beVONr7EEEEG0aZNJ2a6N
IMNI1jc3e0nplF4wKhBfIa9WwkMOV5lNr3D3fdf+TBrdap8wOP0FltjtzNbUoH4q
wDKkGSFhgMeQSW6zyH1Uj4MDV2r+n9oAZ6IvHZu6x3fTztxH84hTyCQt3foQAWnq
g+ljAoGBAMza/hD+Hsz7uNtVvvqki6a6FMk7cSZTEtZvBvqrywIEEZEnbsuHk5tD
towaZbQQirZp45xsEJZDO/8O5Q0+WEs/0ZG1CPBgIwNEBUt/deid6s1HFFoESp0/
DfekILO1scieEpccfz8aIlgq/CoRFfXQ5m0VetfP6H6Wau1Hfx5A
-----END RSA PRIVATE KEY-----

和:

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1I++ulXUpZUopjSe7M74
PJpj0D9JbbpV3MChYvqnu1m9+Rnd5fr1FUg7xQu+EI0XN+YIi9CbZl4tGtxjela0
0MidM2dd1BI/5W2Zl4DHnPPmvfZoybBquK6dwkkTe5AhCCZegYD4TsNhKWGqea8D
fSiCAvTeG0uiXbQGPD6lWei3IoVcOQ0cuz3LheCl440Bbmg2BVMUrZO81r6yH1Nz
0ypYnBfx26Mo7379ngHc3yjxi8vjDF/is4wqOgWj34R3gbbf9EZ5OWS+DpItPpFZ
Ykh82DrNHNCPSyvD0XvmcPhJ6O7yrloAPSiTUP9+u7w1zBpg50Srcp+afUcGODYm
KQIDAQAB
-----END PUBLIC KEY-----

...它工作正常:

$ node test
[193,185,118,187,54,28,71,173,185,255,213,61,254,51,86,168,224,11,113,23,81,123,89,31,89,183,142,194,7,250,194,165,230,254,74,61,15,12,137,246,151,61,83,107,112,178,98,183,234,247,56,11,246,179,183,74,27,190,17,99,161,31,209,178,81,41,56,214,184,165,232,20,125,155,25,102,104,193,1,101,143,209,192,145,47,215,190,95,196,164,69,203,206,69,142,18,196,155,221,8,31,179,5,165,143,29,34,148,218,177,94,31,174,218,153,52,85,156,67,2,157,29,111,95,231,249,212,39,123,229,75,2,18,238,44,94,181,181,98,156,150,44,219,208,161,18,250,117,91,146,133,233,210,161,133,233,228,111,124,107,96,134,123,148,88,238,193,50,216,187,42,131,51,28,52,55,150,31,49,95,63,245,58,212,205,26,223,32,124,233,20,148,107,33,162,47,107,221,238,221,200,89,199,52,164,114,177,254,146,60,118,1,78,73,231,138,136,201,242,26,100,57,237,135,181,44,193,143,191,155,93,66,142,69,203,57,22,147,120,161,117,167,54,16,200,6,27,160,187,15,197,138,201,114,52,202]
Did sign? true
$ dotnet run
True

所以我的猜测?

您的公钥有问题,或者您传递给双方函数的 json 输入由于某种原因并不完全相同。

据我所知,您的签名代码没有任何问题。

于 2017-09-19T05:12:40.347 回答