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

added support for RSA signatures. #16

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
124 changes: 124 additions & 0 deletions bin/jsencrypt.js
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,38 @@ function pkcs1pad2(s,n) {
return new BigInteger(ba);
}

// PKCS#1 (type 1) pad input string s to n bytes, and return a bigint
function pkcs1pad1(s,n) {
if(n < s.length + 11) { // TODO: fix for utf-8
console.error("Message too long for RSA");
return null;
}
var ba = new Array();
var i = s.length - 1;
while(i >= 0 && n > 0) {
var c = s.charCodeAt(i--);
if(c < 128) { // encode using utf-8
ba[--n] = c;
}
else if((c > 127) && (c < 2048)) {
ba[--n] = (c & 63) | 128;
ba[--n] = (c >> 6) | 192;
}
else {
ba[--n] = (c & 63) | 128;
ba[--n] = ((c >> 6) & 63) | 128;
ba[--n] = (c >> 12) | 224;
}
}
ba[--n] = 0;
while(n > 2) {
ba[--n] = 0xFF;
}
ba[--n] = 1;
ba[--n] = 0;
return new BigInteger(ba);
}

// "empty" RSA key constructor
function RSAKey() {
this.n = null;
Expand Down Expand Up @@ -1469,6 +1501,35 @@ function pkcs1unpad2(d,n) {
return ret;
}


// Undo PKCS#1 (type 1) padding and, if valid, return the plaintext
function pkcs1unpad2(d,n) {
var b = d.toByteArray();
var i = 0;
while(i < b.length && b[i] == 0) ++i;
if(b.length-i != n-1 || b[i] != 1)
return null;
++i;
while(b[i] != 0)
if(++i >= b.length) return null;
var ret = "";
while(++i < b.length) {
var c = b[i] & 255;
if(c < 128) { // utf-8 decode
ret += String.fromCharCode(c);
}
else if((c > 191) && (c < 224)) {
ret += String.fromCharCode(((c & 31) << 6) | (b[i+1] & 63));
++i;
}
else {
ret += String.fromCharCode(((c & 15) << 12) | ((b[i+1] & 63) << 6) | (b[i+2] & 63));
i += 2;
}
}
return ret;
}

// Set the private key fields N, e, and d from hex strings
function RSASetPrivate(N,E,D) {
if(N != null && E != null && N.length > 0 && E.length > 0) {
Expand Down Expand Up @@ -1569,6 +1630,39 @@ RSAKey.prototype.setPrivateEx = RSASetPrivateEx;
RSAKey.prototype.generate = RSAGenerate;
RSAKey.prototype.decrypt = RSADecrypt;
//RSAKey.prototype.b64_decrypt = RSAB64Decrypt;


/* RSA signature */

// Return the PKCS#1 RSA encryption of "text" as an even-length hex string
function RSASign(text, digestMethod) {
var digest = digestMethod(text);
var m = pkcs1pad1(digest.toString(),(this.n.bitLength()+7)>>3);
console.log("RSASign: encryption block :- " + m.toString());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No console.log please.

if(m == null) return null;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Standards: Need to expand out the if statement with brackets.

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

var c = m.modPow(this.d, this.n);
if(c == null) return null;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Expand out the if statement with brackets.

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

var h = c.toString(16);
console.log("RSASign: signature (in hex) :- " + h.toString());
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should not have console.log.

if((h.length & 1) == 0) return h; else return "0" + h;
}

function RSAVerify(text, signature, digestMethod) {
var c = parseBigInt(signature, 16);
var m = c.modPowInt(this.e, this.n);
if (m == null) return null;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Coding standards: You need to expand out the if statement here.

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

var digest = pkcs1unpad1(m, (this.n.bitLength()+7)>>3);
console.log("RSAVerify: message digest :- " + digest);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There should not be any console.log commands. This will fail in browsers that don't support it, such as IE.

return digest == digestMethod(text);
}

RSAKey.prototype.verify = RSAVerify;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just assign the function directly instead of having a separate function? Something like this?

RSAKey.prototype.verify = function(text, signature, digestMethod) {
  var c = parseBigInt(signature, 16);
  var m = c.modPowInt(this.e, this.n);
  if (m == null) return null;
  var digest = pkcs1unpad2(m, (this.n.bitLength()+7)>>3);
  console.log("RSAVerify: message digest :- " + digest);
  return digest == digestMethod(text);
};

Same goes for the other function you created.

RSAKey.prototype.sign = RSASign;

/* RSA signature */



// Copyright (c) 2011 Kevin M Burns Jr.
// All Rights Reserved.
// See "LICENSE" for details.
Expand Down Expand Up @@ -4297,6 +4391,36 @@ JSEncrypt.prototype.getPublicKeyB64 = function() {
return this.getKey().getPublicBaseKeyB64();
};

/* RSA signature */

/**
* Proxy method for RSAKey object's sign.
*
*/
JSEncrypt.prototype.sign = function(text, digestMethod) {
// return the RSA signature of 'string' in 'hex' format.
try {
return this.getKey().sign(text, digestMethod);
} catch(ex) {
return false;
}
}

/**
* Proxy method for RSAKey object's verify.
*
*/
JSEncrypt.prototype.verify = function(text, signature, digestMethod) {
// Return the decrypted 'digest' of the signature.
try {
return this.getKey().verify(text, signature, digestMethod);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spacing is off here.

} catch(ex) {
return false;
}
}

/* RSA signature */

exports.JSEncrypt = JSEncrypt;
})(JSEncryptExports);
var JSEncrypt = JSEncryptExports.JSEncrypt;