Skip to content

Long messages support #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 26, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 24 additions & 13 deletions src/libs/jsbn.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
* and disclaimer.
*/

/*
* Added Node.js Buffers support
* 2014 rzcoder
*/

var crypt = require('crypto');

// Bits per digit
Expand Down Expand Up @@ -176,19 +181,25 @@ function nbv(i) {
// (protected) set from string and radix
function bnpFromString(data, radix, unsigned) {
var k;
if (radix == 16) k = 4;
else if (radix == 8) k = 3;
else if (radix == 256) k = 8; // byte array
else if (radix == 2) k = 1;
else if (radix == 32) k = 5;
else if (radix == 4) k = 2;
else {
this.fromRadix(data, radix);
return;
switch(radix) {
case 2: k=1; break;
case 4: k=2; break;
case 8: k=3; break;
case 16: k=4; break;
case 32: k=5; break;
case 256: k=8; break;
default:
this.fromRadix(data, radix);
return;
}

this.t = 0;
this.s = 0;
var i = data.length, mi = false, sh = 0;

var i = data.length;
var mi = false;
var sh = 0;

while (--i >= 0) {
var x = (k == 8) ? data[i] & 0xff : intAt(data, i);
if (x < 0) {
Expand All @@ -207,16 +218,16 @@ function bnpFromString(data, radix, unsigned) {
sh += k;
if (sh >= this.DB) sh -= this.DB;
}
if (k == 8 && (data[0] & 0x80) != 0) {
if ((!unsigned) && k == 8 && (data[0] & 0x80) != 0) {
this.s = -1;
if (sh > 0) this[this.t - 1] |= ((1 << (this.DB - sh)) - 1) << sh;
}
this.clamp();
if (mi) BigInteger.ZERO.subTo(this, this);
}

function bnpFromByteArray(a) {
this.fromString(a, 256)
function bnpFromByteArray(a, unsigned) {
this.fromString(a, 256, unsigned)
}

function bnpFromBuffer(a) {
Expand Down
70 changes: 25 additions & 45 deletions src/libs/rsa.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@

var crypt = require('crypto');
var BigInteger = require("./jsbn.js");
var utils = require('../utils.js')
var utils = require('../utils.js');

exports.BigInteger = BigInteger;
module.exports.Key = (function() {
Expand Down Expand Up @@ -129,6 +129,8 @@ module.exports.Key = (function() {
this.dmp1 = new BigInteger(DP);
this.dmq1 = new BigInteger(DQ);
this.coeff = new BigInteger(C);
} else {
// TODO: re-calculate any missing CRT params
}
this.$$recalculateCache();
} else
Expand Down Expand Up @@ -201,34 +203,28 @@ module.exports.Key = (function() {
}
}

this.debug = {}
this.debug.s = {}
this.debug.s.b = [];
this.debug.s.m = [];
this.debug.s.c = [];
this.debug.s.resbuf = [];
for(var i in buffers) {
var buf = buffers[i];
this.debug.s.b[i] = buf;

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

if (m === null) {
return null;
}

var c = this.$doPublic(m);
this.debug.s.c[i] = c;

if (c === null) {
return null;
}

this.debug.s.resbuf[i] = c.toBuffer(true)
while (this.debug.s.resbuf[i].length < this.encryptedDataLength)
this.debug.s.resbuf[i] = Buffer.concat(new Buffer([0]), this.debug.s.resbuf[i]);
var encryptedBuffer = c.toBuffer(true);

while (encryptedBuffer.length < this.encryptedDataLength) {
encryptedBuffer = Buffer.concat([new Buffer([0]), encryptedBuffer]);
}

results.push( this.debug.s.resbuf[i]);
results.push(encryptedBuffer);
}

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

var result = [];

var s = '';
var offset = 0;
var length = 0;

this.debug.o = {}
this.debug.o.b = [];
this.debug.o.m = [];
this.debug.o.c = [];
this.debug.o.resbuf = [];
for (var i = 0; ; i++) {
offset = length;
length = offset + this.encryptedDataLength// + (buffer[offset] === 0 ? 1 : 0);

this.debug.o.resbuf[i] = buffer.slice(offset, Math.min(length, buffer.length))
var c = new BigInteger(this.debug.o.resbuf[i]);
this.debug.o.c[i] = c;
var buffersCount = buffer.length / this.encryptedDataLength;


for (var i = 0; i < buffersCount; i++) {
offset = i * this.encryptedDataLength;
length = offset + this.encryptedDataLength;

var c = new BigInteger(buffer.slice(offset, Math.min(length, buffer.length)));
var m = this.$doPrivate(c);
this.debug.o.m[i] = m;
if (m === null) {
return null;
}

this.debug.o.b[i] = this.$$pkcs1unpad2(m, this.encryptedDataLength)
result.push(this.debug.o.b[i]);

if (length >= buffer.length)
break;
result.push(this.$$pkcs1unpad2(m, this.encryptedDataLength));
}

try{
a = Buffer.concat(result);
} catch (e) {
console.log(e)
throw e;
}
return a;
return Buffer.concat(result);
};

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

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

return new BigInteger(ba);
}
};

/**
* Undo PKCS#1 (type 2, random) padding and, if valid, return the plaintext
Expand Down Expand Up @@ -360,7 +340,7 @@ module.exports.Key = (function() {
res[c++] = b[i] & 255;
}
return res;
}
};

return RSAKey;
})();
Expand Down
31 changes: 18 additions & 13 deletions test/tests.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
/**
* TODO: test for compatibility with other rsa libraries
*/

var assert = require('chai').assert;
var _ = require('lodash');
var NodeRSA = (require('../src/NodeRSA'));


for(var i=0;i<100;i++)
describe('NodeRSA', function(){
var nodeRSA = null;
Expand Down Expand Up @@ -60,31 +65,31 @@ describe('NodeRSA', function(){
'KY4kQIIx8JEBsAYzgyP2iy0CAwEAAQ==\n'+
'-----END PUBLIC KEY-----';

false && it('.loadFromPrivatePEM() should load private key from PEM string', function(){
it('.loadFromPrivatePEM() should load private key from PEM string', function(){
privateNodeRSA = new NodeRSA(privateKeyPEM);
assert.instanceOf(privateNodeRSA.keyPair, Object);
assert(privateNodeRSA.isPrivate());
assert(privateNodeRSA.isPublic());
assert(!privateNodeRSA.isPublic(true));
});

false && it('.loadFromPublicPEM() should load public key from PEM string', function(){
it('.loadFromPublicPEM() should load public key from PEM string', function(){
publicNodeRSA = new NodeRSA(publicKeyPEM);
assert.instanceOf(privateNodeRSA.keyPair, Object);
assert(publicNodeRSA.isPublic());
assert(publicNodeRSA.isPublic(true));
assert(!publicNodeRSA.isPrivate());
});

false && it('.toPrivatePEM() should return private PEM string', function(){
it('.toPrivatePEM() should return private PEM string', function(){
assert.equal(privateNodeRSA.toPrivatePEM(), privateKeyPEM);
});

false && it('.toPublicPEM() from public key should return public PEM string', function(){
it('.toPublicPEM() from public key should return public PEM string', function(){
assert.equal(publicNodeRSA.toPublicPEM(), publicKeyPEM);
});

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

describe('Encrypting', function(){
false && it('.encrypt() should return Buffer object', function(){
it('.encrypt() should return Buffer object', function(){
encryptedBuffer = nodeRSA.encrypt(dataForEncrypt, null, 'buffer');
assert(Buffer.isBuffer(encryptedBuffer));
});

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

false && it('.encrypt() for js object. Should return Buffer object', function(){
it('.encrypt() for js object. Should return Buffer object', function(){
encryptedJSON = nodeRSA.encrypt(JSONForEncrypt, null, 'buffer');
assert(Buffer.isBuffer(encryptedJSON));
});
});

describe('Decrypting', function(){
false && it('.decrypt() should return decrypted Buffer', function(){
it('.decrypt() should return decrypted Buffer', function(){
decrypted = nodeRSA.decrypt(encryptedBuffer, 'buffer');
assert(Buffer.isBuffer(decrypted));
});

false && it('.decrypt() should return decrypted string', function(){
it('.decrypt() should return decrypted string', function(){
decrypted = nodeRSA.decrypt(new Buffer(encrypted, 'base64'));
assert.isString(decrypted);
});
Expand All @@ -143,20 +148,20 @@ describe('NodeRSA', function(){
assert.isString(decryptedLong);
});

false && it('.decrypt() for js object. Should return decrypted js object', function(){
it('.decrypt() for js object. Should return decrypted js object', function(){
decryptedJSON = nodeRSA.decrypt(encryptedJSON, 'json');
assert.isObject(decryptedJSON);
});

false && it('source and decrypted should be the same', function(){
it('source and decrypted should be the same', function(){
assert.equal(decrypted, dataForEncrypt);
});

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

false && it('source JSON and decrypted JSON should be the same', function(){
it('source JSON and decrypted JSON should be the same', function(){
assert(_.isEqual(decryptedJSON, JSONForEncrypt));
});
});
Expand Down