Skip to content

Instantly share code, notes, and snippets.

@therightstuff
Last active December 19, 2023 02:17
Show Gist options
  • Save therightstuff/84ae710c3c301fe7979d7f0aa9c7c147 to your computer and use it in GitHub Desktop.
Save therightstuff/84ae710c3c301fe7979d7f0aa9c7c147 to your computer and use it in GitHub Desktop.
Javascript / Node.js end-to-end encryption
<html>
<head>
<!-- The following package is required https://www.npmjs.com/package/simple-free-encryption-tool -->
<script src="js/windowSfet.js"></script>
<script language="javascript">
// SECURITY_LEVEL is the encryption key size in bits
let SECURITY_LEVEL = 2048;
// internet explorer can't handle 2048 bit key generation in a reasonable amount of time, so we use 1024 bit.
// this will have minimal impact as the credentials are secured using an externally transmitted verification
// code and cracking the client->server comms won't (usually) compromise server->client comms
// if client->server comms being compromised is a serious problem, then simply force the user to wait
if ((window.navigator.userAgent.indexOf('MSIE') > 0) ||
(window.navigator.userAgent.indexOf('Trident/7') > 0) ||
(window.navigator.userAgent.indexOf('Edge/') > 0)) {
SECURITY_LEVEL = 1024;
}
// RSA keys used to secure the session
let keys = {
client: {},
server: {}
};
// generate the client's keys for the session
function generateSessionKeys {
console.log('generating ' + SECURITY_LEVEL + '-bit key pair...');
keys.client = sfet.rsa.generateKeysSync(SECURITY_LEVEL);
console.log('Keys Generated in ' + keys.client.time);
}
// load existing session keys from storage or generate new keys
function loadSessionKeys() {
// ensure html5 storage available
if (typeof (Storage) !== "undefined") {
if (sessionStorage.RSAKeys) {
keys = JSON.parse(sessionStorage.RSAKeys);
console.log('client keys loaded from session storage');
} else {
generateSessionKeys();
sessionStorage.RSAKeys = JSON.stringify(keys);
console.log('session keys saved to storage');
}
} else {
console.log('Sorry! No Web Storage support..');
// it's possible to continue with new keys generated per page,
// but then you'll have to repeat the key exchange with a new code
}
}
function packMessageData(data) {
data = JSON.stringify(data);
let packedData = {};
// generate aes secret
let aesSecret = sfet.utils.randomstring.generate();
try {
// add RSA-encrypted aes secret to output
packedData.key = sfet.rsa.encrypt(keys.server.public, aesSecret);
// add encrypted data to output
packedData.encrypted = sfet.aes.encrypt(aesSecret, data);
return packedData;
} catch (dataEncryptionException) {
console.log('failed to pack message: ' + dataEncryptionException.message);
return {};
}
}
function unpackMessageData(data) {
var secret = sfet.rsa.decrypt(keys.client.private, data.key);
var message = JSON.parse(sfet.aes.decrypt(secret, data.encrypted));
}
</script>
</head>
<body>
</body>
</html>
var sfet = require('simple-free-encryption-tool');
var SECURITY_LEVEL = 2048;
// generate shared secret for session authentication
var generateSessionSecret = function () {
// number between 4 and 8
var secretLength = Math.floor((Math.random() * 5) + 4);
// session secret must not include ambiguous characters like O/0, 1/l
var secret = sfet.utils.randomstring.generate({
length: secretLength,
readable: true
});
return secret;
};
function pack(data) {
data = JSON.stringify(data);
var packedData = {};
// generate aes key
let aesSecret = sfet.utils.randomstring.generate();
// add encrypted aes key to output
packedData.key = sfet.rsa.encrypt(clientPublicKey, aesSecret);
// add encrypted data to output
packedData.encrypted = sfet.aes.encrypt(aesSecret, data);
return packedData;
}
function unpack(data) {
var aesSecret = sfet.rsa.decrypt(serverPrivateKey, data.key);
return sfet.aes.decrypt(aesSecret, data.encrypted);
}
@rasheshved
Copy link

Can you please explain y does it require to both encrypt,decrypt data on both server,client side?
Also Where this pem files for client is being stored(location)

@therightstuff
Copy link
Author

This is required to create an encrypted bi-directional channel between client and server. For initialization, the client sends it's RSA key AES-encrypted to the server using a secret delivered by a second-factor authentication device (email, sms), and the server responds in the regular format with a randomly generated message key encrypted with the RSA key and the payload encrypted with the message key.

The keys are generated when initializing the session and are stored in memory - in the browser I use HTML5's local storage, on the server I store it in a database or cached.

@TheLox95
Copy link

This code still works with the new versions of the libraries used? You should specify the version used. It would be nice to have an example on how to use it. Currently I'm trying to encrypt/decrypt a json only on fron-end using the packMessageData/unpackMessageData to test this example and it only gives me non-redable string like this 熡yB6 A文+ķǓ1z-؂t-\m_ѰO@3}y(ꂛ/*堺i鷍%婅b꺦㷬뮡D䥭趣k 㱸Ń͞A6_s녻囀

@therightstuff
Copy link
Author

This code still works with the new versions of the libraries used? You should specify the version used. It would be nice to have an example on how to use it. Currently I'm trying to encrypt/decrypt a json only on fron-end using the packMessageData/unpackMessageData to test this example and it only gives me non-redable string like this 熡yB6 A文+ķǓ1z-؂t-\m_ѰO@3}y(ꂛ/*堺i鷍%婅b꺦㷬뮡D䥭趣k 㱸Ń͞A6_s녻囀

I haven't looked at this in years, but I have built the simple-free-encryption-tool that can be used to replace a lot of this functionality.

@therightstuff
Copy link
Author

therightstuff commented May 30, 2020

This code still works with the new versions of the libraries used? You should specify the version used. It would be nice to have an example on how to use it. Currently I'm trying to encrypt/decrypt a json only on fron-end using the packMessageData/unpackMessageData to test this example and it only gives me non-redable string like this 熡yB6 A文+ķǓ1z-؂t-\m_ѰO@3}y(ꂛ/*堺i鷍%婅b꺦㷬뮡D䥭趣k 㱸Ń͞A6_s녻囀

Hey @TheLox95, I've just updated this gist to use the tool that those original functions were turned into, the code will work and it will run client-side, in node.js, and it's also compatible with C# (the gists for those are in the sfet README and source)

@amitojsingh366
Copy link

What are clientPublicKey and serverPrivateKey in server.js. And how do i obtain them... Sorry if its a dumb question, I'm very new to encryption

@therightstuff
Copy link
Author

What are clientPublicKey and serverPrivateKey in server.js. And how do i obtain them... Sorry if its a dumb question, I'm very new to encryption

You can review the documentation at https://github.com/therightstuff/simple-free-encryption-tool#readme for details on how to generate keys using the simple-free-encryption-tool, but if you're not familiar with the fundamentals of public / private key encryption you should probably look that up first

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment