Skip to content
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

fixes #18

Closed
wants to merge 17 commits into from
Prev Previous commit
Next Next commit
signing schemes support
  • Loading branch information
rzcoder committed Nov 20, 2014
commit 62b9a860fc818b6e7898e4473ea0125891479527
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ Based on jsbn library from Tom Wu http://www-cs-students.stanford.edu/~tjw/jsbn/
* Pure JavaScript
* No needed OpenSSL
* Generating keys
* Supports long messages for encrypt/decrypt
* Signing and verifying
* Supports long messages for encrypt/decrypt (PKCS1 and PKCS1_OAEP schemes)
* Signing and verifying (PKCS1 and PSS schemes)


## Example

Expand Down
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
"encryption",
"decryption",
"sign",
"verify"
"verify",
"pkcs1",
"oaep",
"pss"
],
"author": "rzcoder",
"license": "BSD",
Expand Down
44 changes: 22 additions & 22 deletions src/NodeRSA.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ var schemes = require('./schemes/schemes.js');

var PUBLIC_RSA_OID = '1.2.840.113549.1.1.1';

module.exports = (function() {
module.exports = (function () {
var SUPPORTED_HASH_ALGORITHMS = {
node: ['md4', 'md5', 'ripemd160', 'sha', 'sha1', 'sha224', 'sha256', 'sha384', 'sha512'],
browser: ['md5', 'ripemd160', 'sha1', 'sha256', 'sha512']
Expand All @@ -32,7 +32,7 @@ module.exports = (function() {
* @constructor
*/
function NodeRSA(key, options) {
if (! this instanceof NodeRSA) {
if (!this instanceof NodeRSA) {
return new NodeRSA(key, options);
}

Expand Down Expand Up @@ -75,9 +75,9 @@ module.exports = (function() {
this.$options.signingScheme = DEFAULT_SIGNING_SCHEME;
} else {
this.$options.signingSchemeOptions = {
hash: options.signingScheme[1]
hash: signingScheme[1]
};
this.$options.signingScheme = options.signingScheme[0];
this.$options.signingScheme = signingScheme[0];
}

if (!schemes.isSignature(this.$options.signingScheme)) {
Expand Down Expand Up @@ -106,7 +106,7 @@ module.exports = (function() {
* @param exp {int} public exponent. Default 65537.
* @returns {NodeRSA}
*/
NodeRSA.prototype.generateKeyPair = function(bits, exp) {
NodeRSA.prototype.generateKeyPair = function (bits, exp) {
bits = bits || 2048;
exp = exp || 65537;

Expand All @@ -123,7 +123,7 @@ module.exports = (function() {
* Load key from PEM string
* @param pem {string}
*/
NodeRSA.prototype.loadFromPEM = function(pem) {
NodeRSA.prototype.loadFromPEM = function (pem) {
if (Buffer.isBuffer(pem)) {
pem = pem.toString('utf8');
}
Expand All @@ -143,10 +143,10 @@ module.exports = (function() {
*
* @param privatePEM {string}
*/
NodeRSA.prototype.$loadFromPrivatePEM = function(privatePEM, encoding) {
NodeRSA.prototype.$loadFromPrivatePEM = function (privatePEM, encoding) {
var pem = privatePEM
.replace('-----BEGIN RSA PRIVATE KEY-----','')
.replace('-----END RSA PRIVATE KEY-----','')
.replace('-----BEGIN RSA PRIVATE KEY-----', '')
.replace('-----END RSA PRIVATE KEY-----', '')
.replace(/\s+|\n\r|\n|\r$/gm, '');
var reader = new ber.Reader(new Buffer(pem, 'base64'));

Expand All @@ -170,10 +170,10 @@ module.exports = (function() {
*
* @param publicPEM {string}
*/
NodeRSA.prototype.$loadFromPublicPEM = function(publicPEM, encoding) {
NodeRSA.prototype.$loadFromPublicPEM = function (publicPEM, encoding) {
var pem = publicPEM
.replace('-----BEGIN PUBLIC KEY-----','')
.replace('-----END PUBLIC KEY-----','')
.replace('-----BEGIN PUBLIC KEY-----', '')
.replace('-----END PUBLIC KEY-----', '')
.replace(/\s+|\n\r|\n|\r$/gm, '');
var reader = new ber.Reader(new Buffer(pem, 'base64'));

Expand All @@ -195,22 +195,22 @@ module.exports = (function() {
/**
* Check if key pair contains private key
*/
NodeRSA.prototype.isPrivate = function() {
NodeRSA.prototype.isPrivate = function () {
return this.keyPair.n && this.keyPair.e && this.keyPair.d || false;
};

/**
* Check if key pair contains public key
* @param strict {boolean} - public key only, return false if have private exponent
*/
NodeRSA.prototype.isPublic = function(strict) {
NodeRSA.prototype.isPublic = function (strict) {
return this.keyPair.n && this.keyPair.e && !(strict && this.keyPair.d) || false;
};

/**
* Check if key pair doesn't contains any data
*/
NodeRSA.prototype.isEmpty = function(strict) {
NodeRSA.prototype.isEmpty = function (strict) {
return !(this.keyPair.n || this.keyPair.e || this.keyPair.d);
};

Expand All @@ -222,7 +222,7 @@ module.exports = (function() {
* @param source_encoding {string} - optional. Encoding for given string. Default utf8.
* @returns {string|Buffer}
*/
NodeRSA.prototype.encrypt = function(buffer, encoding, source_encoding) {
NodeRSA.prototype.encrypt = function (buffer, encoding, source_encoding) {
var res = this.keyPair.encrypt(this.$getDataForEcrypt(buffer, source_encoding));

if (encoding == 'buffer' || !encoding) {
Expand All @@ -239,7 +239,7 @@ module.exports = (function() {
* @param encoding - encoding for result string, can also take 'json' or 'buffer' for the automatic conversion of this type
* @returns {Buffer|object|string}
*/
NodeRSA.prototype.decrypt = function(buffer, encoding) {
NodeRSA.prototype.decrypt = function (buffer, encoding) {
buffer = _.isString(buffer) ? new Buffer(buffer, 'base64') : buffer;
return this.$getDecryptedData(this.keyPair.decrypt(buffer), encoding);
};
Expand Down Expand Up @@ -305,7 +305,7 @@ module.exports = (function() {
* @param encoding {string} - optional. Encoding for given string. Default utf8.
* @returns {Buffer}
*/
NodeRSA.prototype.$getDataForEcrypt = function(buffer, encoding) {
NodeRSA.prototype.$getDataForEcrypt = function (buffer, encoding) {
if (_.isString(buffer) || _.isNumber(buffer)) {
return new Buffer('' + buffer, encoding || 'utf8');
} else if (Buffer.isBuffer(buffer)) {
Expand All @@ -323,7 +323,7 @@ module.exports = (function() {
* @param encoding - optional. Encoding for result output. May be 'buffer', 'json' or any of Node.js Buffer supported encoding.
* @returns {*}
*/
NodeRSA.prototype.$getDecryptedData = function(buffer, encoding) {
NodeRSA.prototype.$getDecryptedData = function (buffer, encoding) {
encoding = encoding || 'buffer';

if (encoding == 'buffer') {
Expand All @@ -339,7 +339,7 @@ module.exports = (function() {
* private
* Recalculating properties
*/
NodeRSA.prototype.$recalculateCache = function() {
NodeRSA.prototype.$recalculateCache = function () {
this.$cache.privatePEM = this.$makePrivatePEM();
this.$cache.publicPEM = this.$makePublicPEM();
};
Expand All @@ -348,7 +348,7 @@ module.exports = (function() {
* private
* @returns {string} private PEM string
*/
NodeRSA.prototype.$makePrivatePEM = function() {
NodeRSA.prototype.$makePrivatePEM = function () {
if (!this.isPrivate()) {
return null;
}
Expand Down Expand Up @@ -385,7 +385,7 @@ module.exports = (function() {
* private
* @returns {string} public PEM string
*/
NodeRSA.prototype.$makePublicPEM = function() {
NodeRSA.prototype.$makePublicPEM = function () {
if (!this.isPublic()) {
return null;
}
Expand Down
22 changes: 20 additions & 2 deletions src/libs/jsbn.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
*/

var crypt = require('crypto');
var _ = require('lodash');

// Bits per digit
var dbits;
Expand Down Expand Up @@ -815,9 +816,26 @@ function bnToByteArray() {
* @param trim {boolean} slice buffer if first element == 0
* @returns {Buffer}
*/
function bnToBuffer(trim) {
function bnToBuffer(trimOrSize) {
var res = new Buffer(this.toByteArray());
return trim && res[0] === 0 ? res.slice(1) : res;
if (trimOrSize === true && res[0] === 0) {
res = res.slice(1);
} else if (_.isNumber(trimOrSize)) {
if (res.length > trimOrSize) {
for (var i = 0; i < res.length - trimOrSize; i++) {
if (res[i] !== 0) {
return null;
}
}
return res.slice(res.length - trimOrSize);
} else if (res.length < trimOrSize) {
var padded = new Buffer(trimOrSize);
padded.fill(0, 0, trimOrSize - res.length);
res.copy(padded, trimOrSize - res.length);
return padded;
}
}
return res;
}

function bnEquals(a) {
Expand Down
65 changes: 65 additions & 0 deletions src/schemes/oaep.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* PKCS_OAEP signature scheme
*/

var BigInteger = require('../libs/jsbn');
var crypt = require('crypto');

module.exports = {
isEncryption: true,
isSignature: false
};

module.exports.digestLength = {
md4: 16,
md5: 16,
ripemd160: 20,
rmd160: 20,
sha: 20,
sha1: 20,
sha224: 28,
sha256: 32,
sha384: 48,
sha512: 64
};

/*
* OAEP Mask Generation Function 1
* Generates a buffer full of pseudorandom bytes given seed and maskLength.
* Giving the same seed, maskLength, and hashFunction will result in the same exact byte values in the buffer.
*
* https://tools.ietf.org/html/rfc3447#appendix-B.2.1
*
* Parameters:
* seed [Buffer] The pseudo random seed for this function
* maskLength [int] The length of the output
* hashFunction [String] The hashing function to use. Will accept any valid crypto hash. Default "sha1"
* Supports "sha1" and "sha256".
* To add another algorythm the algorythem must be accepted by crypto.createHash, and then the length of the output of the hash function (the digest) must be added to the digestLength object below.
* Most RSA implementations will be expecting sha1
*/
module.exports.eme_oaep_mgf1 = function(seed, maskLength, hashFunction){
hashFunction = hashFunction || "sha1";
var hLen = module.exports.digestLength[hashFunction];
var count = Math.ceil(maskLength / hLen);
var T = new Buffer(hLen * count);
var c = new Buffer(4);
for(var i = 0; i < count; ++i) {
var hash = crypt.createHash(hashFunction);
hash.write(seed);
c.writeUInt32BE(i, 0);
hash.end(c);
hash.read().copy(T, i*hLen);
}
return T.slice(0, maskLength);
};

module.exports.makeScheme = function (key, options) {
function Scheme(key, options) {
this.key = key;
this.options = options;
}


return new Scheme(key, options);
};
Loading