0

I am trying to encrypt an object that is a JSON, in order to do so first i convert it to String, encrypt it and when is decrypted it cames back as random simbols because it is unable to convert it.

I try to encrypt:

 { a: 'A',
 L: 'GET ALL USERS',
   Po: 
     { ttp: 'localhost:3000/ttp/allusers',
     b: 'localhost:8000/server/allusers',
     Mhash: '6d2e5cc3a67ae82ae7edf6fb6054f977' } }


var mensajeToBbignum = bignum.fromBuffer(new Buffer(x));
    console.log('\n\n\nCleartext:',  
mensajeToBbignum.toBuffer().toString(),'\n');
   var mensajeToBcrip = keys2.publicKey.encrypt(mensajeToBbignum);
console.log('encryption with public:', '\n',      
mensajeToBcrip.toBuffer().toString('base64'), '\n');

From String to encryption i have the following:

{"a":"A","L":"GET ALL USERS","Po":{"ttp":"localhost:3000/ttp/allusers","b":"localhost:8000/server/allusers","Mhash":"6d2e5cc3a67ae82ae7edf6fb6054f977"}}

And finally encoded in base64:

 augf1Fuv2GwOYy0aipv1u6LZ3nWvGVz4M9JoA8uhlJgbuoGtYxe0GLSW+u6s1/kiOIqeF0s0cmCFgzpj/oKdF+0k9+OC/TVBgmk+1mO19pWnhcfS42j5OKPpy27mx0tRymQcS7TVDDsak2JptEv7O3POAvWVAKZRJ13zGMwP4qU=

I know it receives the same string in base64 with this code:

var recibidoBignum = bignum(req.body.mensaje);
console.log('recibidoBignum:', '\n',   
recibidoBignum.toBuffer().toString('base64'), '\n');
var reqdecrip = keys.privateKey.decrypt(recibidoBignum);
console.log('decryption with private:', '\n', reqdecrip.toBuffer().toString(), '\n\n\n\n\n\n');

And the following logs:

encryption with public: 

augf1Fuv2GwOYy0aipv1u6LZ3nWvGVz4M9JoA8uhlJgbuoGtYxe0GLSW+u6s1/kiOIqeF0s0cmCFgzpj/oKdF+0k9+OC/TVBgmk+1mO19pWnhcfS42j5OKPpy27mx0tRymQcS7TVDDsak2JptEv7O3POAvWVAKZRJ13zGMwP4qU= 

