Using asymmetric algorithm in angular - node.js

I need to apply asymmetric encryption for large JSON files on client-side to transfer them to the cloud. These files can include images in the base64 format. I'm working with Angular-cli and tried to use the library crypto-browserify but can't encrypt large files. Then I tried the node-rsa library and my program works in the console, but does not work in Angular.
const NodeRSA = require('node-rsa');
let key = new NodeRSA('-----BEGIN PUBLIC KEY-----\n'+
'-----END PUBLIC KEY-----');
let f = '{"data":"data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAA ..."}';
let encrypt_data = key.encrypt(f, 'base64');
console.log(encrypt_data);

A solution is found in using node-rsa through browserify:
browserify -r node-rsa --standalone CryptRSA > rsa-brow.js
Then added to index.html
<script src="assets/js/rsa-brow.js"></script>
Then using in Angular
declare var CryptRSA: any;
#Injectable()
export class MyService {
encrypt(file_content: string){
let key = new CryptRSA(publicKey);
let buffer = Buffer.from(file_content, 'utf-8');
return key.encrypt(buffer, 'base64');
}
}

Related

How to rewrite NodeJS CryptoJS functions so they work in ReactJS web?

I have some code that was created for me by a past contractor that provided a working implementation of CryptoJS between a Unity3D client and NodeJS server app (as in encryption of client-server messages).
I am working on an implementation that needs to call the same server endpoints from a React web app. Basically, I need to be able to ensure that the React app provides the same results when encrypting and decrypting messages as the server (and hence the Unity3D implementation) does.
The existing encrypt/decrypt functions in the NodeJS app are shown below. They are somewhat more advanced than the standard CryptoJS examples and when I attempt to use them as-is in React, I get this error:
TypeError: cryptoJS.createHash is not a function. (In 'cryptoJS.createHash('md5')', 'cryptoJS.createHash' is undefined)
After some researching, I understand that potentially the 'use as-is' approach will fail because it's using a server side library on the client side, but I have been able to find anything that would explain how I would recreate the same code to work client-side.
encrypt(text, key, iv) {
const keyBuffer = Buffer.from(cryptoJS.createHash('md5').update(key).digest('hex'), "hex")
const ivBuffer = Buffer.from(cryptoJS.createHash('md5').update(iv).digest('hex'), "hex")
const textBuffer = Buffer.from(text, 'utf8')
let cipher = cryptoJS.createCipheriv(algorithm, keyBuffer, ivBuffer)
let encryptedText = Buffer.concat([cipher.update(textBuffer), cipher.final()])
return encryptedText.toString("base64")
}
decrypt(text, key, iv) {
const keyBuffer = Buffer.from(cryptoJS.createHash('md5').update(key).digest('hex'), "hex")
const ivBuffer = Buffer.from(cryptoJS.createHash('md5').update(iv).digest('hex'), "hex")
let decipher = cryptoJS.createDecipheriv(algorithm, keyBuffer, ivBuffer)
const textBuffer = Buffer.from(text, 'base64')
var decipheredContent = Buffer.concat([decipher.update(textBuffer), decipher.final()])
return decipheredContent.toString("utf8")
}
So, I need to figure out how to replace these encrypt/decrypt functions with ones that compile and function in client side in React web. Any help in steering me in the right direction or assisting with the code would be greatly appreciated. Thanks for taking the time to read my question.

NodeJS crypto RSA, not compatible with Elixir/Erlang PublicKey?

I’m having trouble trying to decrypt in Elixir (using ExCrypto - which is a only a wrapper around crypto and public_key) encrypted by NodeJS Crypto.
Here’s what works :
encrypt_public in NodeJS -> decrypt_private NodeJS (Works)
encrypt_public in Elixir -> decrypt_pricate in Elixir (Works)
But :
encrypt_public in NodeJS -> decrypt_private in Elixir (Does Not Work)
It seems that an encrypt_public from Node, can’t be decrypted by a decrypt_private in Elixir.
I even tried the hard way directly with the Erlang module public_key, it gives me the same result.
Here’s what I tried :
var fs = require("fs")
var crypto = require("crypto")
var rsa_key = fs.readFileSync('./priv/public.key').toString()
var rsa_priv = fs.readFileSync('./priv/private.key').toString()
var buffer = Buffer.from("Hello world")
var encrypted_auth = crypto.publicEncrypt({key: rsa_key}, buffer)
console.log("copy/paste this in iex: ", encrypted_auth.toString("Base64"))
var crypted_buffer = Buffer.from(encrypted_auth)
var decrypted_auth = crypto.privateDecrypt({key: rsa_priv, passphrase: "my_pass_phrase"}, crypted_buffer)
console.log("--- Res: ", decrypted_auth.toString())
But as soon as you copy/paste the Base64 generated in Node Here’s what I get :
key = ExPublicKey.load!("./priv/private.key", "my_pass_phrase")
cipher = "PASTED BASE64 FROM NODE"
ExPublicKey.decrypt_private(cipher, key)
returns :error
I have suspected the rsa padding to be different, but it doesn’t seems to be that… Does anyone have a clue ?
There were 2 issues
The padding by default in Node is : RSA_PKCS1_OAEP_PADDING
while the default one is erlang is : rsa_pkcs1_padding
the solution is to modify the padding in Node :
var encrypted_auth = crypto.publicEncrypt({key: rsa_key, padding: crypto.constants.RSA_PKCS1_PADDING}, buffer)
The second issue, was that EXPublicKey was trying to Base.url_decode64 while the Base64 generated by Node is not url safe
To fix that :
ExPublicKey.decrypt_private(cipher, key, url_safe: false)

