3

I wanted to encrypt and decrypt a message in node using public and private keys stored in my system. I was using the following java code to read the file and use the keys.

Java Code:

byte[]  keyBytes = Files.readAllBytes(new File(publicKeyFileName).toPath());
X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
KeyFactory kf = KeyFactory.getInstance("RSA");
publicKey=kf.generatePublic(spec);

I am able to use the above java method without any issues to read the public key from file. However, I want to achieve similar functionality in node. I have tried using crypto for achieving the same but it gives me error while passing the key to publicEncrypt method.

Node:

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    var publicKey = fs.read(absolutepath, "utf-8");
    console.log(publicKey);
    var buffer = Buffer.from(toEncrypt);
    var encrypted = crypto.publicEncrypt(publicKey, buffer);
    return encrypted.toString("base64");
};

Error

internal/crypto/cipher.js:43
    return method(toBuf(key), buffer, padding, passphrase);
           ^

Error: error:0906D06C:PEM routines:PEM_read_bio:no start line

Please help. Thanks

Ritvik Joshi
  • 85
  • 1
  • 1
  • 6

2 Answers2

2

Your problem is located in the file format you are actually using with Java. You probably save the private and the public in encoded ("byte array") to a file and rebuild the keys e.g. with X509EncodedKeySpec.

This format is not compatible to Node.JS and you have 3 ways to solve it:

a) you write the keys in Java with re neccessary format for usage in Node.JS

b) you write a converter in Node.JS to get the correct format

c) you convert the files with a tool like OPENSSL.

Here I show you the "c-way" as you are handling just one keypair and probably don't need a programatically solution.

Let's say you have two files with the private key ("rsa_privatekey_2048.der") and the public key ("rsa_publickey_2048.der").

In OPENSSL you are using the command line with

openssl rsa -inform der -in rsa_privatekey_2048.der -outform pem -out rsa_privatekey_2048.pem
openssl rsa -inform der -pubin -in rsa_publickey_2048.der -outform pem -RSAPublicKey_out -out rsa_publickey_2048.pem

to convert the files to their PEM-encoded formats.

Below you can find the two sample files I created.

rsa_privatekey_2048.pem:

-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEAmbeKgSAwVe0nZ84XlbDhMkUDjx1C0duA16MkzHTg1uh9SouO
KK0e3gPtTJ9LssaHlXSYhjpMDMWGO6ujd85XRosI2u9eSMNRYY25AQuBriSTVdi9
BHqWAuWuo6VuvTrkgWTL69vNWvLXTOkTiIyrgnhiavjNvm4UVy2AcO2Y3ER+dKgJ
pQAYlEP1jvuQuf6dfNdSBoN0DZbxZXYbQqoA9R/u0GZHCXY+r8A54RejG34pnnuH
koyROZz5H9LbKGOiaETryornQ1TRvB/p9tgIoCJFI71WsKsqeWQPG3Ymg/FoEWXN
Y0yopZEjpkZa3tU+hrOmAFIRg+/bedKfjYFi/QIDAQABAoIBAD3XZ3N3fbq0BExw
z3A7jv3oYfwrq3w+MOGQEvfmdaZANlfNOU4ICAkNz2QqGgw8bsOj+tDVl070EILl
FIjYjKgmu1NJRcdEPPNgTvOqq2th75xz6+dnYf6cZNwVbC3ZCaE86gVjkoRqek/I
3UDsRvvgbsfWfP+Fzc0c0zWbgQnsK6qivU1uzJX+5xsvgQlZboeZOO2lsdQMgfnu
iGlW1bVVM4Sy7AngqfiKMzihUnYEBIi0Y+mfxAPcBLUW8mrOvIOPPuNNUPxUtkBF
bDEzZ6loXCLLD8UBqXeDbCUPPFdTGcc7INhVgFdl2FL6rHB0+p6eUt8MI/XkZI2d
2AnkBUkCgYEA34cKLs2l5bPjyKybbj6ZG7RhDRsnPypEGU63DMV21twISqt7ZQNv
i3iTP+FYHM3ImECbNRIOZpyLuWLPmh5+5egQH13jRDempoxVSVcghbIserlCz2EU
nD2V6ZKuaDbn395O6Qe/PE/yKHLWbXwJrBBm+o7GGNm/Jd3KJib23PcCgYEAsAxB
esEsxxL8hqg/qf+ij7JJt492svpK/6QXhqeeP/FVOtYSgoNtSrXh9qahGpzMSF0m
FqwIgrOX0RkK3v6ofGVfIKObxOVyhwddS1Ru+SnjBFnTMKS57q0WNrIrBNM6Q0xE
Wd3tiljwmg8xF90U/BXu+m0v5XWKxSn7VLiCBqsCgYEAgl0xtSY/EP6fZJQ2ek+L
4DqNN6WUeCRgXxonbA1mR91AALyOVNVyIreJuYHlb7ccvJ9BZexH9dRrMQ3N4ibS
/6cecAzD1S9XxF6oBwQHdbH6ewC9VFFcQdsxKW5gxWrwRQJUp1fbUoOVyb1gDa5/
vZg7VvoZ0rh74Mu/cAzdgPUCgYEAiNANdwt29AKyUyefykpLGCczGL8aPP88l6z7
R38uAX1Ygg/pdJoUrnHo+FkIbHkcXMRfHFF3j7NoMWynwSLg50OUiPX80SiLN5qm
iytDzskZjsEL2gq6IF1NHRabTfWlmrVDjR9mQhTabq+NtIDwlPOqs9100nrlbFIy
6uU0z18CgYEAkDxQg5UjOzbYIighp/e0LkfKlwUE/cMtISUq1A6Yio9AKZYdBV8p
dd4osUW0gZvDflXlQaBIaNlOwl035lyEZtyuKmFh1oSmoir/TTMbIk0avSgKCLGg
fnhabaQRHl4RdXWcEsioRv3aZUsGkb46Y8xODyAUPRHBPhBsd71gnZ8=
-----END RSA PRIVATE KEY-----