decryption with private: 
�8����P�`��t�>  �x)���m��S���n�l� �:�17^�����l�}%��綷K�N�Y�a-5��J���p���8�@�b�Vs� 

So it seems it can encrypt a JSON object but then is unable to decrypt it

The only external module used is bignum, the rsa implementation is the following

rsa = {
    publicKey: function(bits, n, e) {
        this.bits = bits;
        this.n = n;
        this.e = e;
    },
    privateKey: function(p, q, d, publicKey) {
        this.p = p;
        this.q = q;
        this.d = d;
        this.publicKey = publicKey;
    },
    generateKeys: function(bitlength) {
        var p, q, n, phi, e, d, keys = {};
        // if p and q are bitlength/2 long, n is then bitlength long
        this.bitlength = bitlength || 2048;
        console.log("Generating RSA keys of", this.bitlength, "bits");
        p = bignum.prime(this.bitlength / 2);
        do {
            q = bignum.prime(this.bitlength / 2);
        } while (q.cmp(p) === 0);
        n = p.mul(q);

        phi = p.sub(1).mul(q.sub(1));

        e = bignum(65537);
        d = e.invertm(phi);

        keys.publicKey = new rsa.publicKey(this.bitlength, n, e);
        keys.privateKey = new rsa.privateKey(p, q, d, keys.publicKey);
        return keys;
    }
    };


rsa.publicKey.prototype = {
    encrypt: function(m) {
        return m.powm(this.e, this.n);
    },
    decrypt: function(c) {
        return c.powm(this.e, this.n);
    }
};

rsa.privateKey.prototype = {
    encrypt: function(m) {
        return m.powm(this.d, this.publicKey.n);
    },
    decrypt: function(c) {
        return c.powm(this.d, this.publicKey.n);
    }
};

module.exports = rsa;
Lima9
  • 49
  • 2
  • 9
  • What's the key size? The string you're trying to encrypt is 152 characters long. If you're using a key that is smaller than 1216 bit, then it cannot work. It might even need to be as large as at least 1552 bit if OAEP (padding) is used. By the way, what's `bignum` and `keys`? Which module are you using? – Artjom B. Apr 15 '16 at 14:38
  • The module is bignum: https://www.npmjs.com/package/bignum keys is variable where I generated the keys with a longitude of 2048 like this: var keys = rsa.generateKeys(2048); where generatekeys is a function that uses the bignum module – Lima9 Apr 15 '16 at 14:53
  • Ok, what's `rsa` and which module does it come from. – Artjom B. Apr 15 '16 at 14:58
  • The only external module not coded by me is the bignum, `rsa` is an applicattion of the RSA encryption. I added it in the original post – Lima9 Apr 15 '16 at 15:03
  • Both of your ciphertexts that you show here are 172 Base64-encoded characters long. That's 128 bytes or 1024 bit. That's too short. Besides that, I see nothing wrong with your code. – Artjom B. Apr 15 '16 at 15:46
  • If I can encrypt the JSON into the 172 Base64-encoded character, then send it to the recipient and looking at my rsa implementation I should be able to decrypt it back to the original JSON but I can't. The thing is if instead of the JSON I write a simple string like `"message"` the encryption works flawlessly – Lima9 Apr 15 '16 at 18:24

1 Answers1

1

It's an encoding issue. bignum(s) assumes that s is an integer in Base 10, but according to your description req.body.mensaje is a Base 64 encoded string in var recibidoBignum = bignum(req.body.mensaje);.

Here is the complete code:

var bignum = require("bignum");

var rsa = {
    publicKey: function(bits, n, e) {
        this.bits = bits;
        this.n = n;
        this.e = e;
    },
    privateKey: function(p, q, d, publicKey) {
        this.p = p;
        this.q = q;
        this.d = d;
        this.publicKey = publicKey;
    },
    generateKeys: function(bitlength) {
        var p, q, n, phi, e, d, keys = {};
        // if p and q are bitlength/2 long, n is then bitlength long
        this.bitlength = bitlength || 2048;
        console.log("Generating RSA keys of " + this.bitlength + " bits");
        p = bignum.prime(this.bitlength / 2);
        do {
            q = bignum.prime(this.bitlength / 2);
        } while (q.cmp(p) === 0);
        n = p.mul(q);

        phi = p.sub(1).mul(q.sub(1));

        e = bignum(65537);
        d = e.invertm(phi);

        keys.publicKey = new rsa.publicKey(this.bitlength, n, e);
        keys.privateKey = new rsa.privateKey(p, q, d, keys.publicKey);
        return keys;
    }
};


rsa.publicKey.prototype = {
    encrypt: function(m) {
        return m.powm(this.e, this.n);
    },
    decrypt: function(c) {
        return c.powm(this.e, this.n);
    }
};

rsa.privateKey.prototype = {
    encrypt: function(m) {
        return m.powm(this.d, this.publicKey.n);
    },
    decrypt: function(c) {
        return c.powm(this.d, this.publicKey.n);
    }
};

var keys = rsa.generateKeys(2048);

var pt = '{"a":"A","L":"GET ALL USERS","Po":{"ttp":"localhost:3000/ttp/allusers","b":"localhost:8000/server/allusers","Mhash":"6d2e5cc3a67ae82ae7edf6fb6054f977"}}';

console.log("Plaintext: " + pt);

var mensajeToBbignum = bignum.fromBuffer(new Buffer(pt));
var mensajeToBcrip = keys.publicKey.encrypt(mensajeToBbignum);
var ct = mensajeToBcrip.toBuffer().toString('base64');

console.log("Ciphertext: " + ct);

var recibidoBignum = bignum.fromBuffer(new Buffer(ct, "base64"));
var reqdecrip = keys.privateKey.decrypt(recibidoBignum);
console.log('Recovered plaintext: ' + reqdecrip.toBuffer().toString());

Runnable Demo

Artjom B.
  • 61,146
  • 24
  • 125
  • 222
  • Remember that RSA without padding is really insecure. PKCS#1 v2.2 defines some padding schemes for encryption and signing. Please use OAEP and PSS, respectively. Don't use textbook RSA in production! – Artjom B. Apr 15 '16 at 19:12