Encrypt data on angular decrypt on Nodejs

What's the way of doing this? I tried using CryptoJS on angular and Crypto Module on node, without success I keep getting description error
Angular encrypt method :
_rsaEnc(p) {
var e = new JSEncrypt();
const key = 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDlOJu6TyygqxfWT7eLtGDwajtNFOb9I5XRb6khyfD1Yt3YiCgQWMNW649887VGJiGr/L5i2osbl8C9+WJTeucF+S76xFxdU6jE0NQ+Z+zEdhUTooNRaY5nZiu5PgDB0ED/kaskaskKAS';
e.setPublicKey(key);
return e.encrypt(p);
}
Node decrypt method
privK = {
key: fs.readFileSync('./app/services/private.pem').toString(),
passphrase: 'xxxxxx'
};
var buf = Buffer.from(base64Data, 'base64');
origData = crypto.privateDecrypt(privK, buf);
return origData.toString('utf-8');
error:
Error: error:040A1079:rsa
routines:RSA_padding_check_PKCS1_OAEP_mgf1:oaep decoding error
Ended up changing the angular lib to jsencrypt, CryptoJS doesnt support RSA, and changed node lib to node-rsa to set the encryption scheme to pkcs1 with
myDecrypter.setOptions({encryptionScheme: 'pkcs1'});

encrypt the audio file by android and decrypt it by backend sails js

I want to encrypt the audio file by android and decrypt it by backend sails js. I developed the program for that but I got error in sails js like
error:06065064:digital envelope routines:EVP_DecryptFinal_ex:bad decrypt
This is my source code for encrypt the audio file in android
final String ALGORITHM = "blowfish";
String keyString = "DesireSecretKey";
private void encrypt(String file) throws Exception {
File extStore = Environment.getExternalStorageDirectory();
File inputFile = new File(file);
File encryptedFile = new
File(extStore+"/Movies/encryptAudio.amr");
doCrypto(Cipher.ENCRYPT_MODE, inputFile, encryptedFile);
}
private void doCrypto(int cipherMode, File inputFile,
File outputFile) throws Exception {
Key secretKey = new
SecretKeySpec(keyString.getBytes(),ALGORITHM);
Cipher cipher = Cipher.getInstance(ALGORITHM);
cipher.init(cipherMode, secretKey);
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int) inputFile.length()];
inputStream.read(inputBytes);
byte[] outputBytes = cipher.doFinal(inputBytes);
FileOutputStream outputStream = new
FileOutputStream(outputFile);
outputStream.write(outputBytes);
inputStream.close();
outputStream.close();
}
I installed the crypto , fs libraries in sails js backend by following command
npm install crypto
npm install fs
This is my source code for decrypt the audio file in sails js
function decrypt() {
var crypto = require('crypto'),
algorithm = 'blowfish',
password = 'DesireSecretKey';
var fs = require('fs');
// input file
var r = fs.createReadStream(config.UPLOAD_FILES_PATH
+'/encryptAudio.amr');
var decrypt = crypto.createDecipher(algorithm, password,"");
// write file
var w = fs.createWriteStream(config.AUDIO_PATH+'decryptAudio.amr');
// start pipe
r.pipe(decrypt).pipe(w);
}
Encryption is working properly & i can get the encrypted audio file.But the issue is i couldn't get the decrypted audio file by sails js. Can you identify the issue?
maybe the answer to this question might help as you are using Java's library for cryptography this should pretty much guide you in right direction.
Encrypt with Node.js Crypto module and decrypt with Java (in Android app)
I would have mentioned this in comments section but I do not have enough reputation points to comment.
This is opposite of what you are trying to achieve but still it could help you to analyze your issue.

Encrypting data with a public key in Node.js

