OP-01-005 Side-channel leak in RSA decryption (High). Add config option for RSA blinding, default true. Update jsbn to 1.3. Remove decrypted packets after Message.decrypt().

This commit is contained in:
Thomas Oberndörfer 2014-03-17 11:54:40 +01:00
parent e1fcc51d0e
commit 9f23c6a891
7 changed files with 56 additions and 12 deletions

View File

@ -35,14 +35,15 @@ module.exports = {
prefer_hash_algorithm: enums.hash.sha256, prefer_hash_algorithm: enums.hash.sha256,
encryption_cipher: enums.symmetric.aes256, encryption_cipher: enums.symmetric.aes256,
compression: enums.compression.zip, compression: enums.compression.zip,
integrity_protect: true,
rsa_blinding: true,
show_version: true, show_version: true,
show_comment: true, show_comment: true,
integrity_protect: true,
keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371"
versionstring: "OpenPGP.js VERSION", versionstring: "OpenPGP.js VERSION",
commentstring: "http://openpgpjs.org", commentstring: "http://openpgpjs.org",
keyserver: "keyserver.linux.it", // "pgp.mit.edu:11371"
node_store: './openpgp.store', node_store: './openpgp.store',
debug: false debug: false

View File

@ -93,12 +93,15 @@ module.exports = {
case 'rsa_encrypt': case 'rsa_encrypt':
var rsa = new publicKey.rsa(); var rsa = new publicKey.rsa();
// 0 and 1 are the public key. // 0 and 1 are the public key.
var n = keyIntegers[0].toBigInteger();
var e = keyIntegers[1].toBigInteger();
// 2 to 5 are the private key.
var d = keyIntegers[2].toBigInteger(); var d = keyIntegers[2].toBigInteger();
p = keyIntegers[3].toBigInteger(); p = keyIntegers[3].toBigInteger();
var q = keyIntegers[4].toBigInteger(); var q = keyIntegers[4].toBigInteger();
var u = keyIntegers[5].toBigInteger(); var u = keyIntegers[5].toBigInteger();
var m = dataIntegers[0].toBigInteger(); var m = dataIntegers[0].toBigInteger();
return rsa.decrypt(m, d, p, q, u); return rsa.decrypt(m, n, e, d, p, q, u);
case 'elgamal': case 'elgamal':
var elgamal = new publicKey.elgamal(); var elgamal = new publicKey.elgamal();
var x = keyIntegers[3].toBigInteger(); var x = keyIntegers[3].toBigInteger();

View File

@ -293,7 +293,7 @@ function bnCompareTo(a) {
if (r != 0) return r; if (r != 0) return r;
var i = this.t; var i = this.t;
r = i - a.t; r = i - a.t;
if (r != 0) return r; if (r != 0) return (this.s < 0) ? -r : r;
while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r; while (--i >= 0) if ((r = this[i] - a[i]) != 0) return r;
return 0; return 0;
} }

View File

@ -26,7 +26,8 @@
var BigInteger = require('./jsbn.js'), var BigInteger = require('./jsbn.js'),
util = require('../../util.js'), util = require('../../util.js'),
random = require('../random.js'); random = require('../random.js'),
config = require('../../config');
function SecureRandom() { function SecureRandom() {
function nextBytes(byteArray) { function nextBytes(byteArray) {
@ -37,11 +38,33 @@ function SecureRandom() {
this.nextBytes = nextBytes; this.nextBytes = nextBytes;
} }
var blinder = BigInteger.ZERO;
var unblinder = BigInteger.ZERO;
var TWO = BigInteger.ONE.add(BigInteger.ONE);
function blind(m, n, e) {
if (unblinder.bitLength() === n.bitLength()) {
unblinder = unblinder.square().mod(n);
} else {
unblinder = random.getRandomBigIntegerInRange(TWO, n);
}
blinder = unblinder.modInverse(n).modPow(e, n);
return m.multiply(blinder).mod(n);
}
function unblind(t, n) {
return t.multiply(unblinder).mod(n);
}
function RSA() { function RSA() {
/** /**
* This function uses jsbn Big Num library to decrypt RSA * This function uses jsbn Big Num library to decrypt RSA
* @param m * @param m
* message * message
* @param n
* RSA public modulus n as BigInteger
* @param e
* RSA public exponent as BigInteger
* @param d * @param d
* RSA d as BigInteger * RSA d as BigInteger
* @param p * @param p
@ -52,7 +75,10 @@ function RSA() {
* RSA u as BigInteger * RSA u as BigInteger
* @return {BigInteger} The decrypted value of the message * @return {BigInteger} The decrypted value of the message
*/ */
function decrypt(m, d, p, q, u) { function decrypt(m, n, e, d, p, q, u) {
if (config.rsa_blinding) {
m = blind(m, n, e);
}
var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p); var xp = m.mod(p).modPow(d.mod(p.subtract(BigInteger.ONE)), p);
var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q); var xq = m.mod(q).modPow(d.mod(q.subtract(BigInteger.ONE)), q);
util.print_debug("rsa.js decrypt\nxpn:" + util.hexstrdump(xp.toMPI()) + "\nxqn:" + util.hexstrdump(xq.toMPI())); util.print_debug("rsa.js decrypt\nxpn:" + util.hexstrdump(xp.toMPI()) + "\nxqn:" + util.hexstrdump(xq.toMPI()));
@ -65,7 +91,11 @@ function RSA() {
} else { } else {
t = t.multiply(u).mod(q); t = t.multiply(u).mod(q);
} }
return t.multiply(p).add(xp); t = t.multiply(p).add(xp);
if (config.rsa_blinding) {
t = unblind(t, n);
}
return t;
} }
/** /**

View File

@ -94,8 +94,8 @@ module.exports = {
* @return {BigInteger} Resulting big integer * @return {BigInteger} Resulting big integer
*/ */
getRandomBigInteger: function(bits) { getRandomBigInteger: function(bits) {
if (bits < 0) { if (bits < 1) {
return null; throw new Error('Illegal parameter value: bits < 1');
} }
var numBytes = Math.floor((bits + 7) / 8); var numBytes = Math.floor((bits + 7) / 8);
@ -114,7 +114,7 @@ module.exports = {
getRandomBigIntegerInRange: function(min, max) { getRandomBigIntegerInRange: function(min, max) {
if (max.compareTo(min) <= 0) { if (max.compareTo(min) <= 0) {
return; throw new Error('Illegal parameter value: max <= min');
} }
var range = max.subtract(min); var range = max.subtract(min);

View File

@ -107,7 +107,10 @@ Message.prototype.decrypt = function(privateKey) {
if (symEncryptedPacketlist.length !== 0) { if (symEncryptedPacketlist.length !== 0) {
var symEncryptedPacket = symEncryptedPacketlist[0]; var symEncryptedPacket = symEncryptedPacketlist[0];
symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey); symEncryptedPacket.decrypt(pkESKeyPacket.sessionKeyAlgorithm, pkESKeyPacket.sessionKey);
return new Message(symEncryptedPacket.packets); var resultMsg = new Message(symEncryptedPacket.packets);
// remove packets after decryption
symEncryptedPacket.packets = new packet.List();
return resultMsg;
} }
} }
}; };

View File

@ -257,6 +257,13 @@ describe('Basic', function() {
expect(decrypted).to.equal(plaintext); expect(decrypted).to.equal(plaintext);
done(); done();
}); });
it('Decrypt message 2x', function() {
decrypted = openpgp.decryptMessage(privKey, message);
var decrypted2 = openpgp.decryptMessage(privKey, message);
expect(decrypted).to.equal(decrypted2);
});
}); });
describe("Message 3DES decryption", function() { describe("Message 3DES decryption", function() {