-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathdigitalSignature.js
150 lines (131 loc) · 3.83 KB
/
digitalSignature.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/**
* Digital Signature for Candy
* uses SHA256withRSA algorithm
* required forge.min.js
* https://github.com/digitalbazaar/forge
*/
'use strict';
//unify browser and node
if(typeof _this === 'undefined') {
var _this = this;
}
/**
* Crypto signs methods
* @param {string} dataToSign Optional: data for sign
* @return {DigitalSignature}
* @constructor
*/
function DigitalSignature(dataToSign) { //data in string format
if(_this.window === undefined) {
this.forge = require('node-forge');
} else {
this.forge = forge;
}
/**
* RSA keys for sign
*/
this.keysPair = {};
/**
* Sign
*/
this.sign = '';
/**
* Data format as presented in 'block data'
*/
this.signedData = {
data: dataToSign, //incoming data
sign: '', //sign in HEX format
pubkey: '' //Public key in pem PKCS#1
};
/**
* Generate pair of keys for signing
* @param {number} len Length of the key
*/
this.generate = (len = 2048) => {
let rsa = this.forge.pki.rsa;
let keypair = this.forge.rsa.generateKeyPair({len});
keypair = {
public: repairKey(fix(this.forge.pki.publicKeyToRSAPublicKeyPem(keypair.publicKey, 72))),
private: repairKey(fix(this.forge.pki.privateKeyToPem(keypair.privateKey, 72)))
};
this.keysPair = keypair;
console.log('Info: Keypair generated');
return keypair;
};
/**
* PEM key fixing
* @param str
* @return {string}
*/
function fix(str) {
return str.replace(/\r/g, '') + '\n'
}
/**
* Repair bad generated key
* @param key
* @return {string}
*/
function repairKey(key) {
if(key[key.length - 1] !== "\n") {
key += "\n";
}
return key.replace(new RegExp("\n\n", 'g'), "\n");
}
/**
* Signs data
* @param {data} data for signing
* @param {key} key
*/
/**
* Sign data
* @param {string} data Data
* @param {string} key Private key
* @return {{data: {string}, sign:{string}}} Data - signable data, sign - Sign
*/
this.signData = (data = dataToSign, key = this.keysPair.private) => {
if(!data) {
console.log('No data to sign');
return '';
}
let md = this.forge.md.sha256.create();
md.update(data, 'utf8');
let privateKey = this.forge.pki.privateKeyFromPem(key);
this.sign = privateKey.sign(md);
console.log('Info: Data signed');
return {data: data, sign: this.forge.util.bytesToHex(this.sign)};
};
/**
* Signs data
* @param {string} data Signed data for verify
* @param {string} sign Sign
* @param {string} key Public key
*/
this.verifyData = (data = this.signedData, sign = this.signedData.sign, key = this.signedData.pubkey) => {
if(typeof data === 'object') {
sign = data.sign;
data = data.data;
}
try {
let publicKey = this.forge.pki.publicKeyFromPem(repairKey(fix(key)));
let md = this.forge.md.sha256.create();
md.update(data, 'utf8');
return publicKey.verify(md.digest().bytes(), this.forge.util.hexToBytes(sign)); //verifying only in bytes format
} catch (e) {
console.log(e);
return false;
}
};
if(dataToSign !== undefined) {
this.keysPair = this.generate();
this.signedData.pubkey = this.keysPair.public;
this.signedData.sign = this.signData().sign;
if(this.verifyData() === false) {
console.log('Sign self-validation error! Invalid key or sign checking');
}
}
return this;
}
//unify browser and node
if(this.window === undefined) {
module.exports = DigitalSignature;
}