Skip to content

Commit a6c051e

Browse files
committed
Long messages support
1 parent 22ffb51 commit a6c051e

File tree

3 files changed

+67
-71
lines changed

3 files changed

+67
-71
lines changed

src/libs/jsbn.js

+24-13
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@
3131
* and disclaimer.
3232
*/
3333

34+
/*
35+
* Added Node.js Buffers support
36+
* 2014 rzcoder
37+
*/
38+
3439
var crypt = require('crypto');
3540

3641
// Bits per digit
@@ -176,19 +181,25 @@ function nbv(i) {
176181
// (protected) set from string and radix
177182
function bnpFromString(data, radix, unsigned) {
178183
var k;
179-
if (radix == 16) k = 4;
180-
else if (radix == 8) k = 3;
181-
else if (radix == 256) k = 8; // byte array
182-
else if (radix == 2) k = 1;
183-
else if (radix == 32) k = 5;
184-
else if (radix == 4) k = 2;
185-
else {
186-
this.fromRadix(data, radix);
187-
return;
184+
switch(radix) {
185+
case 2: k=1; break;
186+
case 4: k=2; break;
187+
case 8: k=3; break;
188+
case 16: k=4; break;
189+
case 32: k=5; break;
190+
case 256: k=8; break;
191+
default:
192+
this.fromRadix(data, radix);
193+
return;
188194
}
195+
189196
this.t = 0;
190197
this.s = 0;
191-
var i = data.length, mi = false, sh = 0;
198+
199+
var i = data.length;
200+
var mi = false;
201+
var sh = 0;
202+
192203
while (--i >= 0) {
193204
var x = (k == 8) ? data[i] & 0xff : intAt(data, i);
194205
if (x < 0) {
@@ -207,16 +218,16 @@ function bnpFromString(data, radix, unsigned) {
207218
sh += k;
208219
if (sh >= this.DB) sh -= this.DB;
209220
}
210-
if (k == 8 && (data[0] & 0x80) != 0) {
221+
if ((!unsigned) && k == 8 && (data[0] & 0x80) != 0) {
211222
this.s = -1;
212223
if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
213224
}
214225
this.clamp();
215226
if (mi) BigInteger.ZERO.subTo(this, this);
216227
}
217228

218-
function bnpFromByteArray(a) {
219-
this.fromString(a, 256)
229+
function bnpFromByteArray(a, unsigned) {
230+
this.fromString(a, 256, unsigned)
220231
}
221232

222233
function bnpFromBuffer(a) {

src/libs/rsa.js

+25-45
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838

3939
var crypt = require('crypto');
4040
var BigInteger = require("./jsbn.js");
41-
var utils = require('../utils.js')
41+
var utils = require('../utils.js');
4242

4343
exports.BigInteger = BigInteger;
4444
module.exports.Key = (function() {
@@ -129,6 +129,8 @@ module.exports.Key = (function() {
129129
this.dmp1 = new BigInteger(DP);
130130
this.dmq1 = new BigInteger(DQ);
131131
this.coeff = new BigInteger(C);
132+
} else {
133+
// TODO: re-calculate any missing CRT params
132134
}
133135
this.$$recalculateCache();
134136
} else
@@ -201,34 +203,28 @@ module.exports.Key = (function() {
201203
}
202204
}
203205

204-
this.debug = {}
205-
this.debug.s = {}
206-
this.debug.s.b = [];
207-
this.debug.s.m = [];
208-
this.debug.s.c = [];
209-
this.debug.s.resbuf = [];
210206
for(var i in buffers) {
211207
var buf = buffers[i];
212-
this.debug.s.b[i] = buf;
213208

214209
var m = this.$$pkcs1pad2(buf, this.encryptedDataLength);
215-
this.debug.s.m[i] = m;
216210

217211
if (m === null) {
218212
return null;
219213
}
220214

221215
var c = this.$doPublic(m);
222-
this.debug.s.c[i] = c;
216+
223217
if (c === null) {
224218
return null;
225219
}
226220

227-
this.debug.s.resbuf[i] = c.toBuffer(true)
228-
while (this.debug.s.resbuf[i].length < this.encryptedDataLength)
229-
this.debug.s.resbuf[i] = Buffer.concat(new Buffer([0]), this.debug.s.resbuf[i]);
221+
var encryptedBuffer = c.toBuffer(true);
222+
223+
while (encryptedBuffer.length < this.encryptedDataLength) {
224+
encryptedBuffer = Buffer.concat([new Buffer([0]), encryptedBuffer]);
225+
}
230226

231-
results.push( this.debug.s.resbuf[i]);
227+
results.push(encryptedBuffer);
232228
}
233229

234230
return Buffer.concat(results);
@@ -240,47 +236,31 @@ module.exports.Key = (function() {
240236
* @returns {Buffer}
241237
*/
242238
RSAKey.prototype.decrypt = function (buffer) {
243-
// if (buffer.length % this.encryptedDataLength > 0)
244-
// throw Error('Incorrect data or key');
239+
if (buffer.length % this.encryptedDataLength > 0)
240+
throw Error('Incorrect data or key');
245241

246242
var result = [];
247243

248-
var s = '';
249244
var offset = 0;
250245
var length = 0;
251246

252-
this.debug.o = {}
253-
this.debug.o.b = [];
254-
this.debug.o.m = [];
255-
this.debug.o.c = [];
256-
this.debug.o.resbuf = [];
257-
for (var i = 0; ; i++) {
258-
offset = length;
259-
length = offset + this.encryptedDataLength// + (buffer[offset] === 0 ? 1 : 0);
260-
261-
this.debug.o.resbuf[i] = buffer.slice(offset, Math.min(length, buffer.length))
262-
var c = new BigInteger(this.debug.o.resbuf[i]);
263-
this.debug.o.c[i] = c;
247+
var buffersCount = buffer.length / this.encryptedDataLength;
248+
249+
250+
for (var i = 0; i < buffersCount; i++) {
251+
offset = i * this.encryptedDataLength;
252+
length = offset + this.encryptedDataLength;
253+
254+
var c = new BigInteger(buffer.slice(offset, Math.min(length, buffer.length)));
264255
var m = this.$doPrivate(c);
265-
this.debug.o.m[i] = m;
266256
if (m === null) {
267257
return null;
268258
}
269259

270-
this.debug.o.b[i] = this.$$pkcs1unpad2(m, this.encryptedDataLength)
271-
result.push(this.debug.o.b[i]);
272-
273-
if (length >= buffer.length)
274-
break;
260+
result.push(this.$$pkcs1unpad2(m, this.encryptedDataLength));
275261
}
276262

277-
try{
278-
a = Buffer.concat(result);
279-
} catch (e) {
280-
console.log(e)
281-
throw e;
282-
}
283-
return a;
263+
return Buffer.concat(result);
284264
};
285265

286266
Object.defineProperty(RSAKey.prototype, 'encryptedDataLength', {
@@ -299,7 +279,7 @@ module.exports.Key = (function() {
299279
// Bit & byte length
300280
this.cache.keyBitLength = this.n.bitLength();
301281
this.cache.keyByteLength = (this.cache.keyBitLength + 6) >> 3;
302-
}
282+
};
303283

304284
/**
305285
* PKCS#1 (type 2, random) pad input buffer to n bytes, and return a bigint
@@ -328,7 +308,7 @@ module.exports.Key = (function() {
328308
ba.unshift(0);
329309

330310
return new BigInteger(ba);
331-
}
311+
};
332312

333313
/**
334314
* Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
@@ -360,7 +340,7 @@ module.exports.Key = (function() {
360340
res[c++] = b[i] & 255;
361341
}
362342
return res;
363-
}
343+
};
364344

365345
return RSAKey;
366346
})();

test/tests.js

+18-13
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
1+
/**
2+
* TODO: test for compatibility with other rsa libraries
3+
*/
4+
15
var assert = require('chai').assert;
26
var _ = require('lodash');
37
var NodeRSA = (require('../src/NodeRSA'));
48

9+
510
for(var i=0;i<100;i++)
611
describe('NodeRSA', function(){
712
var nodeRSA = null;
@@ -60,31 +65,31 @@ describe('NodeRSA', function(){
6065
'KY4kQIIx8JEBsAYzgyP2iy0CAwEAAQ==\n'+
6166
'-----END PUBLIC KEY-----';
6267

63-
false && it('.loadFromPrivatePEM() should load private key from PEM string', function(){
68+
it('.loadFromPrivatePEM() should load private key from PEM string', function(){
6469
privateNodeRSA = new NodeRSA(privateKeyPEM);
6570
assert.instanceOf(privateNodeRSA.keyPair, Object);
6671
assert(privateNodeRSA.isPrivate());
6772
assert(privateNodeRSA.isPublic());
6873
assert(!privateNodeRSA.isPublic(true));
6974
});
7075

71-
false && it('.loadFromPublicPEM() should load public key from PEM string', function(){
76+
it('.loadFromPublicPEM() should load public key from PEM string', function(){
7277
publicNodeRSA = new NodeRSA(publicKeyPEM);
7378
assert.instanceOf(privateNodeRSA.keyPair, Object);
7479
assert(publicNodeRSA.isPublic());
7580
assert(publicNodeRSA.isPublic(true));
7681
assert(!publicNodeRSA.isPrivate());
7782
});
7883

79-
false && it('.toPrivatePEM() should return private PEM string', function(){
84+
it('.toPrivatePEM() should return private PEM string', function(){
8085
assert.equal(privateNodeRSA.toPrivatePEM(), privateKeyPEM);
8186
});
8287

83-
false && it('.toPublicPEM() from public key should return public PEM string', function(){
88+
it('.toPublicPEM() from public key should return public PEM string', function(){
8489
assert.equal(publicNodeRSA.toPublicPEM(), publicKeyPEM);
8590
});
8691

87-
false && it('.toPublicPEM() from private key should return public PEM string', function(){
92+
it('.toPublicPEM() from private key should return public PEM string', function(){
8893
assert.equal(privateNodeRSA.toPublicPEM(), publicKeyPEM);
8994
});
9095
});
@@ -105,12 +110,12 @@ describe('NodeRSA', function(){
105110
var decryptedJSON = null;
106111

107112
describe('Encrypting', function(){
108-
false && it('.encrypt() should return Buffer object', function(){
113+
it('.encrypt() should return Buffer object', function(){
109114
encryptedBuffer = nodeRSA.encrypt(dataForEncrypt, null, 'buffer');
110115
assert(Buffer.isBuffer(encryptedBuffer));
111116
});
112117

113-
false && it('.encrypt() should return base64 encrypted string', function(){
118+
it('.encrypt() should return base64 encrypted string', function(){
114119
encrypted = nodeRSA.encrypt(dataForEncrypt);
115120
assert.isString(encrypted);
116121
assert.match(encrypted, /^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$/);
@@ -121,19 +126,19 @@ describe('NodeRSA', function(){
121126
assert(Buffer.isBuffer(encryptedLong));
122127
});
123128

124-
false && it('.encrypt() for js object. Should return Buffer object', function(){
129+
it('.encrypt() for js object. Should return Buffer object', function(){
125130
encryptedJSON = nodeRSA.encrypt(JSONForEncrypt, null, 'buffer');
126131
assert(Buffer.isBuffer(encryptedJSON));
127132
});
128133
});
129134

130135
describe('Decrypting', function(){
131-
false && it('.decrypt() should return decrypted Buffer', function(){
136+
it('.decrypt() should return decrypted Buffer', function(){
132137
decrypted = nodeRSA.decrypt(encryptedBuffer, 'buffer');
133138
assert(Buffer.isBuffer(decrypted));
134139
});
135140

136-
false && it('.decrypt() should return decrypted string', function(){
141+
it('.decrypt() should return decrypted string', function(){
137142
decrypted = nodeRSA.decrypt(new Buffer(encrypted, 'base64'));
138143
assert.isString(decrypted);
139144
});
@@ -143,20 +148,20 @@ describe('NodeRSA', function(){
143148
assert.isString(decryptedLong);
144149
});
145150

146-
false && it('.decrypt() for js object. Should return decrypted js object', function(){
151+
it('.decrypt() for js object. Should return decrypted js object', function(){
147152
decryptedJSON = nodeRSA.decrypt(encryptedJSON, 'json');
148153
assert.isObject(decryptedJSON);
149154
});
150155

151-
false && it('source and decrypted should be the same', function(){
156+
it('source and decrypted should be the same', function(){
152157
assert.equal(decrypted, dataForEncrypt);
153158
});
154159

155160
it('long source and decrypted should be the same', function(){
156161
assert.equal(decryptedLong, longDataForEncrypt);
157162
});
158163

159-
false && it('source JSON and decrypted JSON should be the same', function(){
164+
it('source JSON and decrypted JSON should be the same', function(){
160165
assert(_.isEqual(decryptedJSON, JSONForEncrypt));
161166
});
162167
});

0 commit comments

Comments
 (0)