rsa_publickey_2048.pem:

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEAmbeKgSAwVe0nZ84XlbDhMkUDjx1C0duA16MkzHTg1uh9SouOKK0e
3gPtTJ9LssaHlXSYhjpMDMWGO6ujd85XRosI2u9eSMNRYY25AQuBriSTVdi9BHqW
AuWuo6VuvTrkgWTL69vNWvLXTOkTiIyrgnhiavjNvm4UVy2AcO2Y3ER+dKgJpQAY
lEP1jvuQuf6dfNdSBoN0DZbxZXYbQqoA9R/u0GZHCXY+r8A54RejG34pnnuHkoyR
OZz5H9LbKGOiaETryornQ1TRvB/p9tgIoCJFI71WsKsqeWQPG3Ymg/FoEWXNY0yo
pZEjpkZa3tU+hrOmAFIRg+/bedKfjYFi/QIDAQAB
-----END RSA PUBLIC KEY-----
Michael Fehr
  • 5,827
  • 2
  • 19
  • 40
  • Yes, I am pretty sure this is what the issue is however the key file is not stored in any specific format. It does not have any extension to it. So what modification should i do in the command you mentioned – Ritvik Joshi Sep 22 '20 at 08:59
  • 1
    As you are using "X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);" the two files are already stored in DER-format, so just leave out the ".DER" in the input file names for OPENSSL. – Michael Fehr Sep 22 '20 at 09:01
  • Thanks for your answer. Now i have got into another issue :( where i am able to encrypt as well as decrypt the message with the PEM-encoded keys but the service written in java is not able to decrypt the encoded message which i have sent. It says`BadPaddingException: Decryption Error` in the log of java program. For your info, the original keys are 1024 bit long and they are using **rsa/ecb/pkcs1padding** padding – Ritvik Joshi Sep 22 '20 at 11:59
  • @Ritvik Joshi: this is a total different question - here it is to "read public and private key from". Please ask another question regarding your new question. Please add to your new question some **sample** RSA-keypair AND both codes your are actually using (node.js for encryption and Java for decryption, otherwise it will not be possible your new question. Kindly mark one the two answers to this question as accepted answer, thanks. – Michael Fehr Sep 22 '20 at 12:58
1

There's potentially a few issues with your code or the encryption key you're using:

  1. You're using fs.read incorrectly as Node is asynchronous and it needs a callback function to properly read the file.
  2. The encryption key you're using is formatted incorrectly for crypto.publicEncrypt. You must have the proper RSA headers.

I modified your code to use fs.readFile properly instead in the standard Node callback form, and here's an example encryption key in the correct RSA format to use:

var path = require('path');
var crypto = require('crypto');
var fs = require('fs');

var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey, callback) {
    var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
    fs.readFile(absolutePath, 'utf-8', (err, publicKey) => {
        // The value of `publicKey` is in the callback, not the return value
        console.log(publicKey);
        var buffer = Buffer.from(toEncrypt);
        var encrypted = crypto.publicEncrypt(publicKey, buffer);
        if (err) {
            callback(err);
        } else {
            callback(null, encrypted.toString("base64"));
        }
    });
};

encryptStringWithRsaPublicKey('hello world', 'test.pub', (err, encrypted) => {
    // If you're using a callback in a function,
    // the original function must have a callback as well
    console.log(encrypted);
}); 

Example encryption key at test.pub (must have the RSA headers as shown below):

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA+xGZ/wcz9ugFpP07Nspo6U17l0YhFiFpxxU4pTk3Lifz9R3zsIsu
ERwta7+fWIfxOo208ett/jhskiVodSEt3QBGh4XBipyWopKwZ93HHaDVZAALi/2A
+xTBtWdEo7XGUujKDvC2/aZKukfjpOiUI8AhLAfjmlcD/UZ1QPh0mHsglRNCmpCw
mwSXA9VNmhz+PiB+Dml4WWnKW/VHo2ujTXxq7+efMU4H2fny3Se3KYOsFPFGZ1TN
QSYlFuShWrHPtiLmUdPoP6CV2mML1tk+l7DIIqXrQhLUKDACeM5roMx0kLhUWB8P
+0uj1CNlNN4JRZlC7xFfqiMbFRU9Z4N6YwIDAQAB
-----END RSA PUBLIC KEY-----

As of 2020, there are also other ways of making the code cleaner, such as with using the Promises version of the fs module and async / await, though I wanted to keep this answer as simple as possible for now.

Clarence Leung
  • 2,446
  • 21
  • 24
  • Yes i tried the synchronous read methods as well and there is no luck. I assume the problem is with the file from which i am reading. The key doesn't have any extension to it whereas node assumes 'pem' or 'der' keys. To bring you on the same lines, these keys were previously used in java program as mentioned in the question. Any idea to achieve same functionality? – Ritvik Joshi Sep 22 '20 at 06:46
  • @RitvikJoshi The filename doesn't matter, but you need the RSA headers (`-----BEGIN RSA PUBLIC KEY----`) and the like. – Clarence Leung Sep 22 '20 at 06:47
  • I am not even able to read the contents of the file using any editor. So I don't know whether the headers are present or not. Any help on that as i am new to the cryptography stuff. – Ritvik Joshi Sep 22 '20 at 07:02
  • You should be able to see the contents of a file with `cat [filename]` on the command line. – Clarence Leung Sep 22 '20 at 07:19
  • Yes, i was able to see some weird looking characters when i tried cat [filename]. However, i decoded using base64 and got the string. I appended the headers. Now when i run, it gives me another error `Error: error:0D0680A8:asn1 encoding routines:asn1_check_tlen:wrong tag` I removed the leading and trailing whitespaces as well – Ritvik Joshi Sep 22 '20 at 07:37