I need to encrypt a string using a public key (.pem file), and then sign it using a private key (also a .pem).
I am loading the .pem files fine:
publicCert = fs.readFileSync(publicCertFile).toString();
But after hours of scouring Google, I can't seem to find a way to encrypt data using the public key. In PHP I simply call openssl_public_encrypt(), but I don't see any corresponding function in Node.js or in any modules.
A library is not necessary. Enter crypto.
Here's a janky little module you could use to encrypt/decrypt strings with RSA keys:
var crypto = require("crypto");
var path = require("path");
var fs = require("fs");
var encryptStringWithRsaPublicKey = function(toEncrypt, relativeOrAbsolutePathToPublicKey) {
var absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey);
var publicKey = fs.readFileSync(absolutePath, "utf8");
var buffer = Buffer.from(toEncrypt);
var encrypted = crypto.publicEncrypt(publicKey, buffer);
return encrypted.toString("base64");
};
var decryptStringWithRsaPrivateKey = function(toDecrypt, relativeOrAbsolutePathtoPrivateKey) {
var absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey);
var privateKey = fs.readFileSync(absolutePath, "utf8");
var buffer = Buffer.from(toDecrypt, "base64");
var decrypted = crypto.privateDecrypt(privateKey, buffer);
return decrypted.toString("utf8");
};
module.exports = {
encryptStringWithRsaPublicKey: encryptStringWithRsaPublicKey,
decryptStringWithRsaPrivateKey: decryptStringWithRsaPrivateKey
}
I would recommend not using synchronous fs methods where possible, and you could use promises to make this better, but for simple use cases this is the approach that I have seen work and would take.
I tested this in Node.js 10, you can use encrypt/decrypt functions (small changes on Jacob's answer):
const crypto = require('crypto')
const path = require('path')
const fs = require('fs')
function encrypt(toEncrypt, relativeOrAbsolutePathToPublicKey) {
const absolutePath = path.resolve(relativeOrAbsolutePathToPublicKey)
const publicKey = fs.readFileSync(absolutePath, 'utf8')
const buffer = Buffer.from(toEncrypt, 'utf8')
const encrypted = crypto.publicEncrypt(publicKey, buffer)
return encrypted.toString('base64')
}
function decrypt(toDecrypt, relativeOrAbsolutePathtoPrivateKey) {
const absolutePath = path.resolve(relativeOrAbsolutePathtoPrivateKey)
const privateKey = fs.readFileSync(absolutePath, 'utf8')
const buffer = Buffer.from(toDecrypt, 'base64')
const decrypted = crypto.privateDecrypt(
{
key: privateKey.toString(),
passphrase: '',
},
buffer,
)
return decrypted.toString('utf8')
}
const enc = encrypt('hello', `public.pem`)
console.log('enc', enc)
const dec = decrypt(enc, `private.pem`)
console.log('dec', dec)
For the keys you can generate them with
const { writeFileSync } = require('fs')
const { generateKeyPairSync } = require('crypto')
function generateKeys() {
const { privateKey, publicKey } = generateKeyPairSync('rsa', {
modulusLength: 4096,
publicKeyEncoding: {
type: 'pkcs1',
format: 'pem',
},
privateKeyEncoding: {
type: 'pkcs1',
format: 'pem',
cipher: 'aes-256-cbc',
passphrase: '',
},
})
writeFileSync('private.pem', privateKey)
writeFileSync('public.pem', publicKey)
}
The updated public/private decrypt and encryption module is URSA. The node-rsa module is outdated.
This Node module provides a fairly complete set of wrappers for the
RSA public/private key crypto functionality of OpenSSL.
npm install ursa
Use the node-rsa module. Here's a link to the test.js file that demonstrates usage.
TL;DR: URSA is your best bet. It's really funky that this doesn't come standard with Node.js' crypto.
Every other solutions I found either doesn't work in Windows or aren't actually encryption libraries. URSA, recommended by Louie, looks like the best bet. If you don't care about Windows, you're even more golden.
Note on Ursa: I had to install OpenSSL along with something called "Visual C++ 2008 Redistributables" in order to get the npm install to work. Get that junk here: http://slproweb.com/products/Win32OpenSSL.html
The breakdown:
Annoying additional manual installation steps for Windows
https://github.com/Obvious/ursa - probably the best of the lot
Not compatible with Windows
https://npmjs.org/package/rsautl - says BADPLATFORM
https://github.com/katyo/node-rsa - node-waf isn't available on Windows
https://github.com/paspao/simple_rsa_encrypt - unistd.h isn't on windows
https://npmjs.org/package/pripub - large amounts of linker errors, also not on GitHub
Not encryption libraries
https://github.com/substack/secure-peer
https://github.com/substack/rsa-json - just generates keys, but doesn't use them
https://github.com/substack/rsa-unpack - just unpacks PEM strings
This is literally all I could find.
This is not supported natively by Node.js version v0.11.13 or below, but it seems that next version of Node.js (a.k.a v0.12) will support this.
Here is the clue: https://github.com/joyent/node/blob/v0.12/lib/crypto.js#L358
See crypto.publicEncrypt and crypto.privateDecrypt
Here is the future documentation for this
https://github.com/joyent/node/blob/7c0419730b237dbfa0ec4e6fb33a99ff01825a8f/doc/api/crypto.markdown#cryptopublicencryptpublic_key-buffer

Resources