如何验证来自 asp.net 核心应用程序 C# 的文件中的 Json 个对象
How to Validate Json objects in a file from asp.net core application C#
问题: nodejs 应用程序创建了一个 json 文件,这是一个许可证,asp.net 核心应用程序需要使用 public键。节点应用程序使用 RSA sha256 用私钥对其进行签名,.net 核心应用程序将使用 public 密钥进行验证。谢谢你。 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 核心端尝试了很多东西但没有成功,给定的 public 键有一些不常见的字符,如 \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 () ;
}
}
}
Public 键的格式如下:
-----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;
};
我猜你的密钥文件有问题?
您的代码工作正常。
下面是在节点中生成签名的例子:
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
所以我猜?
要么是你的 public 键有问题,要么是你传递给函数的 json 输入由于某种原因不完全相同。
据我所知,您的签名代码没有任何问题。
问题: nodejs 应用程序创建了一个 json 文件,这是一个许可证,asp.net 核心应用程序需要使用 public键。节点应用程序使用 RSA sha256 用私钥对其进行签名,.net 核心应用程序将使用 public 密钥进行验证。谢谢你。 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 核心端尝试了很多东西但没有成功,给定的 public 键有一些不常见的字符,如 \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 () ;
}
}
}
Public 键的格式如下:
-----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;
};
我猜你的密钥文件有问题?
您的代码工作正常。
下面是在节点中生成签名的例子:
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
所以我猜?
要么是你的 public 键有问题,要么是你传递给函数的 json 输入由于某种原因不完全相同。
据我所知,您的签名代码没有任何问题。