简体   繁体   中英

Getting the same result from two packages (jsencrypt and node-rsa)

We were using jsencrypt on the client-side of an application to encrypt a string (a password) and pass it over to the backend that handles 3rd party API authorisation.

Like so:

 const n = "_key" export const encrypt2 = async(message: string): Promise < string > => { const JSEncrypt = (await import ('jsencrypt')).default; const jsencrypt = new JSEncrypt({ default_key_size: '1024', default_public_exponent: "010001", log: false, }); jsencrypt.setPublicKey(n); return jsencrypt.encrypt(message) || message; };

Due to product changes, we now want the encryption on the backend (nodejs). After research we found node-rsa that can have the same result. Used the code below:

 export const encrypt = async(message: string): Promise < string > => { return new NodeRSA().generateKeyPair(1024, '010001').importKey(n, 'public').encrypt(message).toString('base64') };

given that n is still the same, our 3rd party auth service rejects this implementation.

Question & Goal:

How can I get a valid encrypted password from both of these implementations?

PS, I was unable to use jsencrypt on the server side due to window usage

JSEncrypt only supports PKCS#1 v1.5 padding (see here ), while Node-RSA supports PKCS#1 v1.5 padding and OAEP, where OAEP is the default (see here ). The different paddings are the reason why both codes are not compatible.

In order for PKCS#1 v1.5 padding to be used in the Node-RSA code, this must be explicitly specified, eg in the 3rd parameter when importing the key:

const NodeRSA = require('node-rsa');

var x509 = `-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT
5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E
bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw
KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x
H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4
OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i
GwIDAQAB
-----END PUBLIC KEY-----`;

var message = "The quick brown fox jumps over the lazy dog";
var privateKey = new NodeRSA(x509, 'public', { encryptionScheme: 'pkcs1' }); // specify PKCS#1 v1.5 padding

var ciphertext = privateKey.encrypt(message).toString('base64');
console.log("Ciphertext (Node-RSA): ", ciphertext);

A possible output is:

Ciphertext (Node-RSA):  Lcfy7G0RYhDRCeWAvUXji4b4uFzrhpSsS9G158QcBiRy+Uae5UctQoA6MMgzZsjVWmf4Jlj50eZYTwxP94mGrTY0gMy9+FvFlMXDu0cMJ04qArOU4B+ZHnt3FElDjYvW0fnvbstYJFWd9OQjlLJc2mxSGPKEj0IQi3p8GQXK9qYfJx7MeONA+nfHdWYQgplicnz1crk+aiGf0zlJMAKdOoTodAtQuqVh9bNYyJcpPnzIt4eqUVW+wLEoXNqu14ibz1u5yMpCNX/+jBKug2fYaXv4ImsUnhqFEAok9sHDGVzZkihnYdDxnWaSocpG3db6UNhpGBoJSvwxdEuI86YgSQ==

Test:

Since both OAEP and PKCS#1v1.5 padding are not deterministic, testing by comparing the generated ciphertexts is not possible. Instead, it can be checked whether the Node-RSA ciphertext can be decrypted with that JSEncrypt code which can also decrypt the JSEncrypt ciphertext. If this is the case, the encryption codes are functionally identical:

 var x509 = `-----BEGIN PUBLIC KEY----- MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAunF5aDa6HCfLMMI/MZLT 5hDk304CU+ypFMFiBjowQdUMQKYHZ+fklB7GpLxCatxYJ/hZ7rjfHH3Klq20/Y1E bYDRopyTSfkrTzPzwsX4Ur/l25CtdQldhHCTMgwf/Ev/buBNobfzdZE+Dhdv5lQw KtjI43lDKvAi5kEet2TFwfJcJrBiRJeEcLfVgWTXGRQn7gngWKykUu5rS83eAU1x H9FLojQfyia89/EykiOO7/3UWwd+MATZ9HLjSx2/Lf3g2jr81eifEmYDlri/OZp4 OhZu+0Bo1LXloCTe+vmIQ2YCX7EatUOuyQMt2Vwx4uV+d/A3DP6PtMGBKpF8St4i GwIDAQAB -----END PUBLIC KEY-----`; var pkcs8 = `-----BEGIN PRIVATE KEY----- MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC6cXloNrocJ8sw wj8xktPmEOTfTgJT7KkUwWIGOjBB1QxApgdn5+SUHsakvEJq3Fgn+FnuuN8cfcqW rbT9jURtgNGinJNJ+StPM/PCxfhSv+XbkK11CV2EcJMyDB/8S/9u4E2ht/N1kT4O F2/mVDAq2MjjeUMq8CLmQR63ZMXB8lwmsGJEl4Rwt9WBZNcZFCfuCeBYrKRS7mtL zd4BTXEf0UuiNB/KJrz38TKSI47v/dRbB34wBNn0cuNLHb8t/eDaOvzV6J8SZgOW uL85mng6Fm77QGjUteWgJN76+YhDZgJfsRq1Q67JAy3ZXDHi5X538DcM/o+0wYEq kXxK3iIbAgMBAAECggEASlJj0ExIomKmmBhG8q8SM1s2sWG6gdQMjs6MEeluRT/1 c2v79cq2Dum5y/+UBl8x8TUKPKSLpCLs+GXkiVKgHXrFlqoN+OYQArG2EUWzuODw czdYPhhupBXwR3oX4g41k/BsYfQfZBVzBFEJdWrIDLyAUFWNlfdGIj2BTiAoySfy qmamvmW8bsvc8coiGlZ28UC85/Xqx9wOzjeGoRkCH7PcTMlc9F7SxSthwX/k1VBX mNOHa+HzGOgO/W3k1LDqJbq2wKjZTW3iVEg2VodjxgBLMm0MueSGoI6IuaZSPMyF EM3gGvC2+cDBI2SL/amhiTUa/VDlTVw/IKbSuar9uQKBgQDd76M0Po5Lqh8ZhQ3o bhFqkfO5EBXy7HUL15cw51kVtwF6Gf/J2HNHjwsg9Nb0eJETTS6bbuVd9bn884Jo RS986nVTFNZ4dnjEgKjjQ8GjfzdkpbUxsRLWiIxuOQSpIUZGdMi2ctTTtspvMsDs jRRYdYIQCe/SDsdHGT3vcUCybwKBgQDXDz6iVnY84Fh5iDDVrQOR4lYoxCL/ikCD JjC6y1mjR0eVFdBPQ4j1dDSPU9lahBLby0VyagQCDp/kxQOl0z2zBLRI4I8jUtz9 /9KW6ze7U7dQJ7OTfumd5I97OyQOG9XZwKUkRgfyb/PAMBSUSLgosi38f+OC3IN3 qlvHFzvxFQKBgQCITpUDEmSczih5qQGIvolN1cRF5j5Ey7t7gXbnXz+Umah7kJpM IvdyfMVOAXJABgi8PQwiBLM0ySXo2LpARjXLV8ilNUggBktYDNktc8DrJMgltaya j3HNd2IglD5rjfc2cKWRgOd7/GlKcHaTEnbreYhfR2sWrWLxJOyoMfuVWwKBgFal CbMV6qU0LfEo8aPlBN8ttVDPVNpntP4h0NgxPXgPK8Pg+gA1UWSy4MouGg/hzkdH aj9ifyLlCX598a5JoT4S0x/ZeVHd/LNI8mtjcRzD6cMde7gdFbpLb5NSjIAyrsIA X4hxvpnqiOYRePkVIz0iLGziiaMbfMwlkrxvm/LRAoGBALPRbtSbE2pPgvOHKHTG Pr7gKbmsWVbOcQA8rG801T38W/UPe1XtynMEjzzQ29OaVeQwvUN9+DxFXJ6Yvwj6 ih4Wdq109i7Oo1fDnMczOQN9DKch2eNAHrNSOMyLDCBm++wbyHAsS2T0VO8+gzLA BviZm5AFCQWfke4LZo5mOS10 -----END PRIVATE KEY-----`; var message = "The quick brown fox jumps over the lazy dog"; var publicKey = new JSEncrypt(); publicKey.setPublicKey(x509); var ciphertext = publicKey.encrypt(message); console.log("Ciphertext (JSEncrypt): ", ciphertext); var privateKey = new JSEncrypt(); privateKey.setPrivateKey(pkcs8); var decrypted = privateKey.decrypt(ciphertext); console.log("Decrypted (JSEncrypt): ", decrypted); var ciphertextFromNodeRSA = `Lcfy7G0RYhDRCeWAvUXji4b4uFzrhpSsS9G158QcBiRy+Uae5UctQoA6MMgzZsjVWmf4Jlj50eZYTwxP94mGrTY0gMy9+FvFlMXDu0cMJ04qArOU4B+ZHnt3FElDjYvW0fnvbstYJFWd9OQjlLJc2mxSGPKEj0IQi3p8GQXK9qYfJx7MeONA+nfHdWYQgplicnz1crk+aiGf0zlJMAKdOoTodAtQuqVh9bNYyJcpPnzIt4eqUVW+wLEoXNqu14ibz1u5yMpCNX/+jBKug2fYaXv4ImsUnhqFEAok9sHDGVzZkihnYdDxnWaSocpG3db6UNhpGBoJSvwxdEuI86YgSQ==`; decrypted = privateKey.decrypt(ciphertextFromNodeRSA); console.log("Decrypted (Node-RSA): ", decrypted);
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jsencrypt/3.2.1/jsencrypt.min.js"></script>

A possible output:

Ciphertext (JSEncrypt):  WWcnfnlAB7Quf/jMQIyD9AgOpewJQdPgA/UQFqIu9PvoMhMUgjo+4LnxeKjnFGqhG9mgctqmVKW1EGjEsnJiThbgiC6VNIwufYloXgJcqTrT78p7UiTO9+k7z1H8iCy4HkgXtiOkoBpGI094zr/iMnTyiTMfMKjopygM969pgDPsaXqWeiE2MX4ZjxFcNP9QpYoZpdS7PGxDBj31kbXvttOB/1Oc57IqOepF2N8n0jp9KzIBnAf+CDjzUFbUh8t23feuktoL/o/MYqqySmY/hkvkkmtNd4LDLtTA0NjcU7Es99ue90xNcuYKCEybzaZ20pp769PQjZHu/lU+T7zlrg== 
Decrypted (JSEncrypt):  The quick brown fox jumps over the lazy dog 
Decrypted (Node-RSA):  The quick brown fox jumps over the lazy dog

proving that both encryption codes are functionally equivalent